diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-06 12:48:11 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-13 09:33:43 +0000 |
commit | 7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (patch) | |
tree | fa14ba0ca8d2683ba2efdabd246dc9b18a1229c6 /chromium/net/third_party | |
parent | 79b4f909db1049fca459c07cca55af56a9b54fe3 (diff) | |
download | qtwebengine-chromium-7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3.tar.gz |
BASELINE: Update Chromium to 84.0.4147.141
Change-Id: Ib85eb4cfa1cbe2b2b81e5022c8cad5c493969535
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/net/third_party')
345 files changed, 14018 insertions, 5978 deletions
diff --git a/chromium/net/third_party/quiche/BUILD.gn b/chromium/net/third_party/quiche/BUILD.gn index 55850473980..59a75e2132a 100644 --- a/chromium/net/third_party/quiche/BUILD.gn +++ b/chromium/net/third_party/quiche/BUILD.gn @@ -387,8 +387,6 @@ source_set("quiche") { "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_buffered_packet_store.cc", - "src/quic/core/quic_buffered_packet_store.h", "src/quic/core/quic_circular_deque.h", "src/quic/core/quic_clock.cc", "src/quic/core/quic_clock.h", @@ -852,6 +850,8 @@ source_set("quic_test_tools_core") { "src/quic/test_tools/failing_proof_source.h", "src/quic/test_tools/fake_proof_source.cc", "src/quic/test_tools/fake_proof_source.h", + "src/quic/test_tools/first_flight.cc", + "src/quic/test_tools/first_flight.h", "src/quic/test_tools/mock_clock.cc", "src/quic/test_tools/mock_clock.h", "src/quic/test_tools/mock_quic_client_promised_info.cc", @@ -957,6 +957,8 @@ source_set("quic_test_tools_core") { "src/quic/test_tools/simulator/switch.h", "src/quic/test_tools/simulator/traffic_policer.cc", "src/quic/test_tools/simulator/traffic_policer.h", + "src/quic/test_tools/test_certificates.cc", + "src/quic/test_tools/test_certificates.h", "src/quic/tools/quic_tcp_like_trace_converter.cc", "src/quic/tools/quic_tcp_like_trace_converter.h", ] @@ -1015,6 +1017,8 @@ source_set("simple_quic_tools_core") { "src/quic/core/http/quic_spdy_client_stream.h", "src/quic/core/http/quic_spdy_server_stream_base.cc", "src/quic/core/http/quic_spdy_server_stream_base.h", + "src/quic/core/quic_buffered_packet_store.cc", + "src/quic/core/quic_buffered_packet_store.h", "src/quic/core/quic_dispatcher.cc", "src/quic/core/quic_dispatcher.h", "src/quic/core/quic_packet_writer_wrapper.cc", @@ -1022,6 +1026,8 @@ source_set("simple_quic_tools_core") { "src/quic/core/quic_process_packet_interface.h", "src/quic/core/quic_time_wait_list_manager.cc", "src/quic/core/quic_time_wait_list_manager.h", + "src/quic/core/tls_chlo_extractor.cc", + "src/quic/core/tls_chlo_extractor.h", "src/quic/platform/api/quic_default_proof_providers.h", "src/quic/platform/api/quic_system_event_loop.h", "src/quic/tools/fake_proof_verifier.h", @@ -1053,6 +1059,8 @@ source_set("simple_quic_tools_core") { "src/quic/tools/quic_transport_simple_server_session.h", "src/quic/tools/quic_url.cc", "src/quic/tools/quic_url.h", + "src/quic/tools/simple_ticket_crypter.cc", + "src/quic/tools/simple_ticket_crypter.h", ] deps = [ "//base", @@ -1344,12 +1352,12 @@ source_set("quiche_tests") { "src/quic/core/quic_time_test.cc", "src/quic/core/quic_time_wait_list_manager_test.cc", "src/quic/core/quic_trace_visitor_test.cc", - "src/quic/core/quic_types_test.cc", "src/quic/core/quic_unacked_packet_map_test.cc", "src/quic/core/quic_utils_test.cc", "src/quic/core/quic_version_manager_test.cc", "src/quic/core/quic_versions_test.cc", "src/quic/core/quic_write_blocked_list_test.cc", + "src/quic/core/tls_chlo_extractor_test.cc", "src/quic/core/tls_handshaker_test.cc", "src/quic/core/uber_quic_stream_id_manager_test.cc", "src/quic/core/uber_received_packet_manager_test.cc", @@ -1375,6 +1383,7 @@ source_set("quiche_tests") { "src/quic/test_tools/simulator/simulator_test.cc", "src/quic/tools/quic_memory_cache_backend_test.cc", "src/quic/tools/quic_tcp_like_trace_converter_test.cc", + "src/quic/tools/simple_ticket_crypter_test.cc", "src/spdy/core/array_output_buffer.cc", "src/spdy/core/array_output_buffer.h", "src/spdy/core/array_output_buffer_test.cc", diff --git a/chromium/net/third_party/quiche/src/common/platform/api/quiche_text_utils.h b/chromium/net/third_party/quiche/src/common/platform/api/quiche_text_utils.h index c58c6767d76..2cf920f2c2a 100644 --- a/chromium/net/third_party/quiche/src/common/platform/api/quiche_text_utils.h +++ b/chromium/net/third_party/quiche/src/common/platform/api/quiche_text_utils.h @@ -8,6 +8,7 @@ #include <string> #include "net/third_party/quiche/src/common/platform/api/quiche_export.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_optional.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" #include "net/quiche/common/platform/impl/quiche_text_utils_impl.h" @@ -22,6 +23,12 @@ class QUICHE_EXPORT QuicheTextUtils { return quiche::QuicheTextUtilsImpl::StartsWith(data, prefix); } + // Returns true if |data| ends with |suffix|, case sensitively. + static bool EndsWith(quiche::QuicheStringPiece data, + quiche::QuicheStringPiece suffix) { + return quiche::QuicheTextUtilsImpl::EndsWith(data, suffix); + } + // Returns true if |data| ends with |suffix|, case insensitively. static bool EndsWithIgnoreCase(quiche::QuicheStringPiece data, quiche::QuicheStringPiece suffix) { @@ -101,6 +108,12 @@ class QUICHE_EXPORT QuicheTextUtils { return quiche::QuicheTextUtilsImpl::Base64Encode(data, data_len, output); } + // Decodes a base64-encoded |input|. Returns nullopt when the input is + // invalid. + static QuicheOptional<std::string> Base64Decode(QuicheStringPiece input) { + return quiche::QuicheTextUtilsImpl::Base64Decode(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. 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 38546516137..344501378b5 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 @@ -4,6 +4,8 @@ #include "net/third_party/quiche/src/common/quiche_data_reader.h" +#include <cstring> + #include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" #include "net/third_party/quiche/src/common/platform/api/quiche_logging.h" #include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h" @@ -85,6 +87,17 @@ bool QuicheDataReader::ReadStringPiece16(quiche::QuicheStringPiece* result) { return ReadStringPiece(result, result_len); } +bool QuicheDataReader::ReadStringPiece8(quiche::QuicheStringPiece* result) { + // Read resultant length. + uint8_t result_len; + if (!ReadUInt8(&result_len)) { + // OnFailure() already called. + return false; + } + + return ReadStringPiece(result, result_len); +} + bool QuicheDataReader::ReadStringPiece(quiche::QuicheStringPiece* result, size_t size) { // Make sure that we have enough data to read. diff --git a/chromium/net/third_party/quiche/src/common/quiche_data_reader.h b/chromium/net/third_party/quiche/src/common/quiche_data_reader.h index c837172731c..cf62a164708 100644 --- a/chromium/net/third_party/quiche/src/common/quiche_data_reader.h +++ b/chromium/net/third_party/quiche/src/common/quiche_data_reader.h @@ -11,6 +11,7 @@ #include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" #include "net/third_party/quiche/src/common/platform/api/quiche_export.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_logging.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" namespace quiche { @@ -65,6 +66,15 @@ class QUICHE_EXPORT_PRIVATE QuicheDataReader { // Returns true on success, false otherwise. bool ReadStringPiece16(quiche::QuicheStringPiece* result); + // Reads a string prefixed with 8-bit length into the given output parameter. + // + // NOTE: Does not copy but rather references strings in the underlying buffer. + // This should be kept in mind when handling memory management! + // + // Forwards the internal iterator on success. + // Returns true on success, false otherwise. + bool ReadStringPiece8(quiche::QuicheStringPiece* result); + // Reads a given number of bytes into the given buffer. The buffer // must be of adequate size. // Forwards the internal iterator on success. diff --git a/chromium/net/third_party/quiche/src/common/quiche_data_writer.h b/chromium/net/third_party/quiche/src/common/quiche_data_writer.h index 8df1f908451..cded0fa16c8 100644 --- a/chromium/net/third_party/quiche/src/common/quiche_data_writer.h +++ b/chromium/net/third_party/quiche/src/common/quiche_data_writer.h @@ -7,10 +7,12 @@ #include <cstddef> #include <cstdint> +#include <cstring> #include <limits> #include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" #include "net/third_party/quiche/src/common/platform/api/quiche_export.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_logging.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" namespace quiche { diff --git a/chromium/net/third_party/quiche/src/http2/decoder/decode_http2_structures.cc b/chromium/net/third_party/quiche/src/http2/decoder/decode_http2_structures.cc index f106ab0a91e..8eccaf808df 100644 --- a/chromium/net/third_party/quiche/src/http2/decoder/decode_http2_structures.cc +++ b/chromium/net/third_party/quiche/src/http2/decoder/decode_http2_structures.cc @@ -5,6 +5,7 @@ #include "net/third_party/quiche/src/http2/decoder/decode_http2_structures.h" #include <cstdint> +#include <cstring> #include "net/third_party/quiche/src/http2/decoder/decode_buffer.h" #include "net/third_party/quiche/src/http2/http2_constants.h" diff --git a/chromium/net/third_party/quiche/src/http2/decoder/http2_structure_decoder.cc b/chromium/net/third_party/quiche/src/http2/decoder/http2_structure_decoder.cc index f30a91be163..3a5b1eb6ece 100644 --- a/chromium/net/third_party/quiche/src/http2/decoder/http2_structure_decoder.cc +++ b/chromium/net/third_party/quiche/src/http2/decoder/http2_structure_decoder.cc @@ -5,6 +5,7 @@ #include "net/third_party/quiche/src/http2/decoder/http2_structure_decoder.h" #include <algorithm> +#include <cstring> #include "net/third_party/quiche/src/http2/platform/api/http2_bug_tracker.h" diff --git a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder.cc b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder.cc index 1013292dda4..b879511a7dc 100644 --- a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder.cc +++ b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder.cc @@ -16,9 +16,7 @@ HpackDecoder::HpackDecoder(HpackDecoderListener* listener, : decoder_state_(listener), entry_buffer_(&decoder_state_, max_string_size), block_decoder_(&entry_buffer_), - error_(HpackDecodingError::kOk), - http2_skip_querying_entry_buffer_error_( - GetHttp2ReloadableFlag(http2_skip_querying_entry_buffer_error)) {} + error_(HpackDecodingError::kOk) {} HpackDecoder::~HpackDecoder() = default; @@ -108,21 +106,7 @@ bool HpackDecoder::DetectError() { if (decoder_state_.error() != HpackDecodingError::kOk) { HTTP2_DVLOG(2) << "Error detected in decoder_state_"; HTTP2_CODE_COUNT_N(decompress_failure_3, 10, 23); - HTTP2_CODE_COUNT_N(http2_skip_querying_entry_buffer_error, 1, 3); error_ = decoder_state_.error(); - } else if (entry_buffer_.error_detected()) { - // This should never happen, because if an error had occured in - // |entry_buffer_|, it would have notified its listener, |decoder_state_|. - if (http2_skip_querying_entry_buffer_error_) { - HTTP2_CODE_COUNT_N(http2_skip_querying_entry_buffer_error, 2, 3); - } else { - HTTP2_DVLOG(2) << "Error detected in entry_buffer_"; - HTTP2_CODE_COUNT_N(decompress_failure_3, 9, 23); - HTTP2_CODE_COUNT_N(http2_skip_querying_entry_buffer_error, 3, 3); - // Since this code path should never be executed, error code does not - // matter as long as it is not HpackDecodingError::kOk. - error_ = HpackDecodingError::kIndexVarintError; - } } return error_ != HpackDecodingError::kOk; diff --git a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder.h b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder.h index 6e6360432c5..efe334d13b4 100644 --- a/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder.h +++ b/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder.h @@ -121,9 +121,6 @@ class QUICHE_EXPORT_PRIVATE HpackDecoder { // Error code if an error has occurred, HpackDecodingError::kOk otherwise. HpackDecodingError error_; - - // Latched value of reloadable_flag_http2_skip_querying_entry_buffer_error. - const bool http2_skip_querying_entry_buffer_error_; }; } // namespace http2 diff --git a/chromium/net/third_party/quiche/src/quic/core/chlo_extractor_test.cc b/chromium/net/third_party/quiche/src/quic/core/chlo_extractor_test.cc index e293902faad..1b6a6164234 100644 --- a/chromium/net/third_party/quiche/src/quic/core/chlo_extractor_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/chlo_extractor_test.cc @@ -12,6 +12,7 @@ #include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/first_flight.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" #include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" @@ -32,50 +33,54 @@ class TestDelegate : public ChloExtractor::Delegate { version_ = version; connection_id_ = connection_id; chlo_ = chlo.DebugString(); + quiche::QuicheStringPiece alpn_value; + if (chlo.GetStringPiece(kALPN, &alpn_value)) { + alpn_ = std::string(alpn_value); + } } QuicConnectionId connection_id() const { return connection_id_; } QuicTransportVersion transport_version() const { return version_; } const std::string& chlo() const { return chlo_; } + const std::string& alpn() const { return alpn_; } private: QuicConnectionId connection_id_; QuicTransportVersion version_; std::string chlo_; + std::string alpn_; }; -class ChloExtractorTest : public QuicTest { +class ChloExtractorTest : public QuicTestWithParam<ParsedQuicVersion> { public: - ChloExtractorTest() { - header_.destination_connection_id = TestConnectionId(); - header_.destination_connection_id_included = CONNECTION_ID_PRESENT; - header_.version_flag = true; - header_.version = AllSupportedVersions().front(); - header_.reset_flag = false; - header_.packet_number_length = PACKET_4BYTE_PACKET_NUMBER; - header_.packet_number = QuicPacketNumber(1); - if (QuicVersionHasLongHeaderLengths(header_.version.transport_version)) { - header_.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1; - header_.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; - } - } + ChloExtractorTest() : version_(GetParam()) {} - void MakePacket(ParsedQuicVersion version, - quiche::QuicheStringPiece data, + void MakePacket(quiche::QuicheStringPiece data, bool munge_offset, bool munge_stream_id) { + QuicPacketHeader header; + header.destination_connection_id = TestConnectionId(); + header.destination_connection_id_included = CONNECTION_ID_PRESENT; + header.version_flag = true; + header.version = version_; + header.reset_flag = false; + header.packet_number_length = PACKET_4BYTE_PACKET_NUMBER; + header.packet_number = QuicPacketNumber(1); + if (version_.HasLongHeaderLengths()) { + header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1; + header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; + } QuicFrames frames; size_t offset = 0; if (munge_offset) { offset++; } - QuicFramer framer(SupportedVersions(header_.version), QuicTime::Zero(), + QuicFramer framer(SupportedVersions(version_), QuicTime::Zero(), Perspective::IS_CLIENT, kQuicDefaultConnectionIdLength); framer.SetInitialObfuscators(TestConnectionId()); - if (!QuicVersionUsesCryptoFrames(version.transport_version) || - munge_stream_id) { + if (!version_.UsesCryptoFrames() || munge_stream_id) { QuicStreamId stream_id = - QuicUtils::GetCryptoStreamId(version.transport_version); + QuicUtils::GetCryptoStreamId(version_.transport_version); if (munge_stream_id) { stream_id++; } @@ -86,11 +91,11 @@ class ChloExtractorTest : public QuicTest { QuicFrame(new QuicCryptoFrame(ENCRYPTION_INITIAL, offset, data))); } std::unique_ptr<QuicPacket> packet( - BuildUnsizedDataPacket(&framer, header_, frames)); + BuildUnsizedDataPacket(&framer, header, frames)); EXPECT_TRUE(packet != nullptr); size_t encrypted_length = - framer.EncryptPayload(ENCRYPTION_INITIAL, header_.packet_number, - *packet, buffer_, QUICHE_ARRAYSIZE(buffer_)); + framer.EncryptPayload(ENCRYPTION_INITIAL, header.packet_number, *packet, + buffer_, QUICHE_ARRAYSIZE(buffer_)); ASSERT_NE(0u, encrypted_length); packet_ = std::make_unique<QuicEncryptedPacket>(buffer_, encrypted_length); EXPECT_TRUE(packet_ != nullptr); @@ -98,79 +103,77 @@ class ChloExtractorTest : public QuicTest { } protected: + ParsedQuicVersion version_; TestDelegate delegate_; - QuicPacketHeader header_; std::unique_ptr<QuicEncryptedPacket> packet_; char buffer_[kMaxOutgoingPacketSize]; }; -TEST_F(ChloExtractorTest, FindsValidChlo) { +INSTANTIATE_TEST_SUITE_P( + ChloExtractorTests, + ChloExtractorTest, + ::testing::ValuesIn(AllSupportedVersionsWithQuicCrypto()), + ::testing::PrintToStringParamName()); + +TEST_P(ChloExtractorTest, FindsValidChlo) { CryptoHandshakeMessage client_hello; client_hello.set_tag(kCHLO); std::string client_hello_str(client_hello.GetSerialized().AsStringPiece()); - // Construct a CHLO with each supported version - for (ParsedQuicVersion version : AllSupportedVersions()) { - SCOPED_TRACE(version); - header_.version = version; - if (QuicVersionHasLongHeaderLengths(version.transport_version) && - header_.version_flag) { - header_.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1; - header_.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; - } else { - header_.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_0; - header_.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_0; - } - MakePacket(version, client_hello_str, /*munge_offset*/ false, - /*munge_stream_id*/ false); - EXPECT_TRUE(ChloExtractor::Extract(*packet_, version, {}, &delegate_, - kQuicDefaultConnectionIdLength)) - << ParsedQuicVersionToString(version); - EXPECT_EQ(version.transport_version, delegate_.transport_version()); - EXPECT_EQ(header_.destination_connection_id, delegate_.connection_id()); - EXPECT_EQ(client_hello.DebugString(), delegate_.chlo()) - << ParsedQuicVersionToString(version); - } + + MakePacket(client_hello_str, /*munge_offset=*/false, + /*munge_stream_id=*/false); + EXPECT_TRUE(ChloExtractor::Extract(*packet_, version_, {}, &delegate_, + kQuicDefaultConnectionIdLength)); + EXPECT_EQ(version_.transport_version, delegate_.transport_version()); + EXPECT_EQ(TestConnectionId(), delegate_.connection_id()); + EXPECT_EQ(client_hello.DebugString(), delegate_.chlo()); } -TEST_F(ChloExtractorTest, DoesNotFindValidChloOnWrongStream) { - ParsedQuicVersion version = AllSupportedVersions()[0]; - if (QuicVersionUsesCryptoFrames(version.transport_version)) { +TEST_P(ChloExtractorTest, DoesNotFindValidChloOnWrongStream) { + if (version_.UsesCryptoFrames()) { + // When crypto frames are in use we do not use stream frames. return; } CryptoHandshakeMessage client_hello; client_hello.set_tag(kCHLO); std::string client_hello_str(client_hello.GetSerialized().AsStringPiece()); - MakePacket(version, client_hello_str, - /*munge_offset*/ false, /*munge_stream_id*/ true); - EXPECT_FALSE(ChloExtractor::Extract(*packet_, version, {}, &delegate_, + MakePacket(client_hello_str, + /*munge_offset=*/false, /*munge_stream_id=*/true); + EXPECT_FALSE(ChloExtractor::Extract(*packet_, version_, {}, &delegate_, kQuicDefaultConnectionIdLength)); } -TEST_F(ChloExtractorTest, DoesNotFindValidChloOnWrongOffset) { - ParsedQuicVersion version = AllSupportedVersions()[0]; +TEST_P(ChloExtractorTest, DoesNotFindValidChloOnWrongOffset) { CryptoHandshakeMessage client_hello; client_hello.set_tag(kCHLO); std::string client_hello_str(client_hello.GetSerialized().AsStringPiece()); - MakePacket(version, client_hello_str, /*munge_offset*/ true, - /*munge_stream_id*/ false); - EXPECT_FALSE(ChloExtractor::Extract(*packet_, version, {}, &delegate_, + MakePacket(client_hello_str, /*munge_offset=*/true, + /*munge_stream_id=*/false); + EXPECT_FALSE(ChloExtractor::Extract(*packet_, version_, {}, &delegate_, kQuicDefaultConnectionIdLength)); } -TEST_F(ChloExtractorTest, DoesNotFindInvalidChlo) { - ParsedQuicVersion version = AllSupportedVersions()[0]; - if (QuicVersionUsesCryptoFrames(version.transport_version)) { - return; - } - MakePacket(version, "foo", /*munge_offset*/ false, - /*munge_stream_id*/ true); - EXPECT_FALSE(ChloExtractor::Extract(*packet_, version, {}, &delegate_, +TEST_P(ChloExtractorTest, DoesNotFindInvalidChlo) { + MakePacket("foo", /*munge_offset=*/false, + /*munge_stream_id=*/false); + EXPECT_FALSE(ChloExtractor::Extract(*packet_, version_, {}, &delegate_, kQuicDefaultConnectionIdLength)); } +TEST_P(ChloExtractorTest, FirstFlight) { + std::vector<std::unique_ptr<QuicReceivedPacket>> packets = + GetFirstFlightOfPackets(version_); + ASSERT_EQ(packets.size(), 1u); + EXPECT_TRUE(ChloExtractor::Extract(*packets[0], version_, {}, &delegate_, + kQuicDefaultConnectionIdLength)); + EXPECT_EQ(version_.transport_version, delegate_.transport_version()); + EXPECT_EQ(TestConnectionId(), delegate_.connection_id()); + EXPECT_EQ(AlpnForVersion(version_), delegate_.alpn()); +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.cc index c929e8b55cc..f885c94794c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.cc @@ -382,14 +382,15 @@ BandwidthSample BandwidthSampler::OnPacketAcknowledgedInner( } else { QUIC_CODE_COUNT_N(quic_prev_ack_time_larger_than_current_ack_time, 2, 2); } - QUIC_BUG << "Time of the previously acked packet:" - << a0.ack_time.ToDebuggingValue() - << " is larger than the ack time of the current packet:" - << ack_time.ToDebuggingValue() - << ". acked packet number:" << packet_number - << ", total_bytes_acked_:" << total_bytes_acked_ - << ", overestimate_avoidance_:" << overestimate_avoidance_ - << ", sent_packet:" << sent_packet; + QUIC_LOG_EVERY_N_SEC(ERROR, 60) + << "Time of the previously acked packet:" + << a0.ack_time.ToDebuggingValue() + << " is larger than the ack time of the current packet:" + << ack_time.ToDebuggingValue() + << ". acked packet number:" << packet_number + << ", total_bytes_acked_:" << total_bytes_acked_ + << ", overestimate_avoidance_:" << overestimate_avoidance_ + << ", sent_packet:" << sent_packet; return BandwidthSample(); } QuicBandwidth ack_rate = QuicBandwidth::FromBytesAndTimeDelta( @@ -403,13 +404,15 @@ BandwidthSample BandwidthSampler::OnPacketAcknowledgedInner( sample.rtt = ack_time - sent_packet.sent_time; SentPacketToSendTimeState(sent_packet, &sample.state_at_send); - QUIC_BUG_IF(sample.bandwidth.IsZero()) - << "ack_rate: " << ack_rate << ", send_rate: " << send_rate - << ". acked packet number:" << packet_number - << ", overestimate_avoidance_:" << overestimate_avoidance_ << "a1:{" - << total_bytes_acked_ << "@" << ack_time << "}, a0:{" - << a0.total_bytes_acked << "@" << a0.ack_time - << "}, sent_packet:" << sent_packet; + if (sample.bandwidth.IsZero()) { + QUIC_LOG_EVERY_N_SEC(ERROR, 60) + << "ack_rate: " << ack_rate << ", send_rate: " << send_rate + << ". acked packet number:" << packet_number + << ", overestimate_avoidance_:" << overestimate_avoidance_ << "a1:{" + << total_bytes_acked_ << "@" << ack_time << "}, a0:{" + << a0.total_bytes_acked << "@" << a0.ack_time + << "}, sent_packet:" << sent_packet; + } return sample; } diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.cc index 5a3046794be..90df9a0c0da 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.cc @@ -60,9 +60,7 @@ Bbr2NetworkModel::Bbr2NetworkModel(const Bbr2Params* params, : params_(params), bandwidth_sampler_([](QuicRoundTripCount max_height_tracker_window_length, const BandwidthSampler* old_sampler) { - if (GetQuicReloadableFlag(quic_bbr_copy_sampler_state_from_v1_to_v2) && - old_sampler != nullptr) { - QUIC_RELOADABLE_FLAG_COUNT(quic_bbr_copy_sampler_state_from_v1_to_v2); + if (old_sampler != nullptr) { return BandwidthSampler(*old_sampler); } return BandwidthSampler(/*unacked_packet_map=*/nullptr, @@ -111,10 +109,8 @@ void Bbr2NetworkModel::OnCongestionEventStart( // Avoid updating |max_bandwidth_filter_| if a) this is a loss-only event, or // b) all packets in |acked_packets| did not generate valid samples. (e.g. ack // of ack-only packets). In both cases, total_bytes_acked() will not change. - if (!fix_zero_bw_on_loss_only_event_ || - (prior_bytes_acked != total_bytes_acked())) { - QUIC_BUG_IF((prior_bytes_acked != total_bytes_acked()) && - sample.sample_max_bandwidth.IsZero()) + if (prior_bytes_acked != total_bytes_acked()) { + QUIC_BUG_IF(sample.sample_max_bandwidth.IsZero()) << total_bytes_acked() - prior_bytes_acked << " bytes from " << acked_packets.size() << " packets have been acked, but sample_max_bandwidth is zero."; @@ -123,14 +119,6 @@ void Bbr2NetworkModel::OnCongestionEventStart( congestion_event->sample_max_bandwidth = sample.sample_max_bandwidth; max_bandwidth_filter_.Update(congestion_event->sample_max_bandwidth); } - } else { - if (acked_packets.empty()) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr_fix_zero_bw_on_loss_only_event, 3, - 4); - } else { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr_fix_zero_bw_on_loss_only_event, 4, - 4); - } } if (!sample.sample_rtt.IsInfinite()) { @@ -196,15 +184,17 @@ void Bbr2NetworkModel::AdaptLowerBounds( if (bandwidth_lo_.IsInfinite()) { bandwidth_lo_ = MaxBandwidth(); } - if (inflight_lo_ == inflight_lo_default()) { - inflight_lo_ = congestion_event.prior_cwnd; - } - bandwidth_lo_ = std::max(bandwidth_latest_, bandwidth_lo_ * (1.0 - Params().beta)); QUIC_DVLOG(3) << "bandwidth_lo_ updated to " << bandwidth_lo_ << ", bandwidth_latest_ is " << bandwidth_latest_; + if (Params().ignore_inflight_lo) { + return; + } + if (inflight_lo_ == inflight_lo_default()) { + inflight_lo_ = congestion_event.prior_cwnd; + } inflight_lo_ = std::max<QuicByteCount>( inflight_latest_, inflight_lo_ * (1.0 - Params().beta)); } @@ -292,6 +282,15 @@ void Bbr2NetworkModel::RestartRound() { round_trip_counter_.RestartRound(); } +void Bbr2NetworkModel::cap_inflight_lo(QuicByteCount cap) { + if (Params().ignore_inflight_lo) { + return; + } + if (inflight_lo_ != inflight_lo_default() && inflight_lo_ > cap) { + inflight_lo_ = cap; + } +} + QuicByteCount Bbr2NetworkModel::inflight_hi_with_headroom() const { QuicByteCount headroom = inflight_hi_ * Params().inflight_hi_headroom; diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.h index 63a11e14681..e110a4c3297 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.h @@ -77,7 +77,8 @@ struct QUIC_EXPORT_PRIVATE Bbr2Params { // The gain for both CWND and PacingRate at startup. // TODO(wub): Maybe change to the newly derived value of 2.773 (4 * ln(2)). - float startup_gain = 2.885; + float startup_cwnd_gain = 2.885; + float startup_pacing_gain = 2.885; // Full bandwidth is declared if the total bandwidth growth is less than // |startup_full_bw_threshold| times in the last |startup_full_bw_rounds| @@ -175,8 +176,14 @@ struct QUIC_EXPORT_PRIVATE Bbr2Params { GetQuicReloadableFlag(quic_bbr2_add_ack_height_to_queueing_threshold); // Can be disabled by connection option 'B2RP'. - bool avoid_unnecessary_probe_rtt = - GetQuicReloadableFlag(quic_bbr2_avoid_unnecessary_probe_rtt); + bool avoid_unnecessary_probe_rtt = true; + + // Can be disabled by connection option 'B2CL'. + bool avoid_too_low_probe_bw_cwnd = + GetQuicReloadableFlag(quic_bbr2_avoid_too_low_probe_bw_cwnd); + + // Can be enabled by connection option 'B2LO'. + bool ignore_inflight_lo = false; }; class QUIC_EXPORT_PRIVATE RoundTripCounter { @@ -420,11 +427,7 @@ class QUIC_EXPORT_PRIVATE Bbr2NetworkModel { return std::numeric_limits<QuicByteCount>::max(); } void clear_inflight_lo() { inflight_lo_ = inflight_lo_default(); } - void cap_inflight_lo(QuicByteCount cap) { - if (inflight_lo_ != inflight_lo_default() && inflight_lo_ > cap) { - inflight_lo_ = cap; - } - } + void cap_inflight_lo(QuicByteCount cap); QuicByteCount inflight_hi_with_headroom() const; QuicByteCount inflight_hi() const { return inflight_hi_; } @@ -472,9 +475,6 @@ class QUIC_EXPORT_PRIVATE Bbr2NetworkModel { float cwnd_gain_; float pacing_gain_; - - const bool fix_zero_bw_on_loss_only_event_ = - GetQuicReloadableFlag(quic_bbr_fix_zero_bw_on_loss_only_event); }; enum class Bbr2Mode : uint8_t { diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc index 1a7a7193a16..6fb7eee8059 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc @@ -79,12 +79,36 @@ Bbr2Mode Bbr2ProbeBwMode::OnCongestionEvent( } Limits<QuicByteCount> Bbr2ProbeBwMode::GetCwndLimits() const { - if (cycle_.phase == CyclePhase::PROBE_CRUISE) { + if (!GetQuicReloadableFlag(quic_bbr2_avoid_too_low_probe_bw_cwnd)) { + if (cycle_.phase == CyclePhase::PROBE_CRUISE) { + return NoGreaterThan( + std::min(model_->inflight_lo(), model_->inflight_hi_with_headroom())); + } + return NoGreaterThan( - std::min(model_->inflight_lo(), model_->inflight_hi_with_headroom())); + std::min(model_->inflight_lo(), model_->inflight_hi())); + } + + QUIC_RELOADABLE_FLAG_COUNT(quic_bbr2_avoid_too_low_probe_bw_cwnd); + + QuicByteCount upper_limit = + std::min(model_->inflight_lo(), cycle_.phase == CyclePhase::PROBE_CRUISE + ? model_->inflight_hi_with_headroom() + : model_->inflight_hi()); + + if (Params().avoid_too_low_probe_bw_cwnd) { + // Ensure upper_limit is at least BDP + AckHeight. + QuicByteCount bdp_with_ack_height = + model_->BDP(model_->MaxBandwidth()) + model_->MaxAckHeight(); + if (upper_limit < bdp_with_ack_height) { + QUIC_DVLOG(3) << sender_ << " Rasing upper_limit from " << upper_limit + << " to " << bdp_with_ack_height; + QUIC_CODE_COUNT(quic_bbr2_avoid_too_low_probe_bw_cwnd_in_effect); + upper_limit = bdp_with_ack_height; + } } - return NoGreaterThan(std::min(model_->inflight_lo(), model_->inflight_hi())); + return NoGreaterThan(upper_limit); } bool Bbr2ProbeBwMode::IsProbingForBandwidth() const { diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.cc index 4d794432ec4..8c0171bc9bf 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.cc @@ -108,6 +108,37 @@ void Bbr2Sender::SetFromConfig(const QuicConfig& config, if (config.HasClientRequestedIndependentOption(kB2RP, perspective)) { params_.avoid_unnecessary_probe_rtt = false; } + if (GetQuicReloadableFlag(quic_bbr2_avoid_too_low_probe_bw_cwnd) && + config.HasClientRequestedIndependentOption(kB2CL, perspective)) { + params_.avoid_too_low_probe_bw_cwnd = false; + } + if (GetQuicReloadableFlag(quic_bbr2_fewer_startup_round_trips) && + config.HasClientRequestedIndependentOption(k1RTT, perspective)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_fewer_startup_round_trips, 1, 2); + params_.startup_full_bw_rounds = 1; + } + if (GetQuicReloadableFlag(quic_bbr2_fewer_startup_round_trips) && + config.HasClientRequestedIndependentOption(k2RTT, perspective)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_fewer_startup_round_trips, 2, 2); + params_.startup_full_bw_rounds = 2; + } + if (GetQuicReloadableFlag(quic_bbr2_ignore_inflight_lo) && + config.HasClientRequestedIndependentOption(kB2LO, perspective)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_bbr2_ignore_inflight_lo); + params_.ignore_inflight_lo = true; + } + + ApplyConnectionOptions(config.ClientRequestedIndependentOptions(perspective)); +} + +void Bbr2Sender::ApplyConnectionOptions( + const QuicTagVector& connection_options) { + if (GetQuicReloadableFlag(quic_bbr2_lower_startup_cwnd_gain) && + ContainsQuicTag(connection_options, kBBQ2)) { + // 2 is the lower, derived gain for CWND. + params_.startup_cwnd_gain = 2; + params_.drain_cwnd_gain = 2; + } } Limits<QuicByteCount> Bbr2Sender::GetCwndLimitsByMode() const { @@ -206,7 +237,6 @@ void Bbr2Sender::OnCongestionEvent(bool /*rtt_updated*/, last_sample_is_app_limited_ = congestion_event.last_sample_is_app_limited; if (congestion_event.bytes_in_flight == 0 && params().avoid_unnecessary_probe_rtt) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_avoid_unnecessary_probe_rtt, 2, 2); OnEnterQuiescence(event_time); } @@ -301,7 +331,6 @@ void Bbr2Sender::OnPacketSent(QuicTime sent_time, << ", total_lost:" << model_.total_bytes_lost() << " @ " << sent_time; if (bytes_in_flight == 0 && params().avoid_unnecessary_probe_rtt) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_avoid_unnecessary_probe_rtt, 1, 2); OnExitQuiescence(sent_time); } model_.OnPacketSent(sent_time, bytes_in_flight, packet_number, bytes, diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.h index d68a6a13265..60824cdbd4b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.h @@ -50,6 +50,8 @@ class QUIC_EXPORT_PRIVATE Bbr2Sender final : public SendAlgorithmInterface { void SetFromConfig(const QuicConfig& config, Perspective perspective) override; + void ApplyConnectionOptions(const QuicTagVector& connection_options) override; + void AdjustNetworkParameters(const NetworkParams& params) override; void SetInitialCongestionWindowInPackets( @@ -173,8 +175,8 @@ class QUIC_EXPORT_PRIVATE Bbr2Sender final : public SendAlgorithmInterface { QuicRandom* random_; QuicConnectionStats* connection_stats_; - // Don't use it directly outside of SetFromConfig. Instead, use params() to - // get read-only access. + // Don't use it directly outside of SetFromConfig and ApplyConnectionOptions. + // Instead, use params() to get read-only access. Bbr2Params params_; Bbr2NetworkModel model_; diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_simulator_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_simulator_test.cc index 949b2834e89..f803ab68cdf 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_simulator_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_simulator_test.cc @@ -890,11 +890,8 @@ TEST_F(Bbr2DefaultTopologyTest, ProbeRttAfterQuiescenceImmediatelyExits) { sender_->OnPacketSent(SimulatedNow(), /*bytes_in_flight=*/0, sender_unacked_map()->largest_sent_packet() + 1, kDefaultMaxPacketSize, HAS_RETRANSMITTABLE_DATA); - if (GetQuicReloadableFlag(quic_bbr2_avoid_unnecessary_probe_rtt)) { - EXPECT_EQ(sender_->ExportDebugState().mode, Bbr2Mode::PROBE_BW); - } else { - EXPECT_EQ(sender_->ExportDebugState().mode, Bbr2Mode::PROBE_RTT); - } + + EXPECT_EQ(sender_->ExportDebugState().mode, Bbr2Mode::PROBE_BW); } TEST_F(Bbr2DefaultTopologyTest, ProbeBwAfterQuiescencePostponeMinRttTimestamp) { @@ -921,7 +918,7 @@ TEST_F(Bbr2DefaultTopologyTest, ProbeBwAfterQuiescencePostponeMinRttTimestamp) { // Wait for entering a quiescence of 15 seconds. ASSERT_TRUE(simulator_.RunUntilOrTimeout( [this]() { return sender_unacked_map()->bytes_in_flight() == 0; }, - params.RTT())); + params.RTT() + timeout)); simulator_.RunFor(QuicTime::Delta::FromSeconds(15)); @@ -929,19 +926,13 @@ TEST_F(Bbr2DefaultTopologyTest, ProbeBwAfterQuiescencePostponeMinRttTimestamp) { SendBursts(params, 1, kDefaultTCPMSS, QuicTime::Delta::Zero()); const QuicTime min_rtt_timestamp_after_idle = sender_->ExportDebugState().min_rtt_timestamp; - if (GetQuicReloadableFlag(quic_bbr2_avoid_unnecessary_probe_rtt)) { - EXPECT_LT(min_rtt_timestamp_before_idle + QuicTime::Delta::FromSeconds(14), - min_rtt_timestamp_after_idle); - } else { - EXPECT_EQ(min_rtt_timestamp_before_idle, min_rtt_timestamp_after_idle); - } + + EXPECT_LT(min_rtt_timestamp_before_idle + QuicTime::Delta::FromSeconds(14), + min_rtt_timestamp_after_idle); } // Regression test for http://shortn/_Jt1QWtshAM. TEST_F(Bbr2DefaultTopologyTest, SwitchToBbr2MidConnection) { - if (!GetQuicReloadableFlag(quic_bbr_copy_sampler_state_from_v1_to_v2)) { - return; - } QuicTime now = QuicTime::Zero(); BbrSender old_sender(sender_connection()->clock()->Now(), sender_connection()->sent_packet_manager().GetRttStats(), @@ -1039,7 +1030,7 @@ TEST_F(Bbr2DefaultTopologyTest, SwitchToBbr2MidConnection) { // Receiver class MultiSenderTopologyParams { public: - static const size_t kNumLocalLinks = 8; + static constexpr size_t kNumLocalLinks = 8; std::array<LinkParams, kNumLocalLinks> local_links = { LinkParams(10000, 1987), LinkParams(10000, 1993), LinkParams(10000, 1997), LinkParams(10000, 1999), LinkParams(10000, 2003), LinkParams(10000, 2011), diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.cc index 8514d2accbc..1141ca09e05 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.cc @@ -47,8 +47,8 @@ Bbr2Mode Bbr2StartupMode::OnCongestionEvent( CheckExcessiveLosses(congestion_event); - model_->set_pacing_gain(Params().startup_gain); - model_->set_cwnd_gain(Params().startup_gain); + model_->set_pacing_gain(Params().startup_pacing_gain); + model_->set_cwnd_gain(Params().startup_cwnd_gain); // TODO(wub): Maybe implement STARTUP => PROBE_RTT. return full_bandwidth_reached_ ? Bbr2Mode::DRAIN : Bbr2Mode::STARTUP; diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.h index e8f37ff9b81..378a4fd83fd 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.h @@ -33,6 +33,8 @@ class QUIC_EXPORT_PRIVATE Bbr2StartupMode final : public Bbr2ModeBase { const Bbr2CongestionEvent& congestion_event) override; Limits<QuicByteCount> GetCwndLimits() const override { + // Inflight_lo is never set in STARTUP. + DCHECK_EQ(Bbr2NetworkModel::inflight_lo_default(), model_->inflight_lo()); return NoGreaterThan(model_->inflight_lo()); } diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.cc index 8331611252d..f150ec14787 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.cc @@ -259,9 +259,6 @@ bool BbrSender::IsPipeSufficientlyFull() const { void BbrSender::SetFromConfig(const QuicConfig& config, Perspective perspective) { - if (config.HasClientRequestedIndependentOption(kLRTT, perspective)) { - exit_startup_on_loss_ = true; - } if (config.HasClientRequestedIndependentOption(k1RTT, perspective)) { num_startup_rtts_ = 1; } @@ -303,10 +300,6 @@ void BbrSender::SetFromConfig(const QuicConfig& config, set_high_cwnd_gain(kDerivedHighGain); set_drain_gain(1.f / kDerivedHighGain); } - if (!exit_startup_on_loss_ && - config.HasClientRequestedIndependentOption(kBBQ2, perspective)) { - set_high_cwnd_gain(kDerivedHighCWNDGain); - } if (config.HasClientRequestedIndependentOption(kBBQ3, perspective)) { enable_ack_aggregation_during_startup_ = true; } @@ -327,6 +320,18 @@ void BbrSender::SetFromConfig(const QuicConfig& config, quic_avoid_overestimate_bandwidth_with_aggregation, 3, 4); sampler_.EnableOverestimateAvoidance(); } + + ApplyConnectionOptions(config.ClientRequestedIndependentOptions(perspective)); +} + +void BbrSender::ApplyConnectionOptions( + const QuicTagVector& connection_options) { + if (ContainsQuicTag(connection_options, kLRTT)) { + exit_startup_on_loss_ = true; + } + if (ContainsQuicTag(connection_options, kBBQ2)) { + set_high_cwnd_gain(kDerivedHighCWNDGain); + } } void BbrSender::AdjustNetworkParameters(const NetworkParams& params) { @@ -428,10 +433,8 @@ void BbrSender::OnCongestionEvent(bool /*rtt_updated*/, // packets in |acked_packets| did not generate valid samples. (e.g. ack of // ack-only packets). In both cases, sampler_.total_bytes_acked() will not // change. - if (!fix_zero_bw_on_loss_only_event_ || - (total_bytes_acked_before != sampler_.total_bytes_acked())) { - QUIC_BUG_IF((total_bytes_acked_before != sampler_.total_bytes_acked()) && - sample.sample_max_bandwidth.IsZero()) + if (total_bytes_acked_before != sampler_.total_bytes_acked()) { + QUIC_BUG_IF(sample.sample_max_bandwidth.IsZero()) << sampler_.total_bytes_acked() - total_bytes_acked_before << " bytes from " << acked_packets.size() << " packets have been acked, but sample_max_bandwidth is zero."; @@ -439,15 +442,8 @@ void BbrSender::OnCongestionEvent(bool /*rtt_updated*/, sample.sample_max_bandwidth > max_bandwidth_.GetBest()) { max_bandwidth_.Update(sample.sample_max_bandwidth, round_trip_count_); } - } else { - if (acked_packets.empty()) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr_fix_zero_bw_on_loss_only_event, 1, - 4); - } else { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr_fix_zero_bw_on_loss_only_event, 2, - 4); - } } + if (!sample.sample_rtt.IsInfinite()) { min_rtt_expired = MaybeUpdateMinRtt(event_time, sample.sample_rtt); } @@ -503,7 +499,16 @@ CongestionControlType BbrSender::GetCongestionControlType() const { } QuicTime::Delta BbrSender::GetMinRtt() const { - return !min_rtt_.IsZero() ? min_rtt_ : rtt_stats_->initial_rtt(); + if (!min_rtt_.IsZero()) { + return min_rtt_; + } + if (GetQuicReloadableFlag(quic_bbr_use_available_min_rtt)) { + // min_rtt could be available if the handshake packet gets neutered then + // gets acknowledged. This could only happen for QUIC crypto where we do not + // drop keys. + return rtt_stats_->MinOrInitialRtt(); + } + return rtt_stats_->initial_rtt(); } QuicByteCount BbrSender::GetTargetCongestionWindow(float gain) const { @@ -920,16 +925,9 @@ void BbrSender::CalculateRecoveryWindow(QuicByteCount bytes_acked, recovery_window_ += bytes_acked; } - // Sanity checks. Ensure that we always allow to send at least an MSS or - // |bytes_acked| in response, whichever is larger. + // Always allow sending at least |bytes_acked| in response. recovery_window_ = std::max( recovery_window_, unacked_packets_->bytes_in_flight() + bytes_acked); - if (GetQuicReloadableFlag(quic_bbr_one_mss_conservation)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_bbr_one_mss_conservation); - recovery_window_ = - std::max(recovery_window_, - unacked_packets_->bytes_in_flight() + kMaxSegmentSize); - } recovery_window_ = std::max(min_congestion_window_, recovery_window_); } diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h index ab5d8197419..c7285d76f24 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h @@ -106,6 +106,7 @@ class QUIC_EXPORT_PRIVATE BbrSender : public SendAlgorithmInterface { void SetFromConfig(const QuicConfig& config, Perspective perspective) override; + void ApplyConnectionOptions(const QuicTagVector& connection_options) override; void AdjustNetworkParameters(const NetworkParams& params) override; void SetInitialCongestionWindowInPackets( @@ -390,9 +391,6 @@ class QUIC_EXPORT_PRIVATE BbrSender : public SendAlgorithmInterface { // or it's time for high gain mode. bool drain_to_target_; - const bool fix_zero_bw_on_loss_only_event_ = - GetQuicReloadableFlag(quic_bbr_fix_zero_bw_on_loss_only_event); - // True if network parameters are adjusted, and this will be reset if // overshooting is detected and pacing rate gets slowed. bool network_parameters_adjusted_; diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender_test.cc index e07931b8c79..e50a7c04c61 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender_test.cc @@ -341,7 +341,6 @@ TEST_F(BbrSenderTest, SimpleTransferSmallBuffer) { } TEST_F(BbrSenderTest, RemoveBytesLostInRecovery) { - SetQuicReloadableFlag(quic_bbr_one_mss_conservation, false); // Disable Ack Decimation on the receiver, because it can increase srtt. QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING); CreateDefaultSetup(); @@ -1372,9 +1371,7 @@ TEST_F(BbrSenderTest, LossOnlyCongestionEvent) { lost_packets); // Bandwidth estimate should not change for the loss only event. - if (GetQuicReloadableFlag(quic_bbr_fix_zero_bw_on_loss_only_event)) { - EXPECT_EQ(prior_bandwidth_estimate, sender_->BandwidthEstimate()); - } + EXPECT_EQ(prior_bandwidth_estimate, sender_->BandwidthEstimate()); } } // namespace test diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.cc index 6c090136c1a..f00045e7b8e 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.cc @@ -15,7 +15,7 @@ namespace quic { GeneralLossAlgorithm::GeneralLossAlgorithm() : loss_detection_timeout_(QuicTime::Zero()), reordering_shift_(kDefaultLossDelayShift), - reordering_threshold_(kNumberOfNacksBeforeRetransmission), + reordering_threshold_(kDefaultPacketReorderingThreshold), use_adaptive_reordering_threshold_(true), use_adaptive_time_threshold_(false), use_packet_threshold_for_runt_packets_(true), @@ -23,15 +23,17 @@ GeneralLossAlgorithm::GeneralLossAlgorithm() packet_number_space_(NUM_PACKET_NUMBER_SPACES) {} // Uses nack counts to decide when packets are lost. -void GeneralLossAlgorithm::DetectLosses( +LossDetectionInterface::DetectionStats GeneralLossAlgorithm::DetectLosses( const QuicUnackedPacketMap& unacked_packets, QuicTime time, const RttStats& rtt_stats, QuicPacketNumber largest_newly_acked, const AckedPacketVector& packets_acked, LostPacketVector* packets_lost) { + DetectionStats detection_stats; + loss_detection_timeout_ = QuicTime::Zero(); - if (!packets_acked.empty() && + if (!packets_acked.empty() && least_in_flight_.IsInitialized() && packets_acked.front().packet_number == least_in_flight_) { if (packets_acked.back().packet_number == largest_newly_acked && least_in_flight_ + packets_acked.size() - 1 == largest_newly_acked) { @@ -40,7 +42,7 @@ void GeneralLossAlgorithm::DetectLosses( // do not use this optimization if largest_newly_acked is not the largest // packet in packets_acked. least_in_flight_ = largest_newly_acked + 1; - return; + return detection_stats; } // There is hole in acked_packets, increment least_in_flight_ if possible. for (const auto& acked : packets_acked) { @@ -50,6 +52,7 @@ void GeneralLossAlgorithm::DetectLosses( ++least_in_flight_; } } + QuicTime::Delta max_rtt = std::max(rtt_stats.previous_srtt(), rtt_stats.latest_rtt()); max_rtt = std::max(kAlarmGranularity, max_rtt); @@ -77,19 +80,23 @@ void GeneralLossAlgorithm::DetectLosses( // Skip packets of different packet number space. continue; } + if (!it->in_flight) { continue; } + + if (largest_newly_acked - packet_number > + detection_stats.sent_packets_max_sequence_reordering) { + detection_stats.sent_packets_max_sequence_reordering = + largest_newly_acked - packet_number; + } + // Packet threshold loss detection. // Skip packet threshold loss detection if largest_newly_acked is a runt. const bool skip_packet_threshold_detection = !use_packet_threshold_for_runt_packets_ && it->bytes_sent > unacked_packets.GetTransmissionInfo(largest_newly_acked).bytes_sent; - if (skip_packet_threshold_detection) { - QUIC_RELOADABLE_FLAG_COUNT_N( - quic_skip_packet_threshold_loss_detection_with_runt, 2, 2); - } if (!skip_packet_threshold_detection && largest_newly_acked - packet_number >= reordering_threshold_) { packets_lost->push_back(LostPacket(packet_number, it->bytes_sent)); @@ -112,6 +119,8 @@ void GeneralLossAlgorithm::DetectLosses( // There is no in flight packet. least_in_flight_ = largest_newly_acked + 1; } + + return detection_stats; } QuicTime GeneralLossAlgorithm::GetLossTimeout() const { diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.h index 7ab0d536eb7..ee8ba64c2d7 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.h @@ -11,6 +11,7 @@ #include "net/third_party/quiche/src/quic/core/congestion_control/loss_detection_interface.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/core/quic_time.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" @@ -21,21 +22,21 @@ namespace quic { // Also implements TCP's early retransmit(RFC5827). class QUIC_EXPORT_PRIVATE GeneralLossAlgorithm : public LossDetectionInterface { public: - // TCP retransmits after 3 nacks. - static const QuicPacketCount kNumberOfNacksBeforeRetransmission = 3; - GeneralLossAlgorithm(); GeneralLossAlgorithm(const GeneralLossAlgorithm&) = delete; GeneralLossAlgorithm& operator=(const GeneralLossAlgorithm&) = delete; ~GeneralLossAlgorithm() override {} + void SetFromConfig(const QuicConfig& /*config*/, + Perspective /*perspective*/) override {} + // Uses |largest_acked| and time to decide when packets are lost. - void DetectLosses(const QuicUnackedPacketMap& unacked_packets, - QuicTime time, - const RttStats& rtt_stats, - QuicPacketNumber largest_newly_acked, - const AckedPacketVector& packets_acked, - LostPacketVector* packets_lost) override; + DetectionStats DetectLosses(const QuicUnackedPacketMap& unacked_packets, + QuicTime time, + const RttStats& rtt_stats, + QuicPacketNumber largest_newly_acked, + const AckedPacketVector& packets_acked, + LostPacketVector* packets_lost) override; // Returns a non-zero value when the early retransmit timer is active. QuicTime GetLossTimeout() const override; @@ -66,6 +67,8 @@ class QUIC_EXPORT_PRIVATE GeneralLossAlgorithm : public LossDetectionInterface { void Reset(); + QuicPacketCount reordering_threshold() const { return reordering_threshold_; } + int reordering_shift() const { return reordering_shift_; } void set_reordering_shift(int reordering_shift) { diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm_test.cc index 7bef933b93f..1a58ade2695 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm_test.cc @@ -61,12 +61,25 @@ class GeneralLossAlgorithmTest : public QuicTest { void VerifyLosses(uint64_t largest_newly_acked, const AckedPacketVector& packets_acked, const std::vector<uint64_t>& losses_expected) { + return VerifyLosses(largest_newly_acked, packets_acked, losses_expected, + quiche::QuicheOptional<QuicPacketCount>()); + } + + void VerifyLosses(uint64_t largest_newly_acked, + const AckedPacketVector& packets_acked, + const std::vector<uint64_t>& losses_expected, + quiche::QuicheOptional<QuicPacketCount> + max_sequence_reordering_expected) { unacked_packets_.MaybeUpdateLargestAckedOfPacketNumberSpace( APPLICATION_DATA, QuicPacketNumber(largest_newly_acked)); LostPacketVector lost_packets; - loss_algorithm_.DetectLosses(unacked_packets_, clock_.Now(), rtt_stats_, - QuicPacketNumber(largest_newly_acked), - packets_acked, &lost_packets); + LossDetectionInterface::DetectionStats stats = loss_algorithm_.DetectLosses( + unacked_packets_, clock_.Now(), rtt_stats_, + QuicPacketNumber(largest_newly_acked), packets_acked, &lost_packets); + if (max_sequence_reordering_expected.has_value()) { + EXPECT_EQ(stats.sent_packets_max_sequence_reordering, + max_sequence_reordering_expected.value()); + } ASSERT_EQ(losses_expected.size(), lost_packets.size()); for (size_t i = 0; i < losses_expected.size(); ++i) { EXPECT_EQ(lost_packets[i].packet_number, @@ -91,19 +104,19 @@ TEST_F(GeneralLossAlgorithmTest, NackRetransmit1Packet) { unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2)); packets_acked.push_back(AckedPacket( QuicPacketNumber(2), kMaxOutgoingPacketSize, QuicTime::Zero())); - VerifyLosses(2, packets_acked, std::vector<uint64_t>{}); + VerifyLosses(2, packets_acked, std::vector<uint64_t>{}, 1); packets_acked.clear(); // No loss on two acks. unacked_packets_.RemoveFromInFlight(QuicPacketNumber(3)); packets_acked.push_back(AckedPacket( QuicPacketNumber(3), kMaxOutgoingPacketSize, QuicTime::Zero())); - VerifyLosses(3, packets_acked, std::vector<uint64_t>{}); + VerifyLosses(3, packets_acked, std::vector<uint64_t>{}, 2); packets_acked.clear(); // Loss on three acks. unacked_packets_.RemoveFromInFlight(QuicPacketNumber(4)); packets_acked.push_back(AckedPacket( QuicPacketNumber(4), kMaxOutgoingPacketSize, QuicTime::Zero())); - VerifyLosses(4, packets_acked, {1}); + VerifyLosses(4, packets_acked, {1}, 3); EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); } diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/loss_detection_interface.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/loss_detection_interface.h index 729cbad62ad..8d91976de45 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/loss_detection_interface.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/loss_detection_interface.h @@ -8,8 +8,10 @@ #define QUICHE_QUIC_CORE_CONGESTION_CONTROL_LOSS_DETECTION_INTERFACE_H_ #include "net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h" +#include "net/third_party/quiche/src/quic/core/quic_config.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/core/quic_time.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" namespace quic { @@ -20,13 +22,23 @@ class RttStats; class QUIC_EXPORT_PRIVATE LossDetectionInterface { public: virtual ~LossDetectionInterface() {} + + virtual void SetFromConfig(const QuicConfig& config, + Perspective perspective) = 0; + + struct QUIC_NO_EXPORT DetectionStats { + // Maximum sequence reordering observed in newly acked packets. + QuicPacketCount sent_packets_max_sequence_reordering = 0; + }; + // Called when a new ack arrives or the loss alarm fires. - virtual void DetectLosses(const QuicUnackedPacketMap& unacked_packets, - QuicTime time, - const RttStats& rtt_stats, - QuicPacketNumber largest_newly_acked, - const AckedPacketVector& packets_acked, - LostPacketVector* packets_lost) = 0; + virtual DetectionStats DetectLosses( + const QuicUnackedPacketMap& unacked_packets, + QuicTime time, + const RttStats& rtt_stats, + QuicPacketNumber largest_newly_acked, + const AckedPacketVector& packets_acked, + LostPacketVector* packets_lost) = 0; // Get the time the LossDetectionAlgorithm wants to re-evaluate losses. // Returns QuicTime::Zero if no alarm needs to be set. diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender.h index 781a9211951..a8436f8fc7d 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender.h @@ -74,10 +74,14 @@ class QUIC_EXPORT_PRIVATE PacingSender { QuicBandwidth PacingRate(QuicByteCount bytes_in_flight) const; - QuicTime ideal_next_packet_send_time() const { - return ideal_next_packet_send_time_; + NextReleaseTimeResult GetNextReleaseTime() const { + bool allow_burst = (burst_tokens_ > 0 || lumpy_tokens_ > 0); + return {ideal_next_packet_send_time_, allow_burst}; } + protected: + uint32_t lumpy_tokens() const { return lumpy_tokens_; } + private: friend class test::QuicSentPacketManagerPeer; diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender_test.cc index 3ca80cda87a..8c298d9ccfb 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender_test.cc @@ -27,6 +27,16 @@ namespace test { const QuicByteCount kBytesInFlight = 1024; const int kInitialBurstPackets = 10; +class TestPacingSender : public PacingSender { + public: + using PacingSender::lumpy_tokens; + using PacingSender::PacingSender; + + QuicTime ideal_next_packet_send_time() const { + return GetNextReleaseTime().release_time; + } +}; + class PacingSenderTest : public QuicTest { protected: PacingSenderTest() @@ -34,7 +44,7 @@ class PacingSenderTest : public QuicTest { infinite_time_(QuicTime::Delta::Infinite()), packet_number_(1), mock_sender_(new StrictMock<MockSendAlgorithm>()), - pacing_sender_(new PacingSender) { + pacing_sender_(new TestPacingSender) { pacing_sender_->set_sender(mock_sender_.get()); // Pick arbitrary time. clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(9)); @@ -44,7 +54,7 @@ class PacingSenderTest : public QuicTest { void InitPacingRate(QuicPacketCount burst_size, QuicBandwidth bandwidth) { mock_sender_ = std::make_unique<StrictMock<MockSendAlgorithm>>(); - pacing_sender_ = std::make_unique<PacingSender>(); + pacing_sender_ = std::make_unique<TestPacingSender>(); pacing_sender_->set_sender(mock_sender_.get()); EXPECT_CALL(*mock_sender_, PacingRate(_)).WillRepeatedly(Return(bandwidth)); EXPECT_CALL(*mock_sender_, BandwidthEstimate()) @@ -132,7 +142,7 @@ class PacingSenderTest : public QuicTest { MockClock clock_; QuicPacketNumber packet_number_; std::unique_ptr<StrictMock<MockSendAlgorithm>> mock_sender_; - std::unique_ptr<PacingSender> pacing_sender_; + std::unique_ptr<TestPacingSender> pacing_sender_; }; TEST_F(PacingSenderTest, NoSend) { @@ -466,5 +476,77 @@ TEST_F(PacingSenderTest, NoLumpyPacingForLowBandwidthFlows) { } } +TEST_F(PacingSenderTest, IdealNextPacketSendTimeWithLumpyPacing) { + // Set lumpy size to be 3, and cwnd faction to 0.5 + SetQuicFlag(FLAGS_quic_lumpy_pacing_size, 3); + SetQuicFlag(FLAGS_quic_lumpy_pacing_cwnd_fraction, 0.5f); + + // Configure pacing rate of 1 packet per millisecond. + QuicTime::Delta inter_packet_delay = QuicTime::Delta::FromMilliseconds(1); + InitPacingRate(kInitialBurstPackets, + QuicBandwidth::FromBytesAndTimeDelta(kMaxOutgoingPacketSize, + inter_packet_delay)); + + // Send kInitialBurstPackets packets, and verify that they are not paced. + for (int i = 0; i < kInitialBurstPackets; ++i) { + CheckPacketIsSentImmediately(); + } + + CheckPacketIsSentImmediately(); + EXPECT_EQ(pacing_sender_->ideal_next_packet_send_time(), + clock_.Now() + inter_packet_delay); + EXPECT_EQ(pacing_sender_->lumpy_tokens(), 2u); + + CheckPacketIsSentImmediately(); + EXPECT_EQ(pacing_sender_->ideal_next_packet_send_time(), + clock_.Now() + 2 * inter_packet_delay); + EXPECT_EQ(pacing_sender_->lumpy_tokens(), 1u); + + CheckPacketIsSentImmediately(); + EXPECT_EQ(pacing_sender_->ideal_next_packet_send_time(), + clock_.Now() + 3 * inter_packet_delay); + EXPECT_EQ(pacing_sender_->lumpy_tokens(), 0u); + + CheckPacketIsDelayed(3 * inter_packet_delay); + + // Wake up on time. + clock_.AdvanceTime(3 * inter_packet_delay); + CheckPacketIsSentImmediately(); + EXPECT_EQ(pacing_sender_->ideal_next_packet_send_time(), + clock_.Now() + inter_packet_delay); + EXPECT_EQ(pacing_sender_->lumpy_tokens(), 2u); + + CheckPacketIsSentImmediately(); + EXPECT_EQ(pacing_sender_->ideal_next_packet_send_time(), + clock_.Now() + 2 * inter_packet_delay); + EXPECT_EQ(pacing_sender_->lumpy_tokens(), 1u); + + CheckPacketIsSentImmediately(); + EXPECT_EQ(pacing_sender_->ideal_next_packet_send_time(), + clock_.Now() + 3 * inter_packet_delay); + EXPECT_EQ(pacing_sender_->lumpy_tokens(), 0u); + + CheckPacketIsDelayed(3 * inter_packet_delay); + + // Wake up late. + clock_.AdvanceTime(4.5 * inter_packet_delay); + CheckPacketIsSentImmediately(); + EXPECT_EQ(pacing_sender_->ideal_next_packet_send_time(), + clock_.Now() - 0.5 * inter_packet_delay); + EXPECT_EQ(pacing_sender_->lumpy_tokens(), 2u); + + CheckPacketIsSentImmediately(); + EXPECT_EQ(pacing_sender_->ideal_next_packet_send_time(), + clock_.Now() + 0.5 * inter_packet_delay); + EXPECT_EQ(pacing_sender_->lumpy_tokens(), 1u); + + CheckPacketIsSentImmediately(); + EXPECT_EQ(pacing_sender_->ideal_next_packet_send_time(), + clock_.Now() + 1.5 * inter_packet_delay); + EXPECT_EQ(pacing_sender_->lumpy_tokens(), 0u); + + CheckPacketIsDelayed(1.5 * inter_packet_delay); +} + } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h index 9062c7a339c..f247c1caa28 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h @@ -72,6 +72,10 @@ class QUIC_EXPORT_PRIVATE RttStats { return smoothed_rtt_.IsZero() ? initial_rtt_ : smoothed_rtt_; } + QuicTime::Delta MinOrInitialRtt() const { + return min_rtt_.IsZero() ? initial_rtt_ : min_rtt_; + } + // Sets an initial RTT to be used for SmoothedRtt before any RTT updates. void set_initial_rtt(QuicTime::Delta initial_rtt) { if (initial_rtt.ToMicroseconds() <= 0) { diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.cc index d7b2eca3c74..9d003c59a66 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.cc @@ -45,12 +45,7 @@ SendAlgorithmInterface* SendAlgorithmInterface::Create( ? static_cast<BbrSender*>(old_send_algorithm) : nullptr); case kPCC: - if (GetQuicReloadableFlag(quic_enable_pcc3)) { - return CreatePccSender(clock, rtt_stats, unacked_packets, random, stats, - initial_congestion_window, - max_congestion_window); - } - // Fall back to CUBIC if PCC is disabled. + // PCC is work has stalled, fall back to CUBIC instead. QUIC_FALLTHROUGH_INTENDED; case kCubicBytes: return new TcpCubicSenderBytes( diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h index 2bfc2dfbcf3..ea0c375d8aa 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h @@ -86,6 +86,9 @@ class QUIC_EXPORT_PRIVATE SendAlgorithmInterface { virtual void SetFromConfig(const QuicConfig& config, Perspective perspective) = 0; + virtual void ApplyConnectionOptions( + const QuicTagVector& connection_options) = 0; + // Sets the initial congestion window in number of packets. May be ignored // if called after the initial congestion window is no longer relevant. virtual void SetInitialCongestionWindowInPackets(QuicPacketCount packets) = 0; diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes.h index 7a36f761c1a..59ca7f875be 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes.h @@ -46,6 +46,8 @@ class QUIC_EXPORT_PRIVATE TcpCubicSenderBytes : public SendAlgorithmInterface { // Start implementation of SendAlgorithmInterface. void SetFromConfig(const QuicConfig& config, Perspective perspective) override; + void ApplyConnectionOptions( + const QuicTagVector& /*connection_options*/) override {} void AdjustNetworkParameters(const NetworkParams& params) override; void SetNumEmulatedConnections(int num_connections); void SetInitialCongestionWindowInPackets( diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.cc index 73b26f5cda7..0f294d6b94e 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.cc @@ -6,6 +6,7 @@ #include <algorithm> +#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" namespace quic { @@ -17,13 +18,24 @@ UberLossAlgorithm::UberLossAlgorithm() { } } -void UberLossAlgorithm::DetectLosses( +void UberLossAlgorithm::SetFromConfig(const QuicConfig& config, + Perspective perspective) { + if (config.HasClientRequestedIndependentOption(kELDT, perspective) && + tuner_ != nullptr) { + tuning_enabled_ = true; + MaybeStartTuning(); + } +} + +LossDetectionInterface::DetectionStats UberLossAlgorithm::DetectLosses( const QuicUnackedPacketMap& unacked_packets, QuicTime time, const RttStats& rtt_stats, QuicPacketNumber /*largest_newly_acked*/, const AckedPacketVector& packets_acked, LostPacketVector* packets_lost) { + DetectionStats overall_stats; + for (int8_t i = INITIAL_DATA; i < NUM_PACKET_NUMBER_SPACES; ++i) { const QuicPacketNumber largest_acked = unacked_packets.GetLargestAckedOfPacketNumberSpace( @@ -35,10 +47,16 @@ void UberLossAlgorithm::DetectLosses( continue; } - general_loss_algorithms_[i].DetectLosses(unacked_packets, time, rtt_stats, - largest_acked, packets_acked, - packets_lost); + DetectionStats stats = general_loss_algorithms_[i].DetectLosses( + unacked_packets, time, rtt_stats, largest_acked, packets_acked, + packets_lost); + + overall_stats.sent_packets_max_sequence_reordering = + std::max(overall_stats.sent_packets_max_sequence_reordering, + stats.sent_packets_max_sequence_reordering); } + + return overall_stats; } QuicTime UberLossAlgorithm::GetLossTimeout() const { @@ -78,7 +96,7 @@ void UberLossAlgorithm::SetLossDetectionTuner( } void UberLossAlgorithm::MaybeStartTuning() { - if (tuner_ == nullptr || tuner_started_) { + if (tuner_started_ || !tuning_enabled_ || !min_rtt_available_) { return; } @@ -88,6 +106,7 @@ void UberLossAlgorithm::MaybeStartTuning() { void UberLossAlgorithm::OnConfigNegotiated() {} void UberLossAlgorithm::OnMinRttAvailable() { + min_rtt_available_ = true; MaybeStartTuning(); } @@ -128,6 +147,10 @@ void UberLossAlgorithm::EnableAdaptiveTimeThreshold() { } } +QuicPacketCount UberLossAlgorithm::GetPacketReorderingThreshold() const { + return general_loss_algorithms_[APPLICATION_DATA].reordering_threshold(); +} + void UberLossAlgorithm::DisablePacketThresholdForRuntPackets() { for (int8_t i = INITIAL_DATA; i < NUM_PACKET_NUMBER_SPACES; ++i) { general_loss_algorithms_[i].disable_packet_threshold_for_runt_packets(); diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.h index ff1ac817b3c..86b652572b7 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.h @@ -6,6 +6,7 @@ #define QUICHE_QUIC_CORE_CONGESTION_CONTROL_UBER_LOSS_ALGORITHM_H_ #include "net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/common/platform/api/quiche_optional.h" namespace quic { @@ -46,13 +47,16 @@ class QUIC_EXPORT_PRIVATE UberLossAlgorithm : public LossDetectionInterface { UberLossAlgorithm& operator=(const UberLossAlgorithm&) = delete; ~UberLossAlgorithm() override {} + void SetFromConfig(const QuicConfig& config, + Perspective perspective) override; + // Detects lost packets. - void DetectLosses(const QuicUnackedPacketMap& unacked_packets, - QuicTime time, - const RttStats& rtt_stats, - QuicPacketNumber largest_newly_acked, - const AckedPacketVector& packets_acked, - LostPacketVector* packets_lost) override; + DetectionStats DetectLosses(const QuicUnackedPacketMap& unacked_packets, + QuicTime time, + const RttStats& rtt_stats, + QuicPacketNumber largest_newly_acked, + const AckedPacketVector& packets_acked, + LostPacketVector* packets_lost) override; // Returns the earliest time the early retransmit timer should be active. QuicTime GetLossTimeout() const override; @@ -85,6 +89,10 @@ class QUIC_EXPORT_PRIVATE UberLossAlgorithm : public LossDetectionInterface { // Enable adaptive time threshold of all packet number spaces. void EnableAdaptiveTimeThreshold(); + // Get the packet reordering threshold from the APPLICATION_DATA PN space. + // Always 3 when adaptive reordering is not enabled. + QuicPacketCount GetPacketReorderingThreshold() const; + // Disable packet threshold loss detection for *runt* packets. void DisablePacketThresholdForRuntPackets(); @@ -103,6 +111,8 @@ class QUIC_EXPORT_PRIVATE UberLossAlgorithm : public LossDetectionInterface { std::unique_ptr<LossDetectionTunerInterface> tuner_; LossDetectionParameters tuned_parameters_; bool tuner_started_ = false; + bool min_rtt_available_ = false; + bool tuning_enabled_ = false; // Whether tuning is enabled by config. }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc index a3daf095d56..6fd949f317a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc @@ -11,6 +11,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/test_tools/mock_clock.h" #include "net/third_party/quiche/src/quic/test_tools/quic_unacked_packet_map_peer.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_optional.h" namespace quic { namespace test { @@ -64,10 +65,23 @@ class UberLossAlgorithmTest : public QuicTest { void VerifyLosses(uint64_t largest_newly_acked, const AckedPacketVector& packets_acked, const std::vector<uint64_t>& losses_expected) { + return VerifyLosses(largest_newly_acked, packets_acked, losses_expected, + quiche::QuicheOptional<QuicPacketCount>()); + } + + void VerifyLosses(uint64_t largest_newly_acked, + const AckedPacketVector& packets_acked, + const std::vector<uint64_t>& losses_expected, + quiche::QuicheOptional<QuicPacketCount> + max_sequence_reordering_expected) { LostPacketVector lost_packets; - loss_algorithm_.DetectLosses(*unacked_packets_, clock_.Now(), rtt_stats_, - QuicPacketNumber(largest_newly_acked), - packets_acked, &lost_packets); + LossDetectionInterface::DetectionStats stats = loss_algorithm_.DetectLosses( + *unacked_packets_, clock_.Now(), rtt_stats_, + QuicPacketNumber(largest_newly_acked), packets_acked, &lost_packets); + if (max_sequence_reordering_expected.has_value()) { + EXPECT_EQ(stats.sent_packets_max_sequence_reordering, + max_sequence_reordering_expected.value()); + } ASSERT_EQ(losses_expected.size(), lost_packets.size()); for (size_t i = 0; i < losses_expected.size(); ++i) { EXPECT_EQ(lost_packets[i].packet_number, @@ -98,7 +112,7 @@ TEST_F(UberLossAlgorithmTest, ScenarioA) { unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace( HANDSHAKE_DATA, QuicPacketNumber(4)); // Verify no packet is detected lost. - VerifyLosses(4, packets_acked_, std::vector<uint64_t>{}); + VerifyLosses(4, packets_acked_, std::vector<uint64_t>{}, 0); EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); } @@ -114,7 +128,7 @@ TEST_F(UberLossAlgorithmTest, ScenarioB) { unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace( APPLICATION_DATA, QuicPacketNumber(4)); // No packet loss by acking 4. - VerifyLosses(4, packets_acked_, std::vector<uint64_t>{}); + VerifyLosses(4, packets_acked_, std::vector<uint64_t>{}, 1); EXPECT_EQ(clock_.Now() + 1.25 * rtt_stats_.smoothed_rtt(), loss_algorithm_.GetLossTimeout()); @@ -122,14 +136,14 @@ TEST_F(UberLossAlgorithmTest, ScenarioB) { AckPackets({6}); unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace( APPLICATION_DATA, QuicPacketNumber(6)); - VerifyLosses(6, packets_acked_, std::vector<uint64_t>{3}); + VerifyLosses(6, packets_acked_, std::vector<uint64_t>{3}, 3); EXPECT_EQ(clock_.Now() + 1.25 * rtt_stats_.smoothed_rtt(), loss_algorithm_.GetLossTimeout()); packets_acked_.clear(); clock_.AdvanceTime(1.25 * rtt_stats_.latest_rtt()); // Verify 5 will be early retransmitted. - VerifyLosses(6, packets_acked_, {5}); + VerifyLosses(6, packets_acked_, {5}, 1); } TEST_F(UberLossAlgorithmTest, ScenarioC) { @@ -151,14 +165,14 @@ TEST_F(UberLossAlgorithmTest, ScenarioC) { unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace( HANDSHAKE_DATA, QuicPacketNumber(5)); // No packet loss by acking 5. - VerifyLosses(5, packets_acked_, std::vector<uint64_t>{}); + VerifyLosses(5, packets_acked_, std::vector<uint64_t>{}, 2); EXPECT_EQ(clock_.Now() + 1.25 * rtt_stats_.smoothed_rtt(), loss_algorithm_.GetLossTimeout()); packets_acked_.clear(); clock_.AdvanceTime(1.25 * rtt_stats_.latest_rtt()); // Verify 2 and 3 will be early retransmitted. - VerifyLosses(5, packets_acked_, std::vector<uint64_t>{2, 3}); + VerifyLosses(5, packets_acked_, std::vector<uint64_t>{2, 3}, 2); } // Regression test for b/133771183. diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.cc index 6400528c8fd..0f17d121ca0 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.cc @@ -6,15 +6,24 @@ #include <cstdint> #include <memory> +#include <string> +#include "third_party/boringssl/src/include/openssl/base.h" #include "third_party/boringssl/src/include/openssl/bytestring.h" +#include "third_party/boringssl/src/include/openssl/digest.h" #include "third_party/boringssl/src/include/openssl/ec.h" #include "third_party/boringssl/src/include/openssl/evp.h" #include "third_party/boringssl/src/include/openssl/nid.h" +#include "third_party/boringssl/src/include/openssl/rsa.h" +#include "third_party/boringssl/src/include/openssl/ssl.h" #include "net/third_party/quiche/src/quic/core/crypto/boring_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" #include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_optional.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h" // The literals below were encoded using `ascii2der | xxd -i`. The comments // above the literals are the contents in the der2ascii syntax. @@ -27,10 +36,110 @@ constexpr uint8_t kX509Version[] = {0x02, 0x01, 0x02}; // 2.5.29.17 constexpr uint8_t kSubjectAltNameOid[] = {0x55, 0x1d, 0x11}; +enum class PublicKeyType { + kRsa, + kP256, + kP384, + kEd25519, + kUnknown, +}; + +PublicKeyType PublicKeyTypeFromKey(EVP_PKEY* public_key) { + switch (EVP_PKEY_id(public_key)) { + case EVP_PKEY_RSA: + return PublicKeyType::kRsa; + case EVP_PKEY_EC: { + const EC_KEY* key = EVP_PKEY_get0_EC_KEY(public_key); + if (key == nullptr) { + return PublicKeyType::kUnknown; + } + const EC_GROUP* group = EC_KEY_get0_group(key); + if (group == nullptr) { + return PublicKeyType::kUnknown; + } + const int curve_nid = EC_GROUP_get_curve_name(group); + switch (curve_nid) { + case NID_X9_62_prime256v1: + return PublicKeyType::kP256; + case NID_secp384r1: + return PublicKeyType::kP384; + default: + return PublicKeyType::kUnknown; + } + } + case EVP_PKEY_ED25519: + return PublicKeyType::kEd25519; + default: + return PublicKeyType::kUnknown; + } +} + +PublicKeyType PublicKeyTypeFromSignatureAlgorithm( + uint16_t signature_algorithm) { + switch (signature_algorithm) { + case SSL_SIGN_RSA_PSS_RSAE_SHA256: + return PublicKeyType::kRsa; + case SSL_SIGN_ECDSA_SECP256R1_SHA256: + return PublicKeyType::kP384; + case SSL_SIGN_ECDSA_SECP384R1_SHA384: + return PublicKeyType::kP384; + case SSL_SIGN_ED25519: + return PublicKeyType::kEd25519; + default: + return PublicKeyType::kUnknown; + } +} + } // namespace namespace quic { +PemReadResult ReadNextPemMessage(std::istream* input) { + constexpr quiche::QuicheStringPiece kPemBegin = "-----BEGIN "; + constexpr quiche::QuicheStringPiece kPemEnd = "-----END "; + constexpr quiche::QuicheStringPiece kPemDashes = "-----"; + + std::string line_buffer, encoded_message_contents, expected_end; + bool pending_message = false; + PemReadResult result; + while (std::getline(*input, line_buffer)) { + quiche::QuicheStringPiece line(line_buffer); + quiche::QuicheTextUtils::RemoveLeadingAndTrailingWhitespace(&line); + + // Handle BEGIN lines. + if (!pending_message && + quiche::QuicheTextUtils::StartsWith(line, kPemBegin) && + quiche::QuicheTextUtils::EndsWith(line, kPemDashes)) { + result.type = std::string( + line.substr(kPemBegin.size(), + line.size() - kPemDashes.size() - kPemBegin.size())); + expected_end = quiche::QuicheStrCat(kPemEnd, result.type, kPemDashes); + pending_message = true; + continue; + } + + // Handle END lines. + if (pending_message && line == expected_end) { + quiche::QuicheOptional<std::string> data = + quiche::QuicheTextUtils::Base64Decode(encoded_message_contents); + if (data.has_value()) { + result.status = PemReadResult::kOk; + result.contents = data.value(); + } else { + result.status = PemReadResult::kError; + } + return result; + } + + if (pending_message) { + encoded_message_contents.append(std::string(line)); + } + } + bool eof_reached = input->eof() && !pending_message; + return PemReadResult{ + .status = (eof_reached ? PemReadResult::kEof : PemReadResult::kError)}; +} + std::unique_ptr<CertificateView> CertificateView::ParseSingleCertificate( quiche::QuicheStringPiece certificate) { std::unique_ptr<CertificateView> result(new CertificateView()); @@ -207,6 +316,24 @@ bool CertificateView::ParseExtensions(CBS extensions) { return true; } +std::vector<std::string> CertificateView::LoadPemFromStream( + std::istream* input) { + std::vector<std::string> result; + for (;;) { + PemReadResult read_result = ReadNextPemMessage(input); + if (read_result.status == PemReadResult::kEof) { + return result; + } + if (read_result.status != PemReadResult::kOk) { + return std::vector<std::string>(); + } + if (read_result.type != "CERTIFICATE") { + continue; + } + result.emplace_back(std::move(read_result.contents)); + } +} + bool CertificateView::ValidatePublicKeyParameters() { // The profile here affects what certificates can be used: // (1) when QUIC is used as a server library without any custom certificate @@ -215,32 +342,130 @@ bool CertificateView::ValidatePublicKeyParameters() { // The goal is to allow at minimum any certificate that would be allowed on a // regular Web session over TLS 1.3 while ensuring we do not expose any // algorithms we don't want to support long-term. - switch (EVP_PKEY_id(public_key_.get())) { - case EVP_PKEY_RSA: + PublicKeyType key_type = PublicKeyTypeFromKey(public_key_.get()); + switch (key_type) { + case PublicKeyType::kRsa: return EVP_PKEY_bits(public_key_.get()) >= 2048; - case EVP_PKEY_EC: { - const EC_KEY* key = EVP_PKEY_get0_EC_KEY(public_key_.get()); - if (key == nullptr) { - return false; - } - const EC_GROUP* group = EC_KEY_get0_group(key); - if (group == nullptr) { - return false; - } - const int curve_nid = EC_GROUP_get_curve_name(group); - switch (curve_nid) { - case NID_X9_62_prime256v1: - case NID_secp384r1: - return true; - default: - return false; - } - } - case EVP_PKEY_ED25519: + case PublicKeyType::kP256: + case PublicKeyType::kP384: + case PublicKeyType::kEd25519: return true; default: return false; } } +bool CertificateView::VerifySignature(quiche::QuicheStringPiece data, + quiche::QuicheStringPiece signature, + uint16_t signature_algorithm) const { + if (PublicKeyTypeFromSignatureAlgorithm(signature_algorithm) != + PublicKeyTypeFromKey(public_key_.get())) { + QUIC_BUG << "Mismatch between the requested signature algorithm and the " + "type of the public key."; + return false; + } + + bssl::ScopedEVP_MD_CTX md_ctx; + EVP_PKEY_CTX* pctx; + if (!EVP_DigestVerifyInit( + md_ctx.get(), &pctx, + SSL_get_signature_algorithm_digest(signature_algorithm), nullptr, + public_key_.get())) { + return false; + } + if (SSL_is_signature_algorithm_rsa_pss(signature_algorithm)) { + if (!EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) || + !EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, -1)) { + return false; + } + } + return EVP_DigestVerify( + md_ctx.get(), reinterpret_cast<const uint8_t*>(signature.data()), + signature.size(), reinterpret_cast<const uint8_t*>(data.data()), + data.size()); +} + +std::unique_ptr<CertificatePrivateKey> CertificatePrivateKey::LoadFromDer( + quiche::QuicheStringPiece private_key) { + std::unique_ptr<CertificatePrivateKey> result(new CertificatePrivateKey()); + CBS private_key_cbs = StringPieceToCbs(private_key); + result->private_key_.reset(EVP_parse_private_key(&private_key_cbs)); + if (result->private_key_ == nullptr || CBS_len(&private_key_cbs) != 0) { + return nullptr; + } + return result; +} + +std::unique_ptr<CertificatePrivateKey> CertificatePrivateKey::LoadPemFromStream( + std::istream* input) { + PemReadResult result = ReadNextPemMessage(input); + if (result.status != PemReadResult::kOk) { + return nullptr; + } + // RFC 5958 OneAsymmetricKey message. + if (result.type == "PRIVATE KEY") { + return LoadFromDer(result.contents); + } + // Legacy OpenSSL format: PKCS#1 (RFC 8017) RSAPrivateKey message. + if (result.type == "RSA PRIVATE KEY") { + CBS private_key_cbs = StringPieceToCbs(result.contents); + bssl::UniquePtr<RSA> rsa(RSA_parse_private_key(&private_key_cbs)); + if (rsa == nullptr || CBS_len(&private_key_cbs) != 0) { + return nullptr; + } + + std::unique_ptr<CertificatePrivateKey> key(new CertificatePrivateKey()); + key->private_key_.reset(EVP_PKEY_new()); + EVP_PKEY_assign_RSA(key->private_key_.get(), rsa.release()); + return key; + } + // Unknown format. + return nullptr; +} + +std::string CertificatePrivateKey::Sign(quiche::QuicheStringPiece input, + uint16_t signature_algorithm) { + if (PublicKeyTypeFromSignatureAlgorithm(signature_algorithm) != + PublicKeyTypeFromKey(private_key_.get())) { + QUIC_BUG << "Mismatch between the requested signature algorithm and the " + "type of the private key."; + return ""; + } + + bssl::ScopedEVP_MD_CTX md_ctx; + EVP_PKEY_CTX* pctx; + if (!EVP_DigestSignInit( + md_ctx.get(), &pctx, + SSL_get_signature_algorithm_digest(signature_algorithm), + /*e=*/nullptr, private_key_.get())) { + return ""; + } + if (SSL_is_signature_algorithm_rsa_pss(signature_algorithm)) { + if (!EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) || + !EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, -1)) { + return ""; + } + } + + std::string output; + size_t output_size; + if (!EVP_DigestSign(md_ctx.get(), /*out_sig=*/nullptr, &output_size, + reinterpret_cast<const uint8_t*>(input.data()), + input.size())) { + return ""; + } + output.resize(output_size); + if (!EVP_DigestSign( + md_ctx.get(), reinterpret_cast<uint8_t*>(&output[0]), &output_size, + reinterpret_cast<const uint8_t*>(input.data()), input.size())) { + return ""; + } + output.resize(output_size); + return output; +} + +bool CertificatePrivateKey::MatchesPublicKey(const CertificateView& view) { + return EVP_PKEY_cmp(view.public_key(), private_key_.get()) == 1; +} + } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.h b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.h index 3569f4e0d87..286226d7e20 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.h @@ -5,8 +5,11 @@ #ifndef QUICHE_QUIC_CORE_CRYPTO_CERTIFICATE_VIEW_H_ #define QUICHE_QUIC_CORE_CRYPTO_CERTIFICATE_VIEW_H_ +#include <istream> #include <memory> +#include <vector> +#include "third_party/boringssl/src/include/openssl/base.h" #include "third_party/boringssl/src/include/openssl/bytestring.h" #include "third_party/boringssl/src/include/openssl/evp.h" #include "net/third_party/quiche/src/quic/core/crypto/boring_utils.h" @@ -16,6 +19,18 @@ namespace quic { +struct QUIC_EXPORT_PRIVATE PemReadResult { + enum Status { kOk, kEof, kError }; + Status status; + std::string contents; + // The type of the PEM message (e.g., if the message starts with + // "-----BEGIN CERTIFICATE-----", the |type| would be "CERTIFICATE"). + std::string type; +}; + +// Reads |input| line-by-line and returns the next available PEM message. +QUIC_EXPORT_PRIVATE PemReadResult ReadNextPemMessage(std::istream* input); + // CertificateView represents a parsed version of a single X.509 certificate. As // the word "view" implies, it does not take ownership of the underlying strings // and consists primarily of pointers into the certificate that is passed into @@ -27,7 +42,11 @@ class QUIC_EXPORT_PRIVATE CertificateView { static std::unique_ptr<CertificateView> ParseSingleCertificate( quiche::QuicheStringPiece certificate); - EVP_PKEY* public_key() { return public_key_.get(); } + // Loads all PEM-encoded X.509 certificates found in the |input| stream + // without parsing them. Returns an empty vector if any parsing error occurs. + static std::vector<std::string> LoadPemFromStream(std::istream* input); + + const EVP_PKEY* public_key() const { return public_key_.get(); } const std::vector<quiche::QuicheStringPiece>& subject_alt_name_domains() const { @@ -37,6 +56,11 @@ class QUIC_EXPORT_PRIVATE CertificateView { return subject_alt_name_ips_; } + // |signature_algorithm| is a TLS signature algorithm ID. + bool VerifySignature(quiche::QuicheStringPiece data, + quiche::QuicheStringPiece signature, + uint16_t signature_algorithm) const; + private: CertificateView() = default; @@ -52,6 +76,33 @@ class QUIC_EXPORT_PRIVATE CertificateView { bool ValidatePublicKeyParameters(); }; +// CertificatePrivateKey represents a private key that can be used with an X.509 +// certificate. +class QUIC_EXPORT_PRIVATE CertificatePrivateKey { + public: + // Loads a DER-encoded PrivateKeyInfo structure (RFC 5958) as a private key. + static std::unique_ptr<CertificatePrivateKey> LoadFromDer( + quiche::QuicheStringPiece private_key); + + // Loads a private key from a PEM file formatted according to RFC 7468. Also + // supports legacy OpenSSL RSA key format ("BEGIN RSA PRIVATE KEY"). + static std::unique_ptr<CertificatePrivateKey> LoadPemFromStream( + std::istream* input); + + // |signature_algorithm| is a TLS signature algorithm ID. + std::string Sign(quiche::QuicheStringPiece input, + uint16_t signature_algorithm); + + // Verifies that the private key in question matches the public key of the + // certificate |view|. + bool MatchesPublicKey(const CertificateView& view); + + private: + CertificatePrivateKey() = default; + + bssl::UniquePtr<EVP_PKEY> private_key_; +}; + } // namespace quic #endif // QUICHE_QUIC_CORE_CRYPTO_CERTIFICATE_VIEW_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_der_fuzzer.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_der_fuzzer.cc new file mode 100644 index 00000000000..e2de1ba7efe --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_der_fuzzer.cc @@ -0,0 +1,15 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <string> + +#include "net/third_party/quiche/src/quic/core/crypto/certificate_view.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + std::string input(reinterpret_cast<const char*>(data), size); + + quic::CertificateView::ParseSingleCertificate(input); + quic::CertificatePrivateKey::LoadFromDer(input); + return 0; +} diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_pem_fuzzer.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_pem_fuzzer.cc new file mode 100644 index 00000000000..e1efd988bb9 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_pem_fuzzer.cc @@ -0,0 +1,18 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <sstream> +#include <string> + +#include "net/third_party/quiche/src/quic/core/crypto/certificate_view.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + std::string input(reinterpret_cast<const char*>(data), size); + std::stringstream stream(input); + + quic::CertificateView::LoadPemFromStream(&stream); + stream.seekg(0); + quic::CertificatePrivateKey::LoadPemFromStream(&stream); + return 0; +} diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_test.cc index 6be0e4ae7a6..b0b52f14f3b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_test.cc @@ -4,131 +4,38 @@ #include "net/third_party/quiche/src/quic/core/crypto/certificate_view.h" +#include <memory> +#include <sstream> + #include "third_party/boringssl/src/include/openssl/base.h" #include "third_party/boringssl/src/include/openssl/evp.h" +#include "third_party/boringssl/src/include/openssl/ssl.h" #include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/test_certificates.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" namespace quic { +namespace test { namespace { using testing::ElementsAre; +using testing::HasSubstr; + +TEST(CertificateViewTest, PemParser) { + std::stringstream stream(kTestCertificatePem); + PemReadResult result = ReadNextPemMessage(&stream); + EXPECT_EQ(result.status, PemReadResult::kOk); + EXPECT_EQ(result.type, "CERTIFICATE"); + EXPECT_EQ(result.contents, kTestCertificate); -// A test certificate generated by //net/tools/quic/certs/generate-certs.sh. -constexpr char kTestCertificate[] = { - '\x30', '\x82', '\x03', '\xb4', '\x30', '\x82', '\x02', '\x9c', '\xa0', - '\x03', '\x02', '\x01', '\x02', '\x02', '\x01', '\x01', '\x30', '\x0d', - '\x06', '\x09', '\x2a', '\x86', '\x48', '\x86', '\xf7', '\x0d', '\x01', - '\x01', '\x0b', '\x05', '\x00', '\x30', '\x1e', '\x31', '\x1c', '\x30', - '\x1a', '\x06', '\x03', '\x55', '\x04', '\x03', '\x0c', '\x13', '\x51', - '\x55', '\x49', '\x43', '\x20', '\x53', '\x65', '\x72', '\x76', '\x65', - '\x72', '\x20', '\x52', '\x6f', '\x6f', '\x74', '\x20', '\x43', '\x41', - '\x30', '\x1e', '\x17', '\x0d', '\x32', '\x30', '\x30', '\x31', '\x33', - '\x30', '\x31', '\x38', '\x31', '\x33', '\x35', '\x39', '\x5a', '\x17', - '\x0d', '\x32', '\x30', '\x30', '\x32', '\x30', '\x32', '\x31', '\x38', - '\x31', '\x33', '\x35', '\x39', '\x5a', '\x30', '\x64', '\x31', '\x0b', - '\x30', '\x09', '\x06', '\x03', '\x55', '\x04', '\x06', '\x13', '\x02', - '\x55', '\x53', '\x31', '\x13', '\x30', '\x11', '\x06', '\x03', '\x55', - '\x04', '\x08', '\x0c', '\x0a', '\x43', '\x61', '\x6c', '\x69', '\x66', - '\x6f', '\x72', '\x6e', '\x69', '\x61', '\x31', '\x16', '\x30', '\x14', - '\x06', '\x03', '\x55', '\x04', '\x07', '\x0c', '\x0d', '\x4d', '\x6f', - '\x75', '\x6e', '\x74', '\x61', '\x69', '\x6e', '\x20', '\x56', '\x69', - '\x65', '\x77', '\x31', '\x14', '\x30', '\x12', '\x06', '\x03', '\x55', - '\x04', '\x0a', '\x0c', '\x0b', '\x51', '\x55', '\x49', '\x43', '\x20', - '\x53', '\x65', '\x72', '\x76', '\x65', '\x72', '\x31', '\x12', '\x30', - '\x10', '\x06', '\x03', '\x55', '\x04', '\x03', '\x0c', '\x09', '\x31', - '\x32', '\x37', '\x2e', '\x30', '\x2e', '\x30', '\x2e', '\x31', '\x30', - '\x82', '\x01', '\x22', '\x30', '\x0d', '\x06', '\x09', '\x2a', '\x86', - '\x48', '\x86', '\xf7', '\x0d', '\x01', '\x01', '\x01', '\x05', '\x00', - '\x03', '\x82', '\x01', '\x0f', '\x00', '\x30', '\x82', '\x01', '\x0a', - '\x02', '\x82', '\x01', '\x01', '\x00', '\xc5', '\xe2', '\x51', '\x6d', - '\x3f', '\xd6', '\x28', '\xf2', '\xad', '\x34', '\x73', '\x87', '\x64', - '\xca', '\x33', '\x19', '\x33', '\xb7', '\x75', '\x91', '\xab', '\x31', - '\x19', '\x2b', '\xe3', '\xa4', '\x26', '\x09', '\x29', '\x8b', '\x2d', - '\xf7', '\x52', '\x75', '\xa7', '\x55', '\x15', '\xf0', '\x11', '\xc7', - '\xc2', '\xc4', '\xed', '\x18', '\x1b', '\x33', '\x0b', '\x71', '\x32', - '\xe6', '\x35', '\x89', '\xcd', '\x2d', '\x5a', '\x05', '\x57', '\x4e', - '\xc2', '\x78', '\x75', '\x65', '\x72', '\x2d', '\x8a', '\x17', '\x83', - '\xd6', '\x32', '\x90', '\x85', '\xf8', '\x22', '\xe2', '\x65', '\xa9', - '\xe0', '\xa0', '\xfe', '\x19', '\xb2', '\x39', '\x2d', '\x14', '\x03', - '\x10', '\x2f', '\xcc', '\x8b', '\x5e', '\xaa', '\x25', '\x27', '\x0d', - '\xa3', '\x37', '\x10', '\x0c', '\x17', '\xec', '\xf0', '\x8b', '\xc5', - '\x6b', '\xed', '\x6b', '\x5e', '\xb2', '\xe2', '\x35', '\x3e', '\x46', - '\x3b', '\xf7', '\xf6', '\x59', '\xb1', '\xe0', '\x16', '\xa6', '\xfb', - '\x03', '\xbf', '\x84', '\x4f', '\xce', '\x64', '\x15', '\x0d', '\x59', - '\x99', '\xa6', '\xf0', '\x7f', '\x8a', '\x33', '\x4b', '\xbb', '\x0b', - '\xb8', '\xf2', '\xd1', '\x27', '\x90', '\x8f', '\x38', '\xf8', '\x5a', - '\x41', '\x82', '\x07', '\x9b', '\x0d', '\xd9', '\x52', '\xe0', '\x70', - '\xff', '\xde', '\xda', '\xd8', '\x25', '\x4e', '\x2f', '\x2d', '\x9f', - '\xaf', '\x92', '\x63', '\xc7', '\x42', '\xb4', '\xdc', '\x16', '\x95', - '\x23', '\x05', '\x02', '\x6b', '\xb0', '\xe8', '\xc5', '\xfe', '\x15', - '\x9a', '\xe8', '\x7d', '\x2f', '\xdc', '\x43', '\xf4', '\x70', '\x91', - '\x1a', '\x93', '\xbe', '\x71', '\xaf', '\x85', '\x84', '\xdb', '\xcf', - '\x6b', '\x5c', '\x80', '\xb2', '\xd3', '\xf3', '\x42', '\x6e', '\x24', - '\xec', '\x2a', '\x62', '\x99', '\xc6', '\x3c', '\xe5', '\x32', '\xe5', - '\x72', '\x37', '\x30', '\x9b', '\x0b', '\xe4', '\x06', '\xb4', '\x64', - '\x26', '\x95', '\x59', '\xba', '\xf1', '\x53', '\x83', '\x3d', '\x99', - '\x6d', '\xf0', '\x80', '\xe2', '\xdb', '\x6b', '\x34', '\x52', '\x06', - '\x77', '\x3c', '\x73', '\xbe', '\xc6', '\xe3', '\xce', '\xb2', '\x11', - '\x02', '\x03', '\x01', '\x00', '\x01', '\xa3', '\x81', '\xb6', '\x30', - '\x81', '\xb3', '\x30', '\x0c', '\x06', '\x03', '\x55', '\x1d', '\x13', - '\x01', '\x01', '\xff', '\x04', '\x02', '\x30', '\x00', '\x30', '\x1d', - '\x06', '\x03', '\x55', '\x1d', '\x0e', '\x04', '\x16', '\x04', '\x14', - '\xc8', '\x54', '\x28', '\xf6', '\xd2', '\xd5', '\x12', '\x35', '\x89', - '\x15', '\x75', '\xb8', '\xbf', '\xdd', '\xfb', '\x4a', '\xfc', '\x6c', - '\x89', '\xde', '\x30', '\x1f', '\x06', '\x03', '\x55', '\x1d', '\x23', - '\x04', '\x18', '\x30', '\x16', '\x80', '\x14', '\x50', '\xe4', '\x1d', - '\xc3', '\x1a', '\xfb', '\xfd', '\x38', '\xdd', '\xa2', '\x05', '\xfd', - '\xc8', '\xfa', '\x57', '\x0a', '\xc1', '\x06', '\x0f', '\xae', '\x30', - '\x1d', '\x06', '\x03', '\x55', '\x1d', '\x25', '\x04', '\x16', '\x30', - '\x14', '\x06', '\x08', '\x2b', '\x06', '\x01', '\x05', '\x05', '\x07', - '\x03', '\x01', '\x06', '\x08', '\x2b', '\x06', '\x01', '\x05', '\x05', - '\x07', '\x03', '\x02', '\x30', '\x44', '\x06', '\x03', '\x55', '\x1d', - '\x11', '\x04', '\x3d', '\x30', '\x3b', '\x82', '\x0f', '\x77', '\x77', - '\x77', '\x2e', '\x65', '\x78', '\x61', '\x6d', '\x70', '\x6c', '\x65', - '\x2e', '\x6f', '\x72', '\x67', '\x82', '\x10', '\x6d', '\x61', '\x69', - '\x6c', '\x2e', '\x65', '\x78', '\x61', '\x6d', '\x70', '\x6c', '\x65', - '\x2e', '\x6f', '\x72', '\x67', '\x82', '\x10', '\x6d', '\x61', '\x69', - '\x6c', '\x2e', '\x65', '\x78', '\x61', '\x6d', '\x70', '\x6c', '\x65', - '\x2e', '\x63', '\x6f', '\x6d', '\x87', '\x04', '\x7f', '\x00', '\x00', - '\x01', '\x30', '\x0d', '\x06', '\x09', '\x2a', '\x86', '\x48', '\x86', - '\xf7', '\x0d', '\x01', '\x01', '\x0b', '\x05', '\x00', '\x03', '\x82', - '\x01', '\x01', '\x00', '\x45', '\x41', '\x7a', '\x68', '\xe0', '\xa7', - '\x59', '\xa1', '\x62', '\x54', '\x73', '\x74', '\x14', '\x4f', '\xde', - '\x9c', '\x51', '\xac', '\x25', '\x97', '\x70', '\xf7', '\x09', '\x51', - '\x39', '\x72', '\x39', '\x3c', '\xd0', '\x31', '\xe1', '\xc3', '\x02', - '\x91', '\x14', '\x4d', '\x8f', '\x1d', '\x31', '\xab', '\x98', '\x7e', - '\xe6', '\xbb', '\xab', '\x6a', '\xd9', '\xc5', '\x86', '\xaa', '\x4e', - '\x6a', '\x48', '\xe9', '\xf8', '\xd7', '\xb3', '\x1d', '\xa0', '\xc5', - '\xe6', '\xbf', '\x4c', '\x5a', '\x9b', '\xb5', '\x78', '\x01', '\xa3', - '\x39', '\x7b', '\x5f', '\xbc', '\xb8', '\xa7', '\xc2', '\x71', '\xb0', - '\x7b', '\xdd', '\xa1', '\x87', '\xa6', '\x54', '\x9c', '\xf6', '\x59', - '\x81', '\xb1', '\x2c', '\xde', '\xc5', '\x8a', '\xa2', '\x06', '\x89', - '\xb5', '\xc1', '\x7a', '\xbe', '\x0c', '\x9f', '\x3d', '\xde', '\x81', - '\x48', '\x53', '\x71', '\x7b', '\x8d', '\xc7', '\xea', '\x87', '\xd7', - '\xd1', '\xda', '\x94', '\xb4', '\xc5', '\xac', '\x1e', '\x83', '\xa3', - '\x42', '\x7d', '\xe6', '\xab', '\x3f', '\xd6', '\x1c', '\xd6', '\x65', - '\xc3', '\x60', '\xe9', '\x76', '\x54', '\x79', '\x3f', '\xeb', '\x65', - '\x85', '\x4f', '\x60', '\x7d', '\xbb', '\x96', '\x03', '\x54', '\x2e', - '\xd0', '\x1b', '\xe2', '\x6c', '\x2d', '\x91', '\xae', '\x33', '\x9c', - '\x04', '\xc4', '\x44', '\x0a', '\x7d', '\x5f', '\xbb', '\x80', '\xa2', - '\x01', '\xbc', '\x90', '\x81', '\xa5', '\xdc', '\x4a', '\xc8', '\x77', - '\xc9', '\x8d', '\x34', '\x17', '\xe6', '\x2a', '\x7d', '\x02', '\x1e', - '\x32', '\x3f', '\x7d', '\xd7', '\x0c', '\x80', '\x5b', '\xc6', '\x94', - '\x6a', '\x42', '\x36', '\x05', '\x9f', '\x9e', '\xc5', '\x85', '\x9f', - '\x60', '\xe3', '\x72', '\x73', '\x34', '\x39', '\x44', '\x75', '\x55', - '\x60', '\x24', '\x7a', '\x8b', '\x09', '\x74', '\x84', '\x72', '\xfd', - '\x91', '\x68', '\x93', '\x57', '\x9e', '\x70', '\x46', '\x4d', '\xe4', - '\x30', '\x84', '\x5f', '\x20', '\x07', '\xad', '\xfd', '\x86', '\x32', - '\xd3', '\xfb', '\xba', '\xaf', '\xd9', '\x61', '\x14', '\x3c', '\xe0', - '\xa1', '\xa9', '\x51', '\x51', '\x0f', '\xad', '\x60'}; + result = ReadNextPemMessage(&stream); + EXPECT_EQ(result.status, PemReadResult::kEof); +} TEST(CertificateViewTest, Parse) { - quiche::QuicheStringPiece certificate(kTestCertificate, - sizeof(kTestCertificate)); std::unique_ptr<CertificateView> view = - CertificateView::ParseSingleCertificate(certificate); + CertificateView::ParseSingleCertificate(kTestCertificate); ASSERT_TRUE(view != nullptr); EXPECT_THAT(view->subject_alt_name_domains(), @@ -140,5 +47,68 @@ TEST(CertificateViewTest, Parse) { EXPECT_EQ(EVP_PKEY_id(view->public_key()), EVP_PKEY_RSA); } +TEST(CertificateViewTest, PemSingleCertificate) { + std::stringstream pem_stream(kTestCertificatePem); + std::vector<std::string> chain = + CertificateView::LoadPemFromStream(&pem_stream); + EXPECT_THAT(chain, ElementsAre(kTestCertificate)); +} + +TEST(CertificateViewTest, PemMultipleCertificates) { + std::stringstream pem_stream(kTestCertificateChainPem); + std::vector<std::string> chain = + CertificateView::LoadPemFromStream(&pem_stream); + EXPECT_THAT(chain, + ElementsAre(kTestCertificate, HasSubstr("QUIC Server Root CA"))); +} + +TEST(CertificateViewTest, PemNoCertificates) { + std::stringstream pem_stream("one\ntwo\nthree\n"); + std::vector<std::string> chain = + CertificateView::LoadPemFromStream(&pem_stream); + EXPECT_TRUE(chain.empty()); +} + +TEST(CertificateViewTest, SignAndVerify) { + std::unique_ptr<CertificatePrivateKey> key = + CertificatePrivateKey::LoadFromDer(kTestCertificatePrivateKey); + ASSERT_TRUE(key != nullptr); + + std::string data = "A really important message"; + std::string signature = key->Sign(data, SSL_SIGN_RSA_PSS_RSAE_SHA256); + ASSERT_FALSE(signature.empty()); + + std::unique_ptr<CertificateView> view = + CertificateView::ParseSingleCertificate(kTestCertificate); + ASSERT_TRUE(view != nullptr); + EXPECT_TRUE(key->MatchesPublicKey(*view)); + + EXPECT_TRUE( + view->VerifySignature(data, signature, SSL_SIGN_RSA_PSS_RSAE_SHA256)); + EXPECT_FALSE(view->VerifySignature("An unimportant message", signature, + SSL_SIGN_RSA_PSS_RSAE_SHA256)); + EXPECT_FALSE(view->VerifySignature(data, "Not a signature", + SSL_SIGN_RSA_PSS_RSAE_SHA256)); +} + +TEST(CertificateViewTest, PrivateKeyPem) { + std::unique_ptr<CertificateView> view = + CertificateView::ParseSingleCertificate(kTestCertificate); + ASSERT_TRUE(view != nullptr); + + std::stringstream pem_stream(kTestCertificatePrivateKeyPem); + std::unique_ptr<CertificatePrivateKey> pem_key = + CertificatePrivateKey::LoadPemFromStream(&pem_stream); + ASSERT_TRUE(pem_key != nullptr); + EXPECT_TRUE(pem_key->MatchesPublicKey(*view)); + + std::stringstream legacy_stream(kTestCertificatePrivateKeyLegacyPem); + std::unique_ptr<CertificatePrivateKey> legacy_key = + CertificatePrivateKey::LoadPemFromStream(&legacy_stream); + ASSERT_TRUE(legacy_key != nullptr); + EXPECT_TRUE(legacy_key->MatchesPublicKey(*view)); +} + } // namespace +} // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.cc index d5b4635d1d4..2c92923b35b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.cc @@ -50,6 +50,17 @@ CryptoHandshakeMessage& CryptoHandshakeMessage::operator=( CryptoHandshakeMessage& CryptoHandshakeMessage::operator=( CryptoHandshakeMessage&& other) = default; +bool CryptoHandshakeMessage::operator==( + const CryptoHandshakeMessage& rhs) const { + return tag_ == rhs.tag_ && tag_value_map_ == rhs.tag_value_map_ && + minimum_size_ == rhs.minimum_size_; +} + +bool CryptoHandshakeMessage::operator!=( + const CryptoHandshakeMessage& rhs) const { + return !(*this == rhs); +} + void CryptoHandshakeMessage::Clear() { tag_ = 0; tag_value_map_.clear(); @@ -279,7 +290,6 @@ std::string CryptoHandshakeMessage::DebugStringInternal(size_t indent) const { case kIRTT: case kMIUS: case kMIBS: - case kSCLS: case kTCID: case kMAD: // uint32_t value diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h index 409738a1f81..95390507a6a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h @@ -30,6 +30,9 @@ class QUIC_EXPORT_PRIVATE CryptoHandshakeMessage { CryptoHandshakeMessage& operator=(const CryptoHandshakeMessage& other); CryptoHandshakeMessage& operator=(CryptoHandshakeMessage&& other); + bool operator==(const CryptoHandshakeMessage& rhs) const; + bool operator!=(const CryptoHandshakeMessage& rhs) const; + // Clears state. void Clear(); diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h index 8af8a0429d1..172fd822d0b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h @@ -27,7 +27,7 @@ namespace quic { typedef std::string ServerConfigID; // The following tags have been deprecated and should not be reused: -// "1CON", "BBQ4", "NCON", "RCID", "SREJ", "TBKP", "TB10" +// "1CON", "BBQ4", "NCON", "RCID", "SREJ", "TBKP", "TB10", "SCLS", "SMHL" // clang-format off const QuicTag kCHLO = TAG('C', 'H', 'L', 'O'); // Client hello @@ -121,6 +121,10 @@ const QuicTag kB2NA = TAG('B', '2', 'N', 'A'); // For BBRv2, do not add ack // height to queueing threshold const QuicTag kB2RP = TAG('B', '2', 'R', 'P'); // For BBRv2, run PROBE_RTT on // the regular schedule +const QuicTag kB2CL = TAG('B', '2', 'C', 'L'); // For BBRv2, allow PROBE_BW + // cwnd to be below BDP + ack + // height. +const QuicTag kB2LO = TAG('B', '2', 'L', 'O'); // Ignore inflight_lo in BBR2 const QuicTag kBSAO = TAG('B', 'S', 'A', 'O'); // Avoid Overestimation in // Bandwidth Sampler with ack // aggregation @@ -184,10 +188,6 @@ const QuicTag kILD4 = TAG('I', 'L', 'D', '4'); // IETF style loss detection // threshold const QuicTag kRUNT = TAG('R', 'U', 'N', 'T'); // No packet threshold loss // detection for "runt" packet. -// TODO(fayang): Remove this connection option when QUIC_VERSION_35, is removed -// Since MAX_HEADER_LIST_SIZE settings frame is supported instead. -const QuicTag kSMHL = TAG('S', 'M', 'H', 'L'); // Support MAX_HEADER_LIST_SIZE - // settings frame. const QuicTag kNSTP = TAG('N', 'S', 'T', 'P'); // No stop waiting frames. const QuicTag kNRTT = TAG('N', 'R', 'T', 'T'); // Ignore initial RTT @@ -226,6 +226,8 @@ const QuicTag kPLE2 = TAG('P', 'L', 'E', '2'); // Arm the 1st PTO with // and at least 1.5*srtt from // last sent packet. +const QuicTag kELDT = TAG('E', 'L', 'D', 'T'); // Enable Loss Detection Tuning + // Optional support of truncated Connection IDs. If sent by a peer, the value // is the minimum number of bytes allowed for the connection ID sent to the // peer. @@ -251,6 +253,17 @@ const QuicTag kBWS5 = TAG('B', 'W', 'S', '5'); // QUIC Initial CWND up and down const QuicTag kBWS6 = TAG('B', 'W', 'S', '6'); // QUIC Initial CWND - Enabled // with 0.5 * default // multiplier. +const QuicTag kBWP0 = TAG('B', 'W', 'P', '0'); // QUIC Initial CWND - SPDY + // priority 0. +const QuicTag kBWP1 = TAG('B', 'W', 'P', '1'); // QUIC Initial CWND - SPDY + // priorities 0 and 1. +const QuicTag kBWP2 = TAG('B', 'W', 'P', '2'); // QUIC Initial CWND - SPDY + // priorities 0, 1 and 2. +const QuicTag kBWP3 = TAG('B', 'W', 'P', '3'); // QUIC Initial CWND - SPDY + // priorities 0, 1, 2 and 3. +const QuicTag kBWP4 = TAG('B', 'W', 'P', '4'); // QUIC Initial CWND - SPDY + // priorities >= 0, 1, 2 , 3 and + // 4. const QuicTag kBWS7 = TAG('B', 'W', 'S', '7'); // QUIC Initial CWND - Enabled // with 0.75 * default // multiplier. @@ -294,7 +307,6 @@ const QuicTag kAEAD = TAG('A', 'E', 'A', 'D'); // Authenticated const QuicTag kCOPT = TAG('C', 'O', 'P', 'T'); // Connection options const QuicTag kCLOP = TAG('C', 'L', 'O', 'P'); // Client connection options const QuicTag kICSL = TAG('I', 'C', 'S', 'L'); // Idle network timeout -const QuicTag kSCLS = TAG('S', 'C', 'L', 'S'); // Silently close on timeout const QuicTag kMIBS = TAG('M', 'I', 'D', 'S'); // Max incoming bidi streams const QuicTag kMIUS = TAG('M', 'I', 'U', 'S'); // Max incoming unidi streams const QuicTag kADE = TAG('A', 'D', 'E', 0); // Ack Delay Exponent (IETF diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc index 4cf618b8a6a..ee9dc53cf64 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc @@ -223,7 +223,7 @@ class CryptoServerTest : public QuicTestWithParam<TestParams> { bool called = false; QuicSocketAddress server_address(QuicIpAddress::Any4(), 5); config_.ValidateClientHello( - message, client_address_.host(), server_address, + message, client_address_, server_address, supported_versions_.front().transport_version, &clock_, signed_config_, std::make_unique<ValidateCallback>(this, true, "", &called)); EXPECT_TRUE(called); @@ -241,7 +241,7 @@ class CryptoServerTest : public QuicTestWithParam<TestParams> { bool* called) { QuicSocketAddress server_address(QuicIpAddress::Any4(), 5); config_.ValidateClientHello( - message, client_address_.host(), server_address, + message, client_address_, server_address, supported_versions_.front().transport_version, &clock_, signed_config_, std::make_unique<ValidateCallback>(this, false, error_substr, called)); } diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/curve25519_key_exchange.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/curve25519_key_exchange.cc index f4cc7937d7b..2f19e9d486c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/curve25519_key_exchange.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/curve25519_key_exchange.cc @@ -5,6 +5,7 @@ #include "net/third_party/quiche/src/quic/core/crypto/curve25519_key_exchange.h" #include <cstdint> +#include <cstring> #include <string> #include "third_party/boringssl/src/include/openssl/curve25519.h" diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/p256_key_exchange.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/p256_key_exchange.cc index a1b45ba5f9c..01f345de824 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/p256_key_exchange.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/p256_key_exchange.cc @@ -5,6 +5,7 @@ #include "net/third_party/quiche/src/quic/core/crypto/p256_key_exchange.h" #include <cstdint> +#include <cstring> #include <memory> #include <string> #include <utility> diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.h b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.h index e208b94c26c..c4224f46607 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.h @@ -119,6 +119,7 @@ class QUIC_EXPORT_PRIVATE ProofSource { // // Callers should expect that |callback| might be invoked synchronously. virtual void GetProof(const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, const std::string& hostname, const std::string& server_config, QuicTransportVersion transport_version, @@ -128,6 +129,7 @@ class QUIC_EXPORT_PRIVATE ProofSource { // Returns the certificate chain for |hostname| in leaf-first order. virtual QuicReferenceCountedPointer<Chain> GetCertChain( const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, const std::string& hostname) = 0; // Computes a signature using the private key of the certificate for @@ -140,10 +142,59 @@ class QUIC_EXPORT_PRIVATE ProofSource { // Callers should expect that |callback| might be invoked synchronously. virtual void ComputeTlsSignature( const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, const std::string& hostname, uint16_t signature_algorithm, quiche::QuicheStringPiece in, std::unique_ptr<SignatureCallback> callback) = 0; + + class QUIC_EXPORT_PRIVATE DecryptCallback { + public: + DecryptCallback() = default; + virtual ~DecryptCallback() = default; + + virtual void Run(std::vector<uint8_t> plaintext) = 0; + + private: + DecryptCallback(const Callback&) = delete; + DecryptCallback& operator=(const Callback&) = delete; + }; + + // TicketCrypter is an interface for managing encryption and decryption of TLS + // session tickets. A TicketCrypter gets used as an + // SSL_CTX_set_ticket_aead_method in BoringSSL, which has a synchronous + // Encrypt/Seal operation and a potentially asynchronous Decrypt/Open + // operation. This interface allows for ticket decryptions to be performed on + // a remote service. + class QUIC_EXPORT_PRIVATE TicketCrypter { + public: + TicketCrypter() = default; + virtual ~TicketCrypter() = default; + + // MaxOverhead returns the maximum number of bytes of overhead that may get + // added when encrypting the ticket. + virtual size_t MaxOverhead() = 0; + + // Encrypt takes a serialized TLS session ticket in |in|, encrypts it, and + // returns the encrypted ticket. The resulting value must not be larger than + // MaxOverhead bytes larger than |in|. If encryption fails, this method + // returns an empty vector. + virtual std::vector<uint8_t> Encrypt(quiche::QuicheStringPiece in) = 0; + + // Decrypt takes an encrypted ticket |in|, decrypts it, and calls + // |callback->Run| with the decrypted ticket, which must not be larger than + // |in|. If decryption fails, the callback is invoked with an empty + // vector. + virtual void Decrypt(quiche::QuicheStringPiece in, + std::unique_ptr<DecryptCallback> callback) = 0; + }; + + // Returns the TicketCrypter used for encrypting and decrypting TLS + // session tickets, or nullptr if that functionality is not supported. The + // TicketCrypter returned (if not nullptr) must be valid for the lifetime of + // the ProofSource, and the caller does not take ownership of said + // TicketCrypter. + virtual TicketCrypter* GetTicketCrypter() = 0; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509.cc new file mode 100644 index 00000000000..6afc65f557a --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509.cc @@ -0,0 +1,135 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/core/crypto/proof_source_x509.h" + +#include <memory> + +#include "third_party/boringssl/src/include/openssl/ssl.h" +#include "net/third_party/quiche/src/quic/core/crypto/certificate_view.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/core/quic_data_writer.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" + +namespace quic { + +std::unique_ptr<ProofSourceX509> ProofSourceX509::Create( + QuicReferenceCountedPointer<Chain> default_chain, + CertificatePrivateKey default_key) { + std::unique_ptr<ProofSourceX509> result(new ProofSourceX509()); + if (!result->AddCertificateChain(default_chain, std::move(default_key))) { + return nullptr; + } + result->default_certificate_ = &result->certificates_.front(); + return result; +} + +void ProofSourceX509::GetProof( + const QuicSocketAddress& /*server_address*/, + const QuicSocketAddress& /*client_address*/, + const std::string& hostname, + const std::string& server_config, + QuicTransportVersion /*transport_version*/, + quiche::QuicheStringPiece chlo_hash, + std::unique_ptr<ProofSource::Callback> callback) { + QuicCryptoProof proof; + + size_t payload_size = sizeof(kProofSignatureLabel) + sizeof(uint32_t) + + chlo_hash.size() + server_config.size(); + auto payload = std::make_unique<char[]>(payload_size); + QuicDataWriter payload_writer(payload_size, payload.get(), + quiche::Endianness::HOST_BYTE_ORDER); + bool success = payload_writer.WriteBytes(kProofSignatureLabel, + sizeof(kProofSignatureLabel)) && + payload_writer.WriteUInt32(chlo_hash.size()) && + payload_writer.WriteStringPiece(chlo_hash) && + payload_writer.WriteStringPiece(server_config); + if (!success) { + callback->Run(/*ok=*/false, nullptr, proof, nullptr); + return; + } + + Certificate* certificate = GetCertificate(hostname); + proof.signature = certificate->key.Sign( + quiche::QuicheStringPiece(payload.get(), payload_size), + SSL_SIGN_RSA_PSS_RSAE_SHA256); + callback->Run(/*ok=*/!proof.signature.empty(), certificate->chain, proof, + nullptr); +} + +QuicReferenceCountedPointer<ProofSource::Chain> ProofSourceX509::GetCertChain( + const QuicSocketAddress& /*server_address*/, + const QuicSocketAddress& /*client_address*/, + const std::string& hostname) { + return GetCertificate(hostname)->chain; +} + +void ProofSourceX509::ComputeTlsSignature( + const QuicSocketAddress& /*server_address*/, + const QuicSocketAddress& /*client_address*/, + const std::string& hostname, + uint16_t signature_algorithm, + quiche::QuicheStringPiece in, + std::unique_ptr<ProofSource::SignatureCallback> callback) { + std::string signature = + GetCertificate(hostname)->key.Sign(in, signature_algorithm); + callback->Run(/*ok=*/!signature.empty(), signature, nullptr); +} + +ProofSource::TicketCrypter* ProofSourceX509::GetTicketCrypter() { + return nullptr; +} + +bool ProofSourceX509::AddCertificateChain( + QuicReferenceCountedPointer<Chain> chain, + CertificatePrivateKey key) { + if (chain->certs.empty()) { + QUIC_BUG << "Empty certificate chain supplied."; + return false; + } + + std::unique_ptr<CertificateView> leaf = + CertificateView::ParseSingleCertificate(chain->certs[0]); + if (leaf == nullptr) { + QUIC_BUG << "Unable to parse X.509 leaf certificate in the supplied chain."; + return false; + } + if (!key.MatchesPublicKey(*leaf)) { + QUIC_BUG << "Private key does not match the leaf certificate."; + return false; + } + + certificates_.push_front(Certificate{ + .chain = chain, + .key = std::move(key), + }); + Certificate* certificate = &certificates_.front(); + + for (quiche::QuicheStringPiece host : leaf->subject_alt_name_domains()) { + certificate_map_[std::string(host)] = certificate; + } + return true; +} + +ProofSourceX509::Certificate* ProofSourceX509::GetCertificate( + const std::string& hostname) const { + auto it = certificate_map_.find(hostname); + if (it != certificate_map_.end()) { + return it->second; + } + auto dot_pos = hostname.find('.'); + if (dot_pos != std::string::npos) { + std::string wildcard = quiche::QuicheStrCat("*", hostname.substr(dot_pos)); + it = certificate_map_.find(wildcard); + if (it != certificate_map_.end()) { + return it->second; + } + } + return default_certificate_; +} + +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509.h b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509.h new file mode 100644 index 00000000000..8632d4bfe95 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509.h @@ -0,0 +1,76 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_PROOF_SOURCE_X509_H_ +#define QUICHE_QUIC_CORE_CRYPTO_PROOF_SOURCE_X509_H_ + +#include <forward_list> +#include <memory> + +#include "net/third_party/quiche/src/quic/core/crypto/certificate_view.h" +#include "net/third_party/quiche/src/quic/core/crypto/proof_source.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_macros.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" + +namespace quic { + +// ProofSourceX509 accepts X.509 certificates with private keys and picks a +// certificate internally based on its SubjectAltName value. +class QUIC_EXPORT_PRIVATE ProofSourceX509 : public ProofSource { + public: + // Creates a proof source that uses |default_chain| when no SubjectAltName + // value matches. Returns nullptr if |default_chain| is invalid. + static std::unique_ptr<ProofSourceX509> Create( + QuicReferenceCountedPointer<Chain> default_chain, + CertificatePrivateKey default_key); + + // ProofSource implementation. + void GetProof(const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, + const std::string& hostname, + const std::string& server_config, + QuicTransportVersion transport_version, + quiche::QuicheStringPiece chlo_hash, + std::unique_ptr<Callback> callback) override; + QuicReferenceCountedPointer<Chain> GetCertChain( + const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, + const std::string& hostname) override; + void ComputeTlsSignature( + const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, + const std::string& hostname, + uint16_t signature_algorithm, + quiche::QuicheStringPiece in, + std::unique_ptr<SignatureCallback> callback) override; + TicketCrypter* GetTicketCrypter() override; + + // Adds a certificate chain to the verifier. Returns false if the chain is + // not valid. Newer certificates will override older certificates with the + // same SubjectAltName value. + QUIC_MUST_USE_RESULT bool AddCertificateChain( + QuicReferenceCountedPointer<Chain> chain, + CertificatePrivateKey key); + + private: + ProofSourceX509() = default; + + struct QUIC_EXPORT_PRIVATE Certificate { + QuicReferenceCountedPointer<Chain> chain; + CertificatePrivateKey key; + }; + + // Looks up certficiate for hostname, returns the default if no certificate is + // found. + Certificate* GetCertificate(const std::string& hostname) const; + + std::forward_list<Certificate> certificates_; + Certificate* default_certificate_; + QuicUnorderedMap<std::string, Certificate*> certificate_map_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_PROOF_SOURCE_X509_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509_test.cc new file mode 100644 index 00000000000..23311d08232 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509_test.cc @@ -0,0 +1,136 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/core/crypto/proof_source_x509.h" + +#include <memory> + +#include "third_party/boringssl/src/include/openssl/ssl.h" +#include "net/third_party/quiche/src/quic/core/crypto/certificate_view.h" +#include "net/third_party/quiche/src/quic/core/crypto/proof_source.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_reference_counted.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/test_certificates.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" + +namespace quic { +namespace test { +namespace { + +QuicReferenceCountedPointer<ProofSource::Chain> MakeChain( + quiche::QuicheStringPiece cert) { + return QuicReferenceCountedPointer<ProofSource::Chain>( + new ProofSource::Chain(std::vector<std::string>{std::string(cert)})); +} + +class ProofSourceX509Test : public QuicTest { + public: + ProofSourceX509Test() + : test_chain_(MakeChain(kTestCertificate)), + wildcard_chain_(MakeChain(kWildcardCertificate)), + test_key_( + CertificatePrivateKey::LoadFromDer(kTestCertificatePrivateKey)), + wildcard_key_(CertificatePrivateKey::LoadFromDer( + kWildcardCertificatePrivateKey)) { + CHECK(test_key_ != nullptr); + CHECK(wildcard_key_ != nullptr); + } + + protected: + QuicReferenceCountedPointer<ProofSource::Chain> test_chain_, wildcard_chain_; + std::unique_ptr<CertificatePrivateKey> test_key_, wildcard_key_; +}; + +TEST_F(ProofSourceX509Test, AddCertificates) { + std::unique_ptr<ProofSourceX509> proof_source = + ProofSourceX509::Create(test_chain_, std::move(*test_key_)); + ASSERT_TRUE(proof_source != nullptr); + EXPECT_TRUE(proof_source->AddCertificateChain(wildcard_chain_, + std::move(*wildcard_key_))); +} + +TEST_F(ProofSourceX509Test, AddCertificateKeyMismatch) { + std::unique_ptr<ProofSourceX509> proof_source = + ProofSourceX509::Create(test_chain_, std::move(*test_key_)); + ASSERT_TRUE(proof_source != nullptr); + test_key_ = CertificatePrivateKey::LoadFromDer(kTestCertificatePrivateKey); + bool result; + EXPECT_QUIC_BUG(result = proof_source->AddCertificateChain( + wildcard_chain_, std::move(*test_key_)), + "Private key does not match"); +} + +TEST_F(ProofSourceX509Test, CertificateSelection) { + std::unique_ptr<ProofSourceX509> proof_source = + ProofSourceX509::Create(test_chain_, std::move(*test_key_)); + ASSERT_TRUE(proof_source != nullptr); + ASSERT_TRUE(proof_source->AddCertificateChain(wildcard_chain_, + std::move(*wildcard_key_))); + + // Default certificate. + EXPECT_EQ(proof_source + ->GetCertChain(QuicSocketAddress(), QuicSocketAddress(), + "unknown.test") + ->certs[0], + kTestCertificate); + // mail.example.org is explicitly a SubjectAltName in kTestCertificate. + EXPECT_EQ(proof_source + ->GetCertChain(QuicSocketAddress(), QuicSocketAddress(), + "mail.example.org") + ->certs[0], + kTestCertificate); + // www.foo.test is in kWildcardCertificate. + EXPECT_EQ(proof_source + ->GetCertChain(QuicSocketAddress(), QuicSocketAddress(), + "www.foo.test") + ->certs[0], + kWildcardCertificate); + // *.wildcard.test is in kWildcardCertificate. + EXPECT_EQ(proof_source + ->GetCertChain(QuicSocketAddress(), QuicSocketAddress(), + "www.wildcard.test") + ->certs[0], + kWildcardCertificate); + EXPECT_EQ(proof_source + ->GetCertChain(QuicSocketAddress(), QuicSocketAddress(), + "etc.wildcard.test") + ->certs[0], + kWildcardCertificate); + // wildcard.test itself is not in kWildcardCertificate. + EXPECT_EQ(proof_source + ->GetCertChain(QuicSocketAddress(), QuicSocketAddress(), + "wildcard.test") + ->certs[0], + kTestCertificate); +} + +TEST_F(ProofSourceX509Test, TlsSignature) { + class Callback : public ProofSource::SignatureCallback { + public: + void Run(bool ok, + std::string signature, + std::unique_ptr<ProofSource::Details> /*details*/) override { + ASSERT_TRUE(ok); + std::unique_ptr<CertificateView> view = + CertificateView::ParseSingleCertificate(kTestCertificate); + EXPECT_TRUE(view->VerifySignature("Test data", signature, + SSL_SIGN_RSA_PSS_RSAE_SHA256)); + } + }; + + std::unique_ptr<ProofSourceX509> proof_source = + ProofSourceX509::Create(test_chain_, std::move(*test_key_)); + ASSERT_TRUE(proof_source != nullptr); + + proof_source->ComputeTlsSignature(QuicSocketAddress(), QuicSocketAddress(), + "example.com", SSL_SIGN_RSA_PSS_RSAE_SHA256, + "Test data", std::make_unique<Callback>()); +} + +} // namespace +} // namespace test +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/proof_verifier.h b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_verifier.h index 12036d69887..0380b8a87d8 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/proof_verifier.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_verifier.h @@ -102,6 +102,7 @@ class QUIC_EXPORT_PRIVATE ProofVerifier { // In this case, the ProofVerifier will take ownership of |callback|. virtual QuicAsyncStatus VerifyCertChain( const std::string& hostname, + const uint16_t port, const std::vector<std::string>& certs, const std::string& ocsp_response, const std::string& cert_sct, diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h index e4f7061a82c..e3867c8e7b2 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h @@ -42,13 +42,13 @@ struct QUIC_EXPORT_PRIVATE QuicResumptionState { // client didn't receive a 0-RTT capable session ticket from the server, // |transport_params| will be null. Otherwise, it will contain the transport // parameters received from the server on the original connection. - std::unique_ptr<TransportParameters> transport_params; + TransportParameters* transport_params; // If |transport_params| is null, then |application_state| is ignored and // should be empty. |application_state| contains serialized state that the // client received from the server at the application layer that the client // needs to remember when performing a 0-RTT handshake. - std::vector<uint8_t> application_state; + ApplicationState* application_state; }; // SessionCache is an interface for managing storing and retrieving @@ -57,15 +57,16 @@ class QUIC_EXPORT_PRIVATE SessionCache { public: virtual ~SessionCache() {} - // Inserts |state| into the cache, keyed by |server_id|. Insert is called - // after a session ticket is received. If the session ticket is valid for - // 0-RTT, there may be a delay between its receipt and the call to Insert - // while waiting for application state for |state|. - // - // Insert may be called multiple times per connection. SessionCache - // implementations should support storing multiple entries per server ID. + // Inserts |session|, |params|, and |application_states| into the cache, keyed + // by |server_id|. Insert is first called after all three values are present. + // The ownership of |session| is transferred to the cache, while other two are + // copied. Multiple sessions might need to be inserted for a connection. + // SessionCache implementations should support storing + // multiple entries per server ID. virtual void Insert(const QuicServerId& server_id, - std::unique_ptr<QuicResumptionState> state) = 0; + bssl::UniquePtr<SSL_SESSION> session, + const TransportParameters& params, + const ApplicationState* application_state) = 0; // Lookup is called once at the beginning of each TLS handshake to potentially // provide the saved state both for the TLS handshake and for sending 0-RTT @@ -392,10 +393,14 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { // Saves the |alpn| that will be passed in QUIC's CHLO message. void set_alpn(const std::string& alpn) { alpn_ = alpn; } + // Saves the pre-shared key used during the handshake. void set_pre_shared_key(quiche::QuicheStringPiece psk) { pre_shared_key_ = std::string(psk); } + // Returns the pre-shared key used during the handshake. + const std::string& pre_shared_key() const { return pre_shared_key_; } + bool pad_inchoate_hello() const { return pad_inchoate_hello_; } void set_pad_inchoate_hello(bool new_value) { pad_inchoate_hello_ = new_value; diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc index 4dc34ffd13f..9cb089bf0e8 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc @@ -46,6 +46,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_hostname_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" #include "net/third_party/quiche/src/quic/platform/api/quic_reference_counted.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" #include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h" @@ -242,7 +243,7 @@ QuicCryptoServerConfig::QuicCryptoServerConfig( proof_source_(std::move(proof_source)), client_cert_mode_(ClientCertMode::kNone), key_exchange_source_(std::move(key_exchange_source)), - ssl_ctx_(TlsServerConnection::CreateSslCtx()), + ssl_ctx_(TlsServerConnection::CreateSslCtx(proof_source_.get())), source_address_token_future_secs_(3600), source_address_token_lifetime_secs_(86400), enable_serving_sct_(false), @@ -524,7 +525,7 @@ void QuicCryptoServerConfig::GetConfigIds( void QuicCryptoServerConfig::ValidateClientHello( const CryptoHandshakeMessage& client_hello, - const QuicIpAddress& client_ip, + const QuicSocketAddress& client_address, const QuicSocketAddress& server_address, QuicTransportVersion version, const QuicClock* clock, @@ -533,8 +534,8 @@ void QuicCryptoServerConfig::ValidateClientHello( const QuicWallTime now(clock->WallNow()); QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> result( - new ValidateClientHelloResultCallback::Result(client_hello, client_ip, - now)); + new ValidateClientHelloResultCallback::Result( + client_hello, client_address.host(), now)); quiche::QuicheStringPiece requested_scid; client_hello.GetStringPiece(kSCID, &requested_scid); @@ -551,8 +552,8 @@ void QuicCryptoServerConfig::ValidateClientHello( signed_config->chain = nullptr; signed_config->proof.signature = ""; signed_config->proof.leaf_cert_scts = ""; - EvaluateClientHello(server_address, version, configs, result, - std::move(done_cb)); + EvaluateClientHello(server_address, client_address, version, configs, + result, std::move(done_cb)); } else { done_cb->Run(result, /* details = */ nullptr); } @@ -717,8 +718,9 @@ void QuicCryptoServerConfig::ProcessClientHello( this, std::move(context), configs); DCHECK(proof_source_.get()); - proof_source_->GetProof(server_address, sni, configs.primary->serialized, - transport_version, chlo_hash, std::move(cb)); + proof_source_->GetProof(server_address, client_address, sni, + configs.primary->serialized, transport_version, + chlo_hash, std::move(cb)); return; } @@ -1016,10 +1018,12 @@ void QuicCryptoServerConfig::SendRejectWithFallbackConfig( const std::string sni(context->info().sni); const QuicTransportVersion transport_version = context->transport_version(); + const QuicSocketAddress& client_address = context->client_address(); auto cb = std::make_unique<SendRejectWithFallbackConfigCallback>( this, std::move(context), fallback_config); - proof_source_->GetProof(server_address, sni, fallback_config->serialized, - transport_version, chlo_hash, std::move(cb)); + proof_source_->GetProof(server_address, client_address, sni, + fallback_config->serialized, transport_version, + chlo_hash, std::move(cb)); } void QuicCryptoServerConfig::SendRejectWithFallbackConfigAfterGetProof( @@ -1196,6 +1200,7 @@ void QuicCryptoServerConfig::SelectNewPrimaryConfig( void QuicCryptoServerConfig::EvaluateClientHello( const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, QuicTransportVersion /*version*/, const Configs& configs, QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> @@ -1270,7 +1275,8 @@ void QuicCryptoServerConfig::EvaluateClientHello( } QuicReferenceCountedPointer<ProofSource::Chain> chain = - proof_source_->GetCertChain(server_address, std::string(info->sni)); + proof_source_->GetCertChain(server_address, client_address, + std::string(info->sni)); if (!chain) { info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE); } else if (!ValidateExpectedLeafCertificate(client_hello, chain->certs)) { @@ -1303,7 +1309,7 @@ void QuicCryptoServerConfig::BuildServerConfigUpdateMessage( quiche::QuicheStringPiece chlo_hash, const SourceAddressTokens& previous_source_address_tokens, const QuicSocketAddress& server_address, - const QuicIpAddress& client_ip, + const QuicSocketAddress& client_address, const QuicClock* clock, QuicRandom* rand, QuicCompressedCertsCache* compressed_certs_cache, @@ -1318,8 +1324,8 @@ void QuicCryptoServerConfig::BuildServerConfigUpdateMessage( serialized = primary_config_->serialized; common_cert_sets = primary_config_->common_cert_sets; source_address_token = NewSourceAddressToken( - *primary_config_, previous_source_address_tokens, client_ip, rand, - clock->WallNow(), cached_network_params); + *primary_config_, previous_source_address_tokens, client_address.host(), + rand, clock->WallNow(), cached_network_params); } CryptoHandshakeMessage message; @@ -1332,8 +1338,9 @@ void QuicCryptoServerConfig::BuildServerConfigUpdateMessage( this, compressed_certs_cache, common_cert_sets, params, std::move(message), std::move(cb)); - proof_source_->GetProof(server_address, params.sni, serialized, version, - chlo_hash, std::move(proof_source_cb)); + proof_source_->GetProof(server_address, client_address, params.sni, + serialized, version, chlo_hash, + std::move(proof_source_cb)); } QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback:: diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h index 4a8cb737c98..9f2db603416 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h @@ -294,7 +294,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerConfig { // completion of an asynchronous operation. void ValidateClientHello( const CryptoHandshakeMessage& client_hello, - const QuicIpAddress& client_ip, + const QuicSocketAddress& client_address, const QuicSocketAddress& server_address, QuicTransportVersion version, const QuicClock* clock, @@ -360,7 +360,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerConfig { quiche::QuicheStringPiece chlo_hash, const SourceAddressTokens& previous_source_address_tokens, const QuicSocketAddress& server_address, - const QuicIpAddress& client_ip, + const QuicSocketAddress& client_address, const QuicClock* clock, QuicRandom* rand, QuicCompressedCertsCache* compressed_certs_cache, @@ -432,6 +432,8 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerConfig { SSL_CTX* ssl_ctx() const; + // Pre-shared key used during the handshake. + const std::string& pre_shared_key() const { return pre_shared_key_; } void set_pre_shared_key(quiche::QuicheStringPiece psk) { pre_shared_key_ = std::string(psk); } @@ -551,6 +553,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerConfig { // are written to |client_hello_state->info|. void EvaluateClientHello( const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, QuicTransportVersion version, const Configs& configs, QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config_test.cc index 8dd1108b37f..6f0c047b95b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config_test.cc @@ -481,7 +481,7 @@ TEST_F(CryptoServerConfigsTest, AdvancePrimaryViaValidate) { test_peer_.SelectNewPrimaryConfig(1000); test_peer_.CheckConfigs({{"a", true}, {"b", false}}); CryptoHandshakeMessage client_hello; - QuicIpAddress client_ip; + QuicSocketAddress client_address; QuicSocketAddress server_address; QuicTransportVersion transport_version = QUIC_VERSION_UNSUPPORTED; for (const ParsedQuicVersion& version : AllSupportedVersions()) { @@ -497,7 +497,7 @@ TEST_F(CryptoServerConfigsTest, AdvancePrimaryViaValidate) { std::unique_ptr<ValidateClientHelloResultCallback> done_cb( new ValidateCallback); clock.AdvanceTime(QuicTime::Delta::FromSeconds(1100)); - config_.ValidateClientHello(client_hello, client_ip, server_address, + config_.ValidateClientHello(client_hello, client_address, server_address, transport_version, &clock, signed_config, std::move(done_cb)); test_peer_.CheckConfigs({{"a", false}, {"b", true}}); diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.cc index b0d2147c286..75d28c55d60 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.cc @@ -108,18 +108,10 @@ TlsConnection* TlsConnection::ConnectionFromSsl(const SSL* ssl) { ssl, SslIndexSingleton::GetInstance()->ssl_ex_data_index_connection())); } -// TODO(nharper): Once -// https://boringssl-review.googlesource.com/c/boringssl/+/40127 lands and is -// rolled into google3, remove the BORINGSSL_API_VERSION check. const SSL_QUIC_METHOD TlsConnection::kSslQuicMethod{ -#if BORINGSSL_API_VERSION < 10 - TlsConnection::SetEncryptionSecretCallback, -#else - TlsConnection::SetReadSecretCallback, TlsConnection::SetWriteSecretCallback, -#endif - TlsConnection::WriteMessageCallback, TlsConnection::FlushFlightCallback, - TlsConnection::SendAlertCallback -}; + TlsConnection::SetReadSecretCallback, TlsConnection::SetWriteSecretCallback, + TlsConnection::WriteMessageCallback, TlsConnection::FlushFlightCallback, + TlsConnection::SendAlertCallback}; // static int TlsConnection::SetEncryptionSecretCallback( diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_server_connection.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_server_connection.cc index bdc941ade7c..54db5455ca5 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_server_connection.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_server_connection.cc @@ -4,6 +4,9 @@ #include "net/third_party/quiche/src/quic/core/crypto/tls_server_connection.h" +#include "third_party/boringssl/src/include/openssl/ssl.h" +#include "net/third_party/quiche/src/quic/core/crypto/proof_source.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" namespace quic { @@ -13,12 +16,24 @@ TlsServerConnection::TlsServerConnection(SSL_CTX* ssl_ctx, Delegate* delegate) delegate_(delegate) {} // static -bssl::UniquePtr<SSL_CTX> TlsServerConnection::CreateSslCtx() { +bssl::UniquePtr<SSL_CTX> TlsServerConnection::CreateSslCtx( + ProofSource* proof_source) { bssl::UniquePtr<SSL_CTX> ssl_ctx = TlsConnection::CreateSslCtx(); SSL_CTX_set_tlsext_servername_callback(ssl_ctx.get(), &SelectCertificateCallback); SSL_CTX_set_alpn_select_cb(ssl_ctx.get(), &SelectAlpnCallback, nullptr); - SSL_CTX_set_options(ssl_ctx.get(), SSL_OP_NO_TICKET); + // We don't actually need the TicketCrypter here, but we need to know + // whether it's set. + if (GetQuicReloadableFlag(quic_enable_tls_resumption) && + proof_source->GetTicketCrypter()) { + SSL_CTX_set_ticket_aead_method(ssl_ctx.get(), + &TlsServerConnection::kSessionTicketMethod); + if (GetQuicReloadableFlag(quic_enable_zero_rtt_for_tls)) { + SSL_CTX_set_early_data_enabled(ssl_ctx.get(), 1); + } + } else { + SSL_CTX_set_options(ssl_ctx.get(), SSL_OP_NO_TICKET); + } return ssl_ctx; } @@ -81,4 +96,41 @@ ssl_private_key_result_t TlsServerConnection::PrivateKeyComplete( max_out); } +// static +const SSL_TICKET_AEAD_METHOD TlsServerConnection::kSessionTicketMethod{ + TlsServerConnection::SessionTicketMaxOverhead, + TlsServerConnection::SessionTicketSeal, + TlsServerConnection::SessionTicketOpen, +}; + +// static +size_t TlsServerConnection::SessionTicketMaxOverhead(SSL* ssl) { + return ConnectionFromSsl(ssl)->delegate_->SessionTicketMaxOverhead(); +} + +// static +int TlsServerConnection::SessionTicketSeal(SSL* ssl, + uint8_t* out, + size_t* out_len, + size_t max_out_len, + const uint8_t* in, + size_t in_len) { + return ConnectionFromSsl(ssl)->delegate_->SessionTicketSeal( + out, out_len, max_out_len, + quiche::QuicheStringPiece(reinterpret_cast<const char*>(in), in_len)); +} + +// static +enum ssl_ticket_aead_result_t TlsServerConnection::SessionTicketOpen( + SSL* ssl, + uint8_t* out, + size_t* out_len, + size_t max_out_len, + const uint8_t* in, + size_t in_len) { + return ConnectionFromSsl(ssl)->delegate_->SessionTicketOpen( + out, out_len, max_out_len, + quiche::QuicheStringPiece(reinterpret_cast<const char*>(in), in_len)); +} + } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_server_connection.h b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_server_connection.h index 85ce7e79a81..6da81141335 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_server_connection.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_server_connection.h @@ -5,6 +5,7 @@ #ifndef QUICHE_QUIC_CORE_CRYPTO_TLS_SERVER_CONNECTION_H_ #define QUICHE_QUIC_CORE_CRYPTO_TLS_SERVER_CONNECTION_H_ +#include "net/third_party/quiche/src/quic/core/crypto/proof_source.h" #include "net/third_party/quiche/src/quic/core/crypto/tls_connection.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" @@ -59,6 +60,50 @@ class QUIC_EXPORT_PRIVATE TlsServerConnection : public TlsConnection { size_t* out_len, size_t max_out) = 0; + // The following functions are used to implement an SSL_TICKET_AEAD_METHOD. + // See + // https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#ssl_ticket_aead_result_t + // for details on the BoringSSL API. + + // SessionTicketMaxOverhead returns the maximum number of bytes of overhead + // that SessionTicketSeal may add when encrypting a session ticket. + virtual size_t SessionTicketMaxOverhead() = 0; + + // SessionTicketSeal encrypts the session ticket in |in|, putting the + // resulting encrypted ticket in |out|, writing the length of the bytes + // written to |*out_len|, which is no larger than |max_out_len|. It returns + // 1 on success and 0 on error. + virtual int SessionTicketSeal(uint8_t* out, + size_t* out_len, + size_t max_out_len, + quiche::QuicheStringPiece in) = 0; + + // SessionTicketOpen is called when BoringSSL has an encrypted session + // ticket |in| and wants the ticket decrypted. This decryption operation can + // happen synchronously or asynchronously. + // + // If the decrypted ticket is not available at the time of the function + // call, this function returns ssl_ticket_aead_retry. If this function + // returns ssl_ticket_aead_retry, then SSL_do_handshake will return + // SSL_ERROR_PENDING_TICKET. Once the pending ticket decryption has + // completed, SSL_do_handshake needs to be called again. + // + // When this function is called and the decrypted ticket is available + // (either the ticket was decrypted synchronously, or an asynchronous + // operation has completed and SSL_do_handshake has been called again), the + // decrypted ticket is put in |out|, and the length of that output is + // written to |*out_len|, not to exceed |max_out_len|, and + // ssl_ticket_aead_success is returned. If the ticket cannot be decrypted + // and should be ignored, this function returns + // ssl_ticket_aead_ignore_ticket and a full handshake will be performed + // instead. If a fatal error occurs, ssl_ticket_aead_error can be returned + // which will terminate the handshake. + virtual enum ssl_ticket_aead_result_t SessionTicketOpen( + uint8_t* out, + size_t* out_len, + size_t max_out_len, + quiche::QuicheStringPiece in) = 0; + // Provides the delegate for callbacks that are shared between client and // server. virtual TlsConnection::Delegate* ConnectionDelegate() = 0; @@ -69,7 +114,7 @@ class QUIC_EXPORT_PRIVATE TlsServerConnection : public TlsConnection { TlsServerConnection(SSL_CTX* ssl_ctx, Delegate* delegate); // Creates and configures an SSL_CTX that is appropriate for servers to use. - static bssl::UniquePtr<SSL_CTX> CreateSslCtx(); + static bssl::UniquePtr<SSL_CTX> CreateSslCtx(ProofSource* proof_source); void SetCertChain(const std::vector<CRYPTO_BUFFER*>& cert_chain); @@ -105,6 +150,25 @@ class QUIC_EXPORT_PRIVATE TlsServerConnection : public TlsConnection { size_t* out_len, size_t max_out); + // Implementation of SSL_TICKET_AEAD_METHOD which delegates to corresponding + // methods in TlsServerConnection::Delegate (a.k.a. TlsServerHandshaker). + static const SSL_TICKET_AEAD_METHOD kSessionTicketMethod; + + // The following functions make up the contents of |kSessionTicketMethod|. + static size_t SessionTicketMaxOverhead(SSL* ssl); + static int SessionTicketSeal(SSL* ssl, + uint8_t* out, + size_t* out_len, + size_t max_out_len, + const uint8_t* in, + size_t in_len); + static enum ssl_ticket_aead_result_t SessionTicketOpen(SSL* ssl, + uint8_t* out, + size_t* out_len, + size_t max_out_len, + const uint8_t* in, + size_t in_len); + Delegate* delegate_; }; diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.cc index 4cefcddad22..3e286adc84b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.cc @@ -7,9 +7,11 @@ #include <cstdint> #include <cstring> #include <forward_list> +#include <memory> #include <utility> #include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h" #include "net/third_party/quiche/src/quic/core/quic_connection_id.h" #include "net/third_party/quiche/src/quic/core/quic_data_reader.h" #include "net/third_party/quiche/src/quic/core/quic_data_writer.h" @@ -47,6 +49,9 @@ enum TransportParameters::TransportParameterId : uint64_t { kMaxDatagramFrameSize = 0x20, + kInitialRoundTripTime = 0x3127, + kGoogleConnectionOptions = 0x3128, + kGoogleUserAgentId = 0x3129, kGoogleQuicParam = 18257, // Used for non-standard Google-specific params. kGoogleQuicVersion = 18258, // Used to transmit version and supported_versions. @@ -57,12 +62,14 @@ namespace { // The following constants define minimum and maximum allowed values for some of // the parameters. These come from the "Transport Parameter Definitions" // section of draft-ietf-quic-transport. -const uint64_t kMinMaxPacketSizeTransportParam = 1200; -const uint64_t kMaxAckDelayExponentTransportParam = 20; -const uint64_t kDefaultAckDelayExponentTransportParam = 3; -const uint64_t kMaxMaxAckDelayTransportParam = 16383; -const uint64_t kDefaultMaxAckDelayTransportParam = 25; -const size_t kStatelessResetTokenLength = 16; +constexpr uint64_t kMinMaxPacketSizeTransportParam = 1200; +constexpr uint64_t kMaxAckDelayExponentTransportParam = 20; +constexpr uint64_t kDefaultAckDelayExponentTransportParam = 3; +constexpr uint64_t kMaxMaxAckDelayTransportParam = 16383; +constexpr uint64_t kDefaultMaxAckDelayTransportParam = 25; +constexpr size_t kStatelessResetTokenLength = 16; +constexpr uint64_t kMinActiveConnectionIdLimitTransportParam = 2; +constexpr uint64_t kDefaultActiveConnectionIdLimitTransportParam = 2; std::string TransportParameterIdToString( TransportParameters::TransportParameterId param_id) { @@ -99,6 +106,12 @@ std::string TransportParameterIdToString( return "active_connection_id_limit"; case TransportParameters::kMaxDatagramFrameSize: return "max_datagram_frame_size"; + case TransportParameters::kInitialRoundTripTime: + return "initial_round_trip_time"; + case TransportParameters::kGoogleConnectionOptions: + return "google_connection_options"; + case TransportParameters::kGoogleUserAgentId: + return "user_agent_id"; case TransportParameters::kGoogleQuicParam: return "google"; case TransportParameters::kGoogleQuicVersion: @@ -107,6 +120,35 @@ std::string TransportParameterIdToString( return "Unknown(" + quiche::QuicheTextUtils::Uint64ToString(param_id) + ")"; } +bool TransportParameterIdIsKnown( + TransportParameters::TransportParameterId param_id) { + switch (param_id) { + case TransportParameters::kOriginalConnectionId: + case TransportParameters::kIdleTimeout: + case TransportParameters::kStatelessResetToken: + case TransportParameters::kMaxPacketSize: + case TransportParameters::kInitialMaxData: + case TransportParameters::kInitialMaxStreamDataBidiLocal: + case TransportParameters::kInitialMaxStreamDataBidiRemote: + case TransportParameters::kInitialMaxStreamDataUni: + case TransportParameters::kInitialMaxStreamsBidi: + case TransportParameters::kInitialMaxStreamsUni: + case TransportParameters::kAckDelayExponent: + case TransportParameters::kMaxAckDelay: + case TransportParameters::kDisableMigration: + case TransportParameters::kPreferredAddress: + case TransportParameters::kActiveConnectionIdLimit: + case TransportParameters::kMaxDatagramFrameSize: + case TransportParameters::kInitialRoundTripTime: + case TransportParameters::kGoogleConnectionOptions: + case TransportParameters::kGoogleUserAgentId: + case TransportParameters::kGoogleQuicParam: + case TransportParameters::kGoogleQuicVersion: + return true; + } + return false; +} + bool WriteTransportParameterId( QuicDataWriter* writer, TransportParameters::TransportParameterId param_id, @@ -310,6 +352,19 @@ TransportParameters::PreferredAddress::PreferredAddress() TransportParameters::PreferredAddress::~PreferredAddress() {} +bool TransportParameters::PreferredAddress::operator==( + const PreferredAddress& rhs) const { + return ipv4_socket_address == rhs.ipv4_socket_address && + ipv6_socket_address == rhs.ipv6_socket_address && + connection_id == rhs.connection_id && + stateless_reset_token == rhs.stateless_reset_token; +} + +bool TransportParameters::PreferredAddress::operator!=( + const PreferredAddress& rhs) const { + return !(*this == rhs); +} + std::ostream& operator<<( std::ostream& os, const TransportParameters::PreferredAddress& preferred_address) { @@ -346,9 +401,9 @@ std::string TransportParameters::ToString() const { rv += " supported_versions " + QuicVersionLabelVectorToString(supported_versions); } - if (!original_connection_id.IsEmpty()) { + if (original_connection_id.has_value()) { rv += " " + TransportParameterIdToString(kOriginalConnectionId) + " " + - original_connection_id.ToString(); + original_connection_id.value().ToString(); } rv += idle_timeout_milliseconds.ToString(/*for_use_in_list=*/true); if (!stateless_reset_token.empty()) { @@ -375,20 +430,36 @@ std::string TransportParameters::ToString() const { } rv += active_connection_id_limit.ToString(/*for_use_in_list=*/true); rv += max_datagram_frame_size.ToString(/*for_use_in_list=*/true); + rv += initial_round_trip_time_us.ToString(/*for_use_in_list=*/true); + if (google_connection_options.has_value()) { + rv += " " + TransportParameterIdToString(kGoogleConnectionOptions) + " "; + bool first = true; + for (const QuicTag& connection_option : google_connection_options.value()) { + if (first) { + first = false; + } else { + rv += ","; + } + rv += QuicTagToString(connection_option); + } + } + if (user_agent_id.has_value()) { + rv += " " + TransportParameterIdToString(kGoogleUserAgentId) + " \"" + + user_agent_id.value() + "\""; + } if (google_quic_params) { rv += " " + TransportParameterIdToString(kGoogleQuicParam); } - rv += "]"; for (const auto& kv : custom_parameters) { rv += " 0x" + quiche::QuicheTextUtils::Hex(static_cast<uint32_t>(kv.first)); rv += "=" + quiche::QuicheTextUtils::HexEncode(kv.second); } + rv += "]"; return rv; } TransportParameters::TransportParameters() : version(0), - original_connection_id(EmptyQuicConnectionId()), idle_timeout_milliseconds(kIdleTimeout), max_packet_size(kMaxPacketSize, kDefaultMaxPacketSizeTransportParam, @@ -409,13 +480,109 @@ TransportParameters::TransportParameters() 0, kMaxMaxAckDelayTransportParam), disable_migration(false), - active_connection_id_limit(kActiveConnectionIdLimit), - max_datagram_frame_size(kMaxDatagramFrameSize) + active_connection_id_limit(kActiveConnectionIdLimit, + kDefaultActiveConnectionIdLimitTransportParam, + kMinActiveConnectionIdLimitTransportParam, + kVarInt62MaxValue), + max_datagram_frame_size(kMaxDatagramFrameSize), + initial_round_trip_time_us(kInitialRoundTripTime) // Important note: any new transport parameters must be added // to TransportParameters::AreValid, SerializeTransportParameters and -// ParseTransportParameters. +// ParseTransportParameters, TransportParameters's custom copy constructor, the +// operator==, and TransportParametersTest.Comparator. {} +TransportParameters::TransportParameters(const TransportParameters& other) + : perspective(other.perspective), + version(other.version), + supported_versions(other.supported_versions), + original_connection_id(other.original_connection_id), + idle_timeout_milliseconds(other.idle_timeout_milliseconds), + stateless_reset_token(other.stateless_reset_token), + max_packet_size(other.max_packet_size), + initial_max_data(other.initial_max_data), + initial_max_stream_data_bidi_local( + other.initial_max_stream_data_bidi_local), + initial_max_stream_data_bidi_remote( + other.initial_max_stream_data_bidi_remote), + initial_max_stream_data_uni(other.initial_max_stream_data_uni), + initial_max_streams_bidi(other.initial_max_streams_bidi), + initial_max_streams_uni(other.initial_max_streams_uni), + ack_delay_exponent(other.ack_delay_exponent), + max_ack_delay(other.max_ack_delay), + disable_migration(other.disable_migration), + active_connection_id_limit(other.active_connection_id_limit), + max_datagram_frame_size(other.max_datagram_frame_size), + initial_round_trip_time_us(other.initial_round_trip_time_us), + google_connection_options(other.google_connection_options), + user_agent_id(other.user_agent_id), + custom_parameters(other.custom_parameters) { + if (other.preferred_address) { + preferred_address = std::make_unique<TransportParameters::PreferredAddress>( + *other.preferred_address); + } + if (other.google_quic_params) { + google_quic_params = + std::make_unique<CryptoHandshakeMessage>(*other.google_quic_params); + } +} + +bool TransportParameters::operator==(const TransportParameters& rhs) const { + if (!(perspective == rhs.perspective && version == rhs.version && + supported_versions == rhs.supported_versions && + original_connection_id == rhs.original_connection_id && + idle_timeout_milliseconds.value() == + rhs.idle_timeout_milliseconds.value() && + stateless_reset_token == rhs.stateless_reset_token && + max_packet_size.value() == rhs.max_packet_size.value() && + initial_max_data.value() == rhs.initial_max_data.value() && + initial_max_stream_data_bidi_local.value() == + rhs.initial_max_stream_data_bidi_local.value() && + initial_max_stream_data_bidi_remote.value() == + rhs.initial_max_stream_data_bidi_remote.value() && + initial_max_stream_data_uni.value() == + rhs.initial_max_stream_data_uni.value() && + initial_max_streams_bidi.value() == + rhs.initial_max_streams_bidi.value() && + initial_max_streams_uni.value() == + rhs.initial_max_streams_uni.value() && + ack_delay_exponent.value() == rhs.ack_delay_exponent.value() && + max_ack_delay.value() == rhs.max_ack_delay.value() && + disable_migration == rhs.disable_migration && + active_connection_id_limit.value() == + rhs.active_connection_id_limit.value() && + max_datagram_frame_size.value() == + rhs.max_datagram_frame_size.value() && + initial_round_trip_time_us.value() == + rhs.initial_round_trip_time_us.value() && + google_connection_options == rhs.google_connection_options && + user_agent_id == rhs.user_agent_id && + custom_parameters == rhs.custom_parameters)) { + return false; + } + + if ((!preferred_address && rhs.preferred_address) || + (preferred_address && !rhs.preferred_address) || + (!google_quic_params && rhs.google_quic_params) || + (google_quic_params && !rhs.google_quic_params)) { + return false; + } + bool address = true; + if (preferred_address && rhs.preferred_address) { + address = (*preferred_address == *rhs.preferred_address); + } + + bool google_quic = true; + if (google_quic_params && rhs.google_quic_params) { + google_quic = (*google_quic_params == *rhs.google_quic_params); + } + return address && google_quic; +} + +bool TransportParameters::operator!=(const TransportParameters& rhs) const { + return !(*this == rhs); +} + bool TransportParameters::AreValid(std::string* error_details) const { DCHECK(perspective == Perspective::IS_CLIENT || perspective == Perspective::IS_SERVER); @@ -424,7 +591,7 @@ bool TransportParameters::AreValid(std::string* error_details) const { return false; } if (perspective == Perspective::IS_CLIENT && - !original_connection_id.IsEmpty()) { + original_connection_id.has_value()) { *error_details = "Client cannot send original connection ID"; return false; } @@ -452,6 +619,23 @@ bool TransportParameters::AreValid(std::string* error_details) const { *error_details = "Internal preferred address family failure"; return false; } + for (const auto& kv : custom_parameters) { + if (TransportParameterIdIsKnown(kv.first)) { + *error_details = quiche::QuicheStrCat( + "Using custom_parameters with known ID ", + TransportParameterIdToString(kv.first), " is not allowed"); + return false; + } + } + if (perspective == Perspective::IS_SERVER && + initial_round_trip_time_us.value() > 0) { + *error_details = "Server cannot send initial round trip time"; + return false; + } + if (perspective == Perspective::IS_SERVER && user_agent_id.has_value()) { + *error_details = "Server cannot send user agent ID"; + return false; + } const bool ok = idle_timeout_milliseconds.IsValid() && max_packet_size.IsValid() && initial_max_data.IsValid() && @@ -460,7 +644,8 @@ bool TransportParameters::AreValid(std::string* error_details) const { initial_max_stream_data_uni.IsValid() && initial_max_streams_bidi.IsValid() && initial_max_streams_uni.IsValid() && ack_delay_exponent.IsValid() && max_ack_delay.IsValid() && - active_connection_id_limit.IsValid() && max_datagram_frame_size.IsValid(); + active_connection_id_limit.IsValid() && + max_datagram_frame_size.IsValid() && initial_round_trip_time_us.IsValid(); if (!ok) { *error_details = "Invalid transport parameters " + this->ToString(); } @@ -504,17 +689,18 @@ bool SerializeTransportParameters(ParsedQuicVersion version, } // original_connection_id - if (!in.original_connection_id.IsEmpty()) { + if (in.original_connection_id.has_value()) { DCHECK_EQ(Perspective::IS_SERVER, in.perspective); + QuicConnectionId original_connection_id = in.original_connection_id.value(); if (!WriteTransportParameterId( &writer, TransportParameters::kOriginalConnectionId, version) || !WriteTransportParameterStringPiece( &writer, - quiche::QuicheStringPiece(in.original_connection_id.data(), - in.original_connection_id.length()), + quiche::QuicheStringPiece(original_connection_id.data(), + original_connection_id.length()), version)) { QUIC_BUG << "Failed to write original_connection_id " - << in.original_connection_id << " for " << in; + << in.original_connection_id.value() << " for " << in; return false; } } @@ -552,7 +738,8 @@ bool SerializeTransportParameters(ParsedQuicVersion version, !in.ack_delay_exponent.Write(&writer, version) || !in.max_ack_delay.Write(&writer, version) || !in.active_connection_id_limit.Write(&writer, version) || - !in.max_datagram_frame_size.Write(&writer, version)) { + !in.max_datagram_frame_size.Write(&writer, version) || + !in.initial_round_trip_time_us.Write(&writer, version)) { QUIC_BUG << "Failed to write integers for " << in; return false; } @@ -604,6 +791,42 @@ bool SerializeTransportParameters(ParsedQuicVersion version, } } + // Google-specific connection options. + if (in.google_connection_options.has_value()) { + static_assert(sizeof(in.google_connection_options.value().front()) == 4, + "bad size"); + uint64_t connection_options_length = + in.google_connection_options.value().size() * 4; + if (!WriteTransportParameterId( + &writer, TransportParameters::kGoogleConnectionOptions, version) || + !WriteTransportParameterLength(&writer, connection_options_length, + version)) { + QUIC_BUG << "Failed to write google_connection_options of length " + << connection_options_length << " for " << in; + return false; + } + for (const QuicTag& connection_option : + in.google_connection_options.value()) { + if (!writer.WriteTag(connection_option)) { + QUIC_BUG << "Failed to write google_connection_option " + << QuicTagToString(connection_option) << " for " << in; + return false; + } + } + } + + // Google-specific user agent identifier. + if (in.user_agent_id.has_value()) { + if (!WriteTransportParameterId( + &writer, TransportParameters::kGoogleUserAgentId, version) || + !WriteTransportParameterStringPiece(&writer, in.user_agent_id.value(), + version)) { + QUIC_BUG << "Failed to write Google user agent ID \"" + << in.user_agent_id.value() << "\" for " << in; + return false; + } + } + // Google-specific non-standard parameter. if (in.google_quic_params) { const QuicData& serialized_google_quic_params = @@ -648,12 +871,56 @@ bool SerializeTransportParameters(ParsedQuicVersion version, } for (const auto& kv : in.custom_parameters) { - QUIC_BUG_IF(static_cast<uint64_t>(kv.first) < 0xff00) - << "custom_parameters should not be used " - "for non-private use parameters"; - if (!WriteTransportParameterId(&writer, kv.first, version) || + const TransportParameters::TransportParameterId param_id = kv.first; + if (param_id % 31 == 27) { + // See the "Reserved Transport Parameters" section of + // draft-ietf-quic-transport. + QUIC_BUG << "Serializing custom_parameters with GREASE ID " << param_id + << " is not allowed"; + return false; + } + if (!WriteTransportParameterId(&writer, param_id, version) || !WriteTransportParameterStringPiece(&writer, kv.second, version)) { - QUIC_BUG << "Failed to write custom parameter " << kv.first; + QUIC_BUG << "Failed to write custom parameter " << param_id; + return false; + } + } + + { + // Add a random GREASE transport parameter, as defined in the + // "Reserved Transport Parameters" section of draft-ietf-quic-transport. + // https://quicwg.org/base-drafts/draft-ietf-quic-transport.html + // This forces receivers to support unexpected input. + QuicRandom* random = QuicRandom::GetInstance(); + uint64_t grease_id64 = random->RandUint64(); + if (version.HasVarIntTransportParams()) { + // With these versions, identifiers are 62 bits long so we need to ensure + // that the output of the computation below fits in 62 bits. + grease_id64 %= ((1ULL << 62) - 31); + } else { + // Same with 16 bits. + grease_id64 %= ((1ULL << 16) - 31); + } + // Make sure grease_id % 31 == 27. Note that this is not uniformely + // distributed but is acceptable since no security depends on this + // randomness. + grease_id64 = (grease_id64 / 31) * 31 + 27; + DCHECK(version.HasVarIntTransportParams() || + grease_id64 <= std::numeric_limits<uint16_t>::max()) + << grease_id64 << " invalid for " << version; + TransportParameters::TransportParameterId grease_id = + static_cast<TransportParameters::TransportParameterId>(grease_id64); + const size_t kMaxGreaseLength = 16; + const size_t grease_length = random->RandUint64() % kMaxGreaseLength; + DCHECK_GE(kMaxGreaseLength, grease_length); + char grease_contents[kMaxGreaseLength]; + random->RandBytes(grease_contents, grease_length); + if (!WriteTransportParameterId(&writer, grease_id, version) || + !WriteTransportParameterStringPiece( + &writer, quiche::QuicheStringPiece(grease_contents, grease_length), + version)) { + QUIC_BUG << "Failed to write GREASE parameter " + << TransportParameterIdToString(grease_id); return false; } } @@ -679,6 +946,7 @@ bool SerializeTransportParameters(ParsedQuicVersion version, QUIC_DLOG(INFO) << "Serialized " << in << " as " << writer.length() << " bytes"; + return true; } @@ -722,7 +990,7 @@ bool ParseTransportParameters(ParsedQuicVersion version, bool parse_success = true; switch (param_id) { case TransportParameters::kOriginalConnectionId: { - if (!out->original_connection_id.IsEmpty()) { + if (out->original_connection_id.has_value()) { *error_details = "Received a second original connection ID"; return false; } @@ -734,11 +1002,13 @@ bool ParseTransportParameters(ParsedQuicVersion version, connection_id_length); return false; } - if (!value_reader.ReadConnectionId(&out->original_connection_id, + QuicConnectionId original_connection_id; + if (!value_reader.ReadConnectionId(&original_connection_id, connection_id_length)) { *error_details = "Failed to read original connection ID"; return false; } + out->original_connection_id = original_connection_id; } break; case TransportParameters::kIdleTimeout: parse_success = @@ -848,6 +1118,32 @@ bool ParseTransportParameters(ParsedQuicVersion version, parse_success = out->max_datagram_frame_size.Read(&value_reader, error_details); break; + case TransportParameters::kInitialRoundTripTime: + parse_success = + out->initial_round_trip_time_us.Read(&value_reader, error_details); + break; + case TransportParameters::kGoogleConnectionOptions: { + if (out->google_connection_options.has_value()) { + *error_details = "Received a second Google connection options"; + return false; + } + out->google_connection_options = QuicTagVector{}; + while (!value_reader.IsDoneReading()) { + QuicTag connection_option; + if (!value_reader.ReadTag(&connection_option)) { + *error_details = "Failed to read a Google connection option"; + return false; + } + out->google_connection_options.value().push_back(connection_option); + } + } break; + case TransportParameters::kGoogleUserAgentId: + if (out->user_agent_id.has_value()) { + *error_details = "Received a second user agent ID"; + return false; + } + out->user_agent_id = std::string(value_reader.ReadRemainingPayload()); + break; case TransportParameters::kGoogleQuicParam: { if (out->google_quic_params) { *error_details = "Received a second Google parameter"; diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.h b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.h index 831caecd1a9..9dec484a552 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.h @@ -15,6 +15,7 @@ #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/core/quic_versions.h" #include "net/third_party/quiche/src/quic/platform/api/quic_containers.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_optional.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" namespace quic { @@ -35,7 +36,6 @@ struct QUIC_EXPORT_PRIVATE TransportParameters { public: // Forbid constructing and copying apart from TransportParameters. IntegerParameter() = delete; - IntegerParameter(const IntegerParameter&) = delete; IntegerParameter& operator=(const IntegerParameter&) = delete; // Sets the value of this transport parameter. void set_value(uint64_t value); @@ -67,6 +67,8 @@ struct QUIC_EXPORT_PRIVATE TransportParameters { uint64_t default_value, uint64_t min_value, uint64_t max_value); + IntegerParameter(const IntegerParameter& other) = default; + IntegerParameter(IntegerParameter&& other) = default; // Human-readable string representation. std::string ToString(bool for_use_in_list) const; @@ -88,7 +90,11 @@ struct QUIC_EXPORT_PRIVATE TransportParameters { // send to clients. struct QUIC_EXPORT_PRIVATE PreferredAddress { PreferredAddress(); + PreferredAddress(const PreferredAddress& other) = default; + PreferredAddress(PreferredAddress&& other) = default; ~PreferredAddress(); + bool operator==(const PreferredAddress& rhs) const; + bool operator!=(const PreferredAddress& rhs) const; QuicSocketAddress ipv4_socket_address; QuicSocketAddress ipv6_socket_address; @@ -103,7 +109,10 @@ struct QUIC_EXPORT_PRIVATE TransportParameters { }; TransportParameters(); + TransportParameters(const TransportParameters& other); ~TransportParameters(); + bool operator==(const TransportParameters& rhs) const; + bool operator!=(const TransportParameters& rhs) const; // Represents the sender of the transport parameters. When |perspective| is // Perspective::IS_CLIENT, this struct is being used in the client_hello @@ -123,7 +132,7 @@ struct QUIC_EXPORT_PRIVATE TransportParameters { // The value of the Destination Connection ID field from the first // Initial packet sent by the client. - QuicConnectionId original_connection_id; + quiche::QuicheOptional<QuicConnectionId> original_connection_id; // Idle timeout expressed in milliseconds. IntegerParameter idle_timeout_milliseconds; @@ -172,9 +181,19 @@ struct QUIC_EXPORT_PRIVATE TransportParameters { IntegerParameter active_connection_id_limit; // Indicates support for the DATAGRAM frame and the maximum frame size that - // the sender accepts. See draft-pauly-quic-datagram. + // the sender accepts. See draft-ietf-quic-datagram. IntegerParameter max_datagram_frame_size; + // Google-specific transport parameter that carries an estimate of the + // initial round-trip time in microseconds. + IntegerParameter initial_round_trip_time_us; + + // Google-specific connection options. + quiche::QuicheOptional<QuicTagVector> google_connection_options; + + // Google-specific user agent identifier. + quiche::QuicheOptional<std::string> user_agent_id; + // Transport parameters used by Google QUIC but not IETF QUIC. This is // serialized into a TransportParameter struct with a TransportParameterId of // kGoogleQuicParamId. @@ -209,7 +228,6 @@ QUIC_EXPORT_PRIVATE bool SerializeTransportParameters( // This method returns true if the input was successfully parsed. // On failure, this method will write a human-readable error message to // |error_details|. -// TODO(nharper): Write fuzz tests for this method. QUIC_EXPORT_PRIVATE bool ParseTransportParameters(ParsedQuicVersion version, Perspective perspective, const uint8_t* in, diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters_test.cc index bbcba74efb8..1fc1f5c5c93 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters_test.cc @@ -7,6 +7,10 @@ #include <cstring> #include <utility> +#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/core/quic_connection_id.h" +#include "net/third_party/quiche/src/quic/core/quic_tag.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/core/quic_versions.h" #include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" #include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h" @@ -19,9 +23,6 @@ namespace quic { namespace test { namespace { -using testing::Pair; -using testing::UnorderedElementsAre; - const QuicVersionLabel kFakeVersionLabel = 0x01234567; const QuicVersionLabel kFakeVersionLabel2 = 0x89ABCDEF; const uint64_t kFakeIdleTimeoutMilliseconds = 12012; @@ -39,6 +40,7 @@ const uint64_t kFakeAckDelayExponent = 10; const uint64_t kFakeMaxAckDelay = 51; const bool kFakeDisableMigration = true; const uint64_t kFakeActiveConnectionIdLimit = 52; +const uint64_t kFakeInitialRoundTripTime = 53; const uint8_t kFakePreferredStatelessResetTokenData[16] = { 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F}; @@ -101,14 +103,26 @@ CreateFakePreferredAddress() { preferred_address); } -std::vector<ParsedQuicVersion> AllSupportedTlsVersions() { - std::vector<ParsedQuicVersion> tls_versions; - for (const ParsedQuicVersion& version : AllSupportedVersions()) { - if (version.handshake_protocol == PROTOCOL_TLS1_3) { - tls_versions.push_back(version); +QuicTagVector CreateFakeGoogleConnectionOptions() { + return {kALPN, MakeQuicTag('E', 'F', 'G', 0x00), + MakeQuicTag('H', 'I', 'J', 0xff)}; +} + +std::string CreateFakeUserAgentId() { + return "FakeUAID"; +} + +void RemoveGreaseParameters(TransportParameters* params) { + std::vector<TransportParameters::TransportParameterId> grease_params; + for (const auto& kv : params->custom_parameters) { + if (kv.first % 31 == 27) { + grease_params.push_back(kv.first); } } - return tls_versions; + EXPECT_EQ(grease_params.size(), 1u); + for (TransportParameters::TransportParameterId param_id : grease_params) { + params->custom_parameters.erase(param_id); + } } } // namespace @@ -122,9 +136,129 @@ class TransportParametersTest : public QuicTestWithParam<ParsedQuicVersion> { INSTANTIATE_TEST_SUITE_P(TransportParametersTests, TransportParametersTest, - ::testing::ValuesIn(AllSupportedTlsVersions()), + ::testing::ValuesIn(AllSupportedVersionsWithTls()), ::testing::PrintToStringParamName()); +TEST_P(TransportParametersTest, Comparator) { + TransportParameters orig_params; + TransportParameters new_params; + // Test comparison on primitive members. + orig_params.perspective = Perspective::IS_CLIENT; + new_params.perspective = Perspective::IS_SERVER; + EXPECT_NE(orig_params, new_params); + EXPECT_FALSE(orig_params == new_params); + EXPECT_TRUE(orig_params != new_params); + new_params.perspective = Perspective::IS_CLIENT; + orig_params.version = kFakeVersionLabel; + new_params.version = kFakeVersionLabel; + orig_params.disable_migration = true; + new_params.disable_migration = true; + EXPECT_EQ(orig_params, new_params); + EXPECT_TRUE(orig_params == new_params); + EXPECT_FALSE(orig_params != new_params); + + // Test comparison on vectors. + orig_params.supported_versions.push_back(kFakeVersionLabel); + new_params.supported_versions.push_back(kFakeVersionLabel2); + EXPECT_NE(orig_params, new_params); + EXPECT_FALSE(orig_params == new_params); + EXPECT_TRUE(orig_params != new_params); + new_params.supported_versions.pop_back(); + new_params.supported_versions.push_back(kFakeVersionLabel); + orig_params.stateless_reset_token = CreateFakeStatelessResetToken(); + new_params.stateless_reset_token = CreateFakeStatelessResetToken(); + EXPECT_EQ(orig_params, new_params); + EXPECT_TRUE(orig_params == new_params); + EXPECT_FALSE(orig_params != new_params); + + // Test comparison on IntegerParameters. + orig_params.max_packet_size.set_value(kFakeMaxPacketSize); + new_params.max_packet_size.set_value(kFakeMaxPacketSize + 1); + EXPECT_NE(orig_params, new_params); + EXPECT_FALSE(orig_params == new_params); + EXPECT_TRUE(orig_params != new_params); + new_params.max_packet_size.set_value(kFakeMaxPacketSize); + EXPECT_EQ(orig_params, new_params); + EXPECT_TRUE(orig_params == new_params); + EXPECT_FALSE(orig_params != new_params); + + // Test comparison on PreferredAddress + orig_params.preferred_address = CreateFakePreferredAddress(); + EXPECT_NE(orig_params, new_params); + EXPECT_FALSE(orig_params == new_params); + EXPECT_TRUE(orig_params != new_params); + new_params.preferred_address = CreateFakePreferredAddress(); + EXPECT_EQ(orig_params, new_params); + EXPECT_TRUE(orig_params == new_params); + EXPECT_FALSE(orig_params != new_params); + + // Test comparison on CryptoHandshakeMessage. + orig_params.google_quic_params = std::make_unique<CryptoHandshakeMessage>(); + const std::string kTestString = "test string"; + orig_params.google_quic_params->SetStringPiece(42, kTestString); + const uint32_t kTestValue = 12; + orig_params.google_quic_params->SetValue(1337, kTestValue); + EXPECT_NE(orig_params, new_params); + EXPECT_FALSE(orig_params == new_params); + EXPECT_TRUE(orig_params != new_params); + + new_params.google_quic_params = std::make_unique<CryptoHandshakeMessage>(); + new_params.google_quic_params->SetStringPiece(42, kTestString); + new_params.google_quic_params->SetValue(1337, kTestValue + 1); + EXPECT_NE(orig_params, new_params); + EXPECT_FALSE(orig_params == new_params); + EXPECT_TRUE(orig_params != new_params); + new_params.google_quic_params->SetValue(1337, kTestValue); + EXPECT_EQ(orig_params, new_params); + EXPECT_TRUE(orig_params == new_params); + EXPECT_FALSE(orig_params != new_params); + + // Test comparison on CustomMap + orig_params.custom_parameters[kCustomParameter1] = kCustomParameter1Value; + orig_params.custom_parameters[kCustomParameter2] = kCustomParameter2Value; + + new_params.custom_parameters[kCustomParameter2] = kCustomParameter2Value; + new_params.custom_parameters[kCustomParameter1] = kCustomParameter1Value; + EXPECT_EQ(orig_params, new_params); + EXPECT_TRUE(orig_params == new_params); + EXPECT_FALSE(orig_params != new_params); +} + +TEST_P(TransportParametersTest, CopyConstructor) { + TransportParameters orig_params; + orig_params.perspective = Perspective::IS_CLIENT; + orig_params.version = kFakeVersionLabel; + orig_params.supported_versions.push_back(kFakeVersionLabel); + orig_params.supported_versions.push_back(kFakeVersionLabel2); + orig_params.original_connection_id = CreateFakeOriginalConnectionId(); + orig_params.idle_timeout_milliseconds.set_value(kFakeIdleTimeoutMilliseconds); + orig_params.stateless_reset_token = CreateFakeStatelessResetToken(); + orig_params.max_packet_size.set_value(kFakeMaxPacketSize); + orig_params.initial_max_data.set_value(kFakeInitialMaxData); + orig_params.initial_max_stream_data_bidi_local.set_value( + kFakeInitialMaxStreamDataBidiLocal); + orig_params.initial_max_stream_data_bidi_remote.set_value( + kFakeInitialMaxStreamDataBidiRemote); + orig_params.initial_max_stream_data_uni.set_value( + kFakeInitialMaxStreamDataUni); + orig_params.initial_max_streams_bidi.set_value(kFakeInitialMaxStreamsBidi); + orig_params.initial_max_streams_uni.set_value(kFakeInitialMaxStreamsUni); + orig_params.ack_delay_exponent.set_value(kFakeAckDelayExponent); + orig_params.max_ack_delay.set_value(kFakeMaxAckDelay); + orig_params.disable_migration = kFakeDisableMigration; + orig_params.preferred_address = CreateFakePreferredAddress(); + orig_params.active_connection_id_limit.set_value( + kFakeActiveConnectionIdLimit); + orig_params.initial_round_trip_time_us.set_value(kFakeInitialRoundTripTime); + orig_params.google_connection_options = CreateFakeGoogleConnectionOptions(); + orig_params.user_agent_id = CreateFakeUserAgentId(); + orig_params.custom_parameters[kCustomParameter1] = kCustomParameter1Value; + orig_params.custom_parameters[kCustomParameter2] = kCustomParameter2Value; + + TransportParameters new_params(orig_params); + EXPECT_EQ(new_params, orig_params); +} + TEST_P(TransportParametersTest, RoundTripClient) { TransportParameters orig_params; orig_params.perspective = Perspective::IS_CLIENT; @@ -145,6 +279,9 @@ TEST_P(TransportParametersTest, RoundTripClient) { orig_params.disable_migration = kFakeDisableMigration; orig_params.active_connection_id_limit.set_value( kFakeActiveConnectionIdLimit); + orig_params.initial_round_trip_time_us.set_value(kFakeInitialRoundTripTime); + orig_params.google_connection_options = CreateFakeGoogleConnectionOptions(); + orig_params.user_agent_id = CreateFakeUserAgentId(); orig_params.custom_parameters[kCustomParameter1] = kCustomParameter1Value; orig_params.custom_parameters[kCustomParameter2] = kCustomParameter2Value; @@ -158,34 +295,8 @@ TEST_P(TransportParametersTest, RoundTripClient) { &new_params, &error_details)) << error_details; EXPECT_TRUE(error_details.empty()); - EXPECT_EQ(Perspective::IS_CLIENT, new_params.perspective); - EXPECT_EQ(kFakeVersionLabel, new_params.version); - EXPECT_TRUE(new_params.supported_versions.empty()); - EXPECT_EQ(EmptyQuicConnectionId(), new_params.original_connection_id); - EXPECT_EQ(kFakeIdleTimeoutMilliseconds, - new_params.idle_timeout_milliseconds.value()); - EXPECT_TRUE(new_params.stateless_reset_token.empty()); - EXPECT_EQ(kFakeMaxPacketSize, new_params.max_packet_size.value()); - EXPECT_EQ(kFakeInitialMaxData, new_params.initial_max_data.value()); - EXPECT_EQ(kFakeInitialMaxStreamDataBidiLocal, - new_params.initial_max_stream_data_bidi_local.value()); - EXPECT_EQ(kFakeInitialMaxStreamDataBidiRemote, - new_params.initial_max_stream_data_bidi_remote.value()); - EXPECT_EQ(kFakeInitialMaxStreamDataUni, - new_params.initial_max_stream_data_uni.value()); - EXPECT_EQ(kFakeInitialMaxStreamsBidi, - new_params.initial_max_streams_bidi.value()); - EXPECT_EQ(kFakeInitialMaxStreamsUni, - new_params.initial_max_streams_uni.value()); - EXPECT_EQ(kFakeAckDelayExponent, new_params.ack_delay_exponent.value()); - EXPECT_EQ(kFakeMaxAckDelay, new_params.max_ack_delay.value()); - EXPECT_EQ(kFakeDisableMigration, new_params.disable_migration); - EXPECT_EQ(kFakeActiveConnectionIdLimit, - new_params.active_connection_id_limit.value()); - EXPECT_THAT( - new_params.custom_parameters, - UnorderedElementsAre(Pair(kCustomParameter1, kCustomParameter1Value), - Pair(kCustomParameter2, kCustomParameter2Value))); + RemoveGreaseParameters(&new_params); + EXPECT_EQ(new_params, orig_params); } TEST_P(TransportParametersTest, RoundTripServer) { @@ -213,6 +324,7 @@ TEST_P(TransportParametersTest, RoundTripServer) { orig_params.preferred_address = CreateFakePreferredAddress(); orig_params.active_connection_id_limit.set_value( kFakeActiveConnectionIdLimit); + orig_params.google_connection_options = CreateFakeGoogleConnectionOptions(); std::vector<uint8_t> serialized; ASSERT_TRUE(SerializeTransportParameters(version_, orig_params, &serialized)); @@ -224,43 +336,8 @@ TEST_P(TransportParametersTest, RoundTripServer) { &new_params, &error_details)) << error_details; EXPECT_TRUE(error_details.empty()); - EXPECT_EQ(Perspective::IS_SERVER, new_params.perspective); - EXPECT_EQ(kFakeVersionLabel, new_params.version); - EXPECT_EQ(2u, new_params.supported_versions.size()); - EXPECT_EQ(kFakeVersionLabel, new_params.supported_versions[0]); - EXPECT_EQ(kFakeVersionLabel2, new_params.supported_versions[1]); - EXPECT_EQ(CreateFakeOriginalConnectionId(), - new_params.original_connection_id); - EXPECT_EQ(kFakeIdleTimeoutMilliseconds, - new_params.idle_timeout_milliseconds.value()); - EXPECT_EQ(CreateFakeStatelessResetToken(), new_params.stateless_reset_token); - EXPECT_EQ(kFakeMaxPacketSize, new_params.max_packet_size.value()); - EXPECT_EQ(kFakeInitialMaxData, new_params.initial_max_data.value()); - EXPECT_EQ(kFakeInitialMaxStreamDataBidiLocal, - new_params.initial_max_stream_data_bidi_local.value()); - EXPECT_EQ(kFakeInitialMaxStreamDataBidiRemote, - new_params.initial_max_stream_data_bidi_remote.value()); - EXPECT_EQ(kFakeInitialMaxStreamDataUni, - new_params.initial_max_stream_data_uni.value()); - EXPECT_EQ(kFakeInitialMaxStreamsBidi, - new_params.initial_max_streams_bidi.value()); - EXPECT_EQ(kFakeInitialMaxStreamsUni, - new_params.initial_max_streams_uni.value()); - EXPECT_EQ(kFakeAckDelayExponent, new_params.ack_delay_exponent.value()); - EXPECT_EQ(kFakeMaxAckDelay, new_params.max_ack_delay.value()); - EXPECT_EQ(kFakeDisableMigration, new_params.disable_migration); - ASSERT_NE(nullptr, new_params.preferred_address.get()); - EXPECT_EQ(CreateFakeV4SocketAddress(), - new_params.preferred_address->ipv4_socket_address); - EXPECT_EQ(CreateFakeV6SocketAddress(), - new_params.preferred_address->ipv6_socket_address); - EXPECT_EQ(CreateFakePreferredConnectionId(), - new_params.preferred_address->connection_id); - EXPECT_EQ(CreateFakePreferredStatelessResetToken(), - new_params.preferred_address->stateless_reset_token); - EXPECT_EQ(kFakeActiveConnectionIdLimit, - new_params.active_connection_id_limit.value()); - EXPECT_EQ(0u, new_params.custom_parameters.size()); + RemoveGreaseParameters(&new_params); + EXPECT_EQ(new_params, orig_params); } TEST_P(TransportParametersTest, AreValid) { @@ -330,6 +407,29 @@ TEST_P(TransportParametersTest, AreValid) { "Invalid transport parameters [Client ack_delay_exponent 21 " "(Invalid)]"); } + { + TransportParameters params; + std::string error_details; + params.perspective = Perspective::IS_CLIENT; + EXPECT_TRUE(params.AreValid(&error_details)); + EXPECT_TRUE(error_details.empty()); + params.active_connection_id_limit.set_value(2); + EXPECT_TRUE(params.AreValid(&error_details)); + EXPECT_TRUE(error_details.empty()); + params.active_connection_id_limit.set_value(999999); + EXPECT_TRUE(params.AreValid(&error_details)); + EXPECT_TRUE(error_details.empty()); + params.active_connection_id_limit.set_value(1); + EXPECT_FALSE(params.AreValid(&error_details)); + EXPECT_EQ(error_details, + "Invalid transport parameters [Client active_connection_id_limit" + " 1 (Invalid)]"); + params.active_connection_id_limit.set_value(0); + EXPECT_FALSE(params.AreValid(&error_details)); + EXPECT_EQ(error_details, + "Invalid transport parameters [Client active_connection_id_limit" + " 0 (Invalid)]"); + } } TEST_P(TransportParametersTest, NoClientParamsWithStatelessResetToken) { @@ -352,7 +452,7 @@ TEST_P(TransportParametersTest, NoClientParamsWithStatelessResetToken) { TEST_P(TransportParametersTest, ParseClientParams) { // clang-format off const uint8_t kClientParamsOld[] = { - 0x00, 0x49, // length of the parameters array that follows + 0x00, 0x6a, // length of the parameters array that follows // idle_timeout 0x00, 0x01, // parameter id 0x00, 0x02, // length @@ -400,6 +500,20 @@ TEST_P(TransportParametersTest, ParseClientParams) { 0x00, 0x0e, // parameter id 0x00, 0x01, // length 0x34, // value + // initial_round_trip_time_us + 0x31, 0x27, // parameter id + 0x00, 0x01, // length + 0x35, // value + // google_connection_options + 0x31, 0x28, // parameter id + 0x00, 0x0c, // length + 'A', 'L', 'P', 'N', // value + 'E', 'F', 'G', 0x00, + 'H', 'I', 'J', 0xff, + // user_agent_id + 0x31, 0x29, // parameter id + 0x00, 0x08, // length + 'F', 'a', 'k', 'e', 'U', 'A', 'I', 'D', // value // Google version extension 0x47, 0x52, // parameter id 0x00, 0x04, // length @@ -453,6 +567,20 @@ TEST_P(TransportParametersTest, ParseClientParams) { 0x0e, // parameter id 0x01, // length 0x34, // value + // initial_round_trip_time_us + 0x71, 0x27, // parameter id + 0x01, // length + 0x35, // value + // google_connection_options + 0x71, 0x28, // parameter id + 0x0c, // length + 'A', 'L', 'P', 'N', // value + 'E', 'F', 'G', 0x00, + 'H', 'I', 'J', 0xff, + // user_agent_id + 0x71, 0x29, // parameter id + 0x08, // length + 'F', 'a', 'k', 'e', 'U', 'A', 'I', 'D', // value // Google version extension 0x80, 0x00, 0x47, 0x52, // parameter id 0x04, // length @@ -476,7 +604,7 @@ TEST_P(TransportParametersTest, ParseClientParams) { EXPECT_EQ(Perspective::IS_CLIENT, new_params.perspective); EXPECT_EQ(kFakeVersionLabel, new_params.version); EXPECT_TRUE(new_params.supported_versions.empty()); - EXPECT_EQ(EmptyQuicConnectionId(), new_params.original_connection_id); + EXPECT_FALSE(new_params.original_connection_id.has_value()); EXPECT_EQ(kFakeIdleTimeoutMilliseconds, new_params.idle_timeout_milliseconds.value()); EXPECT_TRUE(new_params.stateless_reset_token.empty()); @@ -497,6 +625,13 @@ TEST_P(TransportParametersTest, ParseClientParams) { EXPECT_EQ(kFakeDisableMigration, new_params.disable_migration); EXPECT_EQ(kFakeActiveConnectionIdLimit, new_params.active_connection_id_limit.value()); + EXPECT_EQ(kFakeInitialRoundTripTime, + new_params.initial_round_trip_time_us.value()); + ASSERT_TRUE(new_params.google_connection_options.has_value()); + EXPECT_EQ(CreateFakeGoogleConnectionOptions(), + new_params.google_connection_options.value()); + ASSERT_TRUE(new_params.user_agent_id.has_value()); + EXPECT_EQ(CreateFakeUserAgentId(), new_params.user_agent_id.value()); } TEST_P(TransportParametersTest, @@ -664,7 +799,7 @@ TEST_P(TransportParametersTest, ParseClientParametersRepeated) { TEST_P(TransportParametersTest, ParseServerParams) { // clang-format off const uint8_t kServerParamsOld[] = { - 0x00, 0xa7, // length of parameters array that follows + 0x00, 0xb7, // length of parameters array that follows // original_connection_id 0x00, 0x00, // parameter id 0x00, 0x08, // length @@ -733,6 +868,12 @@ TEST_P(TransportParametersTest, ParseServerParams) { 0x00, 0x0e, // parameter id 0x00, 0x01, // length 0x34, // value + // google_connection_options + 0x31, 0x28, // parameter id + 0x00, 0x0c, // length + 'A', 'L', 'P', 'N', // value + 'E', 'F', 'G', 0x00, + 'H', 'I', 'J', 0xff, // Google version extension 0x47, 0x52, // parameter id 0x00, 0x0d, // length @@ -810,6 +951,12 @@ TEST_P(TransportParametersTest, ParseServerParams) { 0x0e, // parameter id 0x01, // length 0x34, // value + // google_connection_options + 0x71, 0x28, // parameter id + 0x0c, // length + 'A', 'L', 'P', 'N', // value + 'E', 'F', 'G', 0x00, + 'H', 'I', 'J', 0xff, // Google version extension 0x80, 0x00, 0x47, 0x52, // parameter id 0x0d, // length @@ -838,8 +985,9 @@ TEST_P(TransportParametersTest, ParseServerParams) { EXPECT_EQ(2u, new_params.supported_versions.size()); EXPECT_EQ(kFakeVersionLabel, new_params.supported_versions[0]); EXPECT_EQ(kFakeVersionLabel2, new_params.supported_versions[1]); + ASSERT_TRUE(new_params.original_connection_id.has_value()); EXPECT_EQ(CreateFakeOriginalConnectionId(), - new_params.original_connection_id); + new_params.original_connection_id.value()); EXPECT_EQ(kFakeIdleTimeoutMilliseconds, new_params.idle_timeout_milliseconds.value()); EXPECT_EQ(CreateFakeStatelessResetToken(), new_params.stateless_reset_token); @@ -869,6 +1017,10 @@ TEST_P(TransportParametersTest, ParseServerParams) { new_params.preferred_address->stateless_reset_token); EXPECT_EQ(kFakeActiveConnectionIdLimit, new_params.active_connection_id_limit.value()); + ASSERT_TRUE(new_params.google_connection_options.has_value()); + EXPECT_EQ(CreateFakeGoogleConnectionOptions(), + new_params.google_connection_options.value()); + EXPECT_FALSE(new_params.user_agent_id.has_value()); } TEST_P(TransportParametersTest, ParseServerParametersRepeated) { @@ -928,6 +1080,59 @@ TEST_P(TransportParametersTest, ParseServerParametersRepeated) { EXPECT_EQ(error_details, "Received a second idle_timeout"); } +TEST_P(TransportParametersTest, + ParseServerParametersEmptyOriginalConnectionId) { + // clang-format off + const uint8_t kServerParamsEmptyOriginalConnectionIdOld[] = { + 0x00, 0x1e, // length of parameters array that follows + // original_connection_id + 0x00, 0x00, // parameter id + 0x00, 0x00, // length + // idle_timeout + 0x00, 0x01, // parameter id + 0x00, 0x02, // length + 0x6e, 0xec, // value + // stateless_reset_token + 0x00, 0x02, // parameter id + 0x00, 0x10, // length + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + }; + const uint8_t kServerParamsEmptyOriginalConnectionId[] = { + // original_connection_id + 0x00, // parameter id + 0x00, // length + // idle_timeout + 0x01, // parameter id + 0x02, // length + 0x6e, 0xec, // value + // stateless_reset_token + 0x02, // parameter id + 0x10, // length + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + }; + // clang-format on + const uint8_t* server_params = + reinterpret_cast<const uint8_t*>(kServerParamsEmptyOriginalConnectionId); + size_t server_params_length = + QUICHE_ARRAYSIZE(kServerParamsEmptyOriginalConnectionId); + if (!version_.HasVarIntTransportParams()) { + server_params = reinterpret_cast<const uint8_t*>( + kServerParamsEmptyOriginalConnectionIdOld); + server_params_length = + QUICHE_ARRAYSIZE(kServerParamsEmptyOriginalConnectionIdOld); + } + TransportParameters out_params; + std::string error_details; + ASSERT_TRUE(ParseTransportParameters(version_, Perspective::IS_SERVER, + server_params, server_params_length, + &out_params, &error_details)) + << error_details; + ASSERT_TRUE(out_params.original_connection_id.has_value()); + EXPECT_EQ(out_params.original_connection_id.value(), EmptyQuicConnectionId()); +} + TEST_P(TransportParametersTest, CryptoHandshakeMessageRoundtrip) { TransportParameters orig_params; orig_params.perspective = Perspective::IS_CLIENT; diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frame.cc index 2946c01af8b..3fd3dea6120 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frame.cc @@ -26,12 +26,7 @@ bool IsAwaitingPacket(const QuicAckFrame& ack_frame, !ack_frame.packets.Contains(packet_number); } -QuicAckFrame::QuicAckFrame() - : ack_delay_time(QuicTime::Delta::Infinite()), - ecn_counters_populated(false), - ect_0_count(0), - ect_1_count(0), - ecn_ce_count(0) {} +QuicAckFrame::QuicAckFrame() = default; QuicAckFrame::QuicAckFrame(const QuicAckFrame& other) = default; diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frame.h index 9003c76e3d3..69023404db3 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frame.h +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frame.h @@ -108,7 +108,7 @@ struct QUIC_EXPORT_PRIVATE QuicAckFrame { // Time elapsed since largest_observed() was received until this Ack frame was // sent. - QuicTime::Delta ack_delay_time; + QuicTime::Delta ack_delay_time = QuicTime::Delta::Infinite(); // Vector of <packet_number, time> for when packets arrived. PacketTimeVector received_packet_times; @@ -118,10 +118,10 @@ struct QUIC_EXPORT_PRIVATE QuicAckFrame { // ECN counters, used only in version 99's ACK frame and valid only when // |ecn_counters_populated| is true. - bool ecn_counters_populated; - QuicPacketCount ect_0_count; - QuicPacketCount ect_1_count; - QuicPacketCount ecn_ce_count; + bool ecn_counters_populated = false; + QuicPacketCount ect_0_count = 0; + QuicPacketCount ect_1_count = 0; + QuicPacketCount ecn_ce_count = 0; }; // The highest acked packet number we've observed from the peer. If no packets diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_blocked_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_blocked_frame.cc index 41ba1443ce9..1da520e03b0 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_blocked_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_blocked_frame.cc @@ -3,13 +3,9 @@ // found in the LICENSE file. #include "net/third_party/quiche/src/quic/core/frames/quic_blocked_frame.h" -#include "net/third_party/quiche/src/quic/core/quic_constants.h" namespace quic { -QuicBlockedFrame::QuicBlockedFrame() - : control_frame_id(kInvalidControlFrameId), stream_id(0), offset(0) {} - QuicBlockedFrame::QuicBlockedFrame(QuicControlFrameId control_frame_id, QuicStreamId stream_id) : control_frame_id(control_frame_id), stream_id(stream_id), offset(0) {} diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_blocked_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_blocked_frame.h index 30dcdf4ca05..64f3aeed477 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_blocked_frame.h +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_blocked_frame.h @@ -7,6 +7,7 @@ #include <ostream> +#include "net/third_party/quiche/src/quic/core/quic_constants.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" namespace quic { @@ -16,7 +17,7 @@ namespace quic { // send data. The BLOCKED frame is purely advisory and optional. // Based on SPDY's BLOCKED frame (undocumented as of 2014-01-28). struct QUIC_EXPORT_PRIVATE QuicBlockedFrame { - QuicBlockedFrame(); + QuicBlockedFrame() = default; QuicBlockedFrame(QuicControlFrameId control_frame_id, QuicStreamId stream_id); QuicBlockedFrame(QuicControlFrameId control_frame_id, QuicStreamId stream_id, @@ -28,7 +29,7 @@ struct QUIC_EXPORT_PRIVATE QuicBlockedFrame { // A unique identifier of this control frame. 0 when this frame is received, // and non-zero when sent. - QuicControlFrameId control_frame_id; + QuicControlFrameId control_frame_id = kInvalidControlFrameId; // 0 is a special case meaning the connection is blocked, rather than a // stream. So stream_id 0 corresponds to a BLOCKED frame and non-0 @@ -36,10 +37,10 @@ struct QUIC_EXPORT_PRIVATE QuicBlockedFrame { // TODO(fkastenholz): This should be converted to use // QuicUtils::GetInvalidStreamId to get the correct invalid stream id value // and not rely on 0. - QuicStreamId stream_id; + QuicStreamId stream_id = 0; // For Google QUIC, the offset is ignored. - QuicStreamOffset offset; + QuicStreamOffset offset = 0; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.cc index 35aedf4a292..e1b9302ceb4 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.cc @@ -7,60 +7,55 @@ #include <memory> #include "net/third_party/quiche/src/quic/core/quic_constants.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" namespace quic { -QuicConnectionCloseFrame::QuicConnectionCloseFrame() - // Default close type ensures that existing, pre-V99 code works as expected. - : close_type(GOOGLE_QUIC_CONNECTION_CLOSE), - quic_error_code(QUIC_NO_ERROR), - extracted_error_code(QUIC_NO_ERROR), - transport_close_frame_type(0) {} QuicConnectionCloseFrame::QuicConnectionCloseFrame( QuicTransportVersion transport_version, QuicErrorCode error_code, std::string error_phrase, uint64_t frame_type) - : extracted_error_code(error_code), error_details(error_phrase) { + : quic_error_code(error_code), error_details(error_phrase) { if (!VersionHasIetfQuicFrames(transport_version)) { close_type = GOOGLE_QUIC_CONNECTION_CLOSE; - quic_error_code = error_code; + wire_error_code = error_code; transport_close_frame_type = 0; return; } QuicErrorCodeToIetfMapping mapping = QuicErrorCodeToTransportErrorCode(error_code); - if (mapping.is_transport_close_) { + wire_error_code = mapping.error_code; + if (mapping.is_transport_close) { // Maps to a transport close close_type = IETF_QUIC_TRANSPORT_CONNECTION_CLOSE; - transport_error_code = mapping.transport_error_code_; transport_close_frame_type = frame_type; return; } // Maps to an application close. close_type = IETF_QUIC_APPLICATION_CONNECTION_CLOSE; - application_error_code = mapping.application_error_code_; transport_close_frame_type = 0; } std::ostream& operator<<( std::ostream& os, const QuicConnectionCloseFrame& connection_close_frame) { - os << "{ Close type: " << connection_close_frame.close_type - << ", error_code: "; + os << "{ Close type: " << connection_close_frame.close_type; switch (connection_close_frame.close_type) { case IETF_QUIC_TRANSPORT_CONNECTION_CLOSE: - os << connection_close_frame.transport_error_code; + os << ", wire_error_code: " + << static_cast<QuicIetfTransportErrorCodes>( + connection_close_frame.wire_error_code); break; case IETF_QUIC_APPLICATION_CONNECTION_CLOSE: - os << connection_close_frame.application_error_code; + os << ", wire_error_code: " << connection_close_frame.wire_error_code; break; case GOOGLE_QUIC_CONNECTION_CLOSE: - os << connection_close_frame.quic_error_code; + // Do not log, value same as |quic_error_code|. break; } - os << ", extracted_error_code: " - << QuicErrorCodeToString(connection_close_frame.extracted_error_code) + os << ", quic_error_code: " + << QuicErrorCodeToString(connection_close_frame.quic_error_code) << ", error_details: '" << connection_close_frame.error_details << "'"; if (connection_close_frame.close_type == IETF_QUIC_TRANSPORT_CONNECTION_CLOSE) { diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.h index 4ee41b97fd9..de40dadc860 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.h +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.h @@ -16,7 +16,7 @@ namespace quic { struct QUIC_EXPORT_PRIVATE QuicConnectionCloseFrame { - QuicConnectionCloseFrame(); + QuicConnectionCloseFrame() = default; // Builds a connection close frame based on the transport version // and the mapping of error_code. THIS IS THE PREFERRED C'TOR @@ -31,33 +31,25 @@ struct QUIC_EXPORT_PRIVATE QuicConnectionCloseFrame { std::ostream& os, const QuicConnectionCloseFrame& c); - // Indicates whether the received CONNECTION_CLOSE frame is a Google QUIC - // CONNECTION_CLOSE, IETF QUIC CONNECTION_CLOSE. - QuicConnectionCloseType close_type; + // Indicates whether the the frame is a Google QUIC CONNECTION_CLOSE frame, + // an IETF QUIC CONNECTION_CLOSE frame with transport error code, + // or an IETF QUIC CONNECTION_CLOSE frame with application error code. + QuicConnectionCloseType close_type = GOOGLE_QUIC_CONNECTION_CLOSE; - // This is the error field in the frame. - // The CONNECTION_CLOSE frame reports an error code: - // - The transport error code as reported in a CONNECTION_CLOSE/Transport - // frame (serialized as a VarInt), - // - An opaque 64-bit code as reported in CONNECTION_CLOSE/Application frames - // (serialized as a VarInt),, - // - A 16 bit QuicErrorCode, which is used in Google QUIC. - union { - QuicIetfTransportErrorCodes transport_error_code; - uint64_t application_error_code; - QuicErrorCode quic_error_code; - }; + // The error code on the wire. For Google QUIC frames, this has the same + // value as |quic_error_code|. + uint64_t wire_error_code = QUIC_NO_ERROR; - // For IETF QUIC frames, this is the error code is extracted from, or added - // to, the error details text. For received Google QUIC frames, the Google - // QUIC error code from the frame's error code field is copied here (as well - // as in quic_error_code, above). - QuicErrorCode extracted_error_code; + // The underlying error. For Google QUIC frames, this has the same value as + // |wire_error_code|. For sent IETF QUIC frames, this is the error that + // triggered the closure of the connection. For received IETF QUIC frames, + // this is parsed from the Reason Phrase field of the CONNECTION_CLOSE frame, + // or QUIC_IETF_GQUIC_ERROR_MISSING. + QuicErrorCode quic_error_code = QUIC_NO_ERROR; - // String with additional error details. "QuicErrorCode: 123" will be appended - // to the error details when sending IETF QUIC Connection Close and - // Application Close frames and parsed into extracted_error_code upon receipt, - // when present. + // String with additional error details. |quic_error_code| and a colon will be + // prepended to the error details when sending IETF QUIC frames, and parsed + // into |quic_error_code| upon receipt, when present. std::string error_details; // The frame type present in the IETF transport connection close frame. @@ -65,7 +57,7 @@ struct QUIC_EXPORT_PRIVATE QuicConnectionCloseFrame { // Contains the type of frame that triggered the connection close. Made a // uint64, as opposed to the QuicIetfFrameType, to support possible // extensions as well as reporting invalid frame types received from the peer. - uint64_t transport_close_frame_type; + uint64_t transport_close_frame_type = 0; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.cc index d750da76939..81b3e18a6b2 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.cc @@ -9,9 +9,6 @@ namespace quic { -QuicCryptoFrame::QuicCryptoFrame() - : QuicCryptoFrame(ENCRYPTION_INITIAL, 0, nullptr, 0) {} - QuicCryptoFrame::QuicCryptoFrame(EncryptionLevel level, QuicStreamOffset offset, QuicPacketLength data_length) @@ -35,7 +32,7 @@ QuicCryptoFrame::~QuicCryptoFrame() {} std::ostream& operator<<(std::ostream& os, const QuicCryptoFrame& stream_frame) { - os << "{ level: " << static_cast<int>(stream_frame.level) + os << "{ level: " << EncryptionLevelToString(stream_frame.level) << ", offset: " << stream_frame.offset << ", length: " << stream_frame.data_length << " }\n"; return os; diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.h index 28434cb6362..2bb7a08d68a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.h +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.h @@ -16,7 +16,7 @@ namespace quic { struct QUIC_EXPORT_PRIVATE QuicCryptoFrame { - QuicCryptoFrame(); + QuicCryptoFrame() = default; QuicCryptoFrame(EncryptionLevel level, QuicStreamOffset offset, QuicPacketLength data_length); @@ -31,12 +31,12 @@ struct QUIC_EXPORT_PRIVATE QuicCryptoFrame { // When writing a crypto frame to a packet, the packet must be encrypted at // |level|. When a crypto frame is read, the encryption level of the packet it // was received in is put in |level|. - EncryptionLevel level; - QuicPacketLength data_length; + EncryptionLevel level = ENCRYPTION_INITIAL; + QuicPacketLength data_length = 0; // When reading, |data_buffer| points to the data that was received in the // frame. |data_buffer| is not used when writing. - const char* data_buffer; - QuicStreamOffset offset; // Location of this data in the stream. + const char* data_buffer = nullptr; + QuicStreamOffset offset = 0; // Location of this data in the stream. QuicCryptoFrame(EncryptionLevel level, QuicStreamOffset offset, diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frames_test.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frames_test.cc index 7450adb5d2c..22322ed8ee2 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frames_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frames_test.cc @@ -147,11 +147,9 @@ TEST_F(QuicFramesTest, ConnectionCloseFrameToString) { // indicating that, in fact, no extended error code was available from the // underlying frame. EXPECT_EQ( - "{ Close type: GOOGLE_QUIC_CONNECTION_CLOSE, error_code: 25, " - "extracted_error_code: QUIC_NO_ERROR, " - "error_details: 'No recent " - "network activity.'" - "}\n", + "{ Close type: GOOGLE_QUIC_CONNECTION_CLOSE, " + "quic_error_code: QUIC_NETWORK_IDLE_TIMEOUT, " + "error_details: 'No recent network activity.'}\n", stream.str()); QuicFrame quic_frame(&frame); EXPECT_FALSE(IsControlFrame(quic_frame.type)); @@ -160,16 +158,16 @@ TEST_F(QuicFramesTest, ConnectionCloseFrameToString) { TEST_F(QuicFramesTest, TransportConnectionCloseFrameToString) { QuicConnectionCloseFrame frame; frame.close_type = IETF_QUIC_TRANSPORT_CONNECTION_CLOSE; - frame.transport_error_code = FINAL_SIZE_ERROR; - frame.extracted_error_code = QUIC_NETWORK_IDLE_TIMEOUT; + frame.wire_error_code = FINAL_SIZE_ERROR; + frame.quic_error_code = QUIC_NETWORK_IDLE_TIMEOUT; frame.error_details = "No recent network activity."; frame.transport_close_frame_type = IETF_STREAM; std::ostringstream stream; stream << frame; EXPECT_EQ( - "{ Close type: IETF_QUIC_TRANSPORT_CONNECTION_CLOSE, error_code: " - "FINAL_SIZE_ERROR, " - "extracted_error_code: QUIC_NETWORK_IDLE_TIMEOUT, " + "{ Close type: IETF_QUIC_TRANSPORT_CONNECTION_CLOSE, " + "wire_error_code: FINAL_SIZE_ERROR, " + "quic_error_code: QUIC_NETWORK_IDLE_TIMEOUT, " "error_details: 'No recent " "network activity.', " "frame_type: IETF_STREAM" diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_goaway_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_goaway_frame.cc index 3842f92690e..4c8848d1738 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_goaway_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_goaway_frame.cc @@ -5,15 +5,9 @@ #include <string> #include "net/third_party/quiche/src/quic/core/frames/quic_goaway_frame.h" -#include "net/third_party/quiche/src/quic/core/quic_constants.h" namespace quic { -QuicGoAwayFrame::QuicGoAwayFrame() - : control_frame_id(kInvalidControlFrameId), - error_code(QUIC_NO_ERROR), - last_good_stream_id(0) {} - QuicGoAwayFrame::QuicGoAwayFrame(QuicControlFrameId control_frame_id, QuicErrorCode error_code, QuicStreamId last_good_stream_id, diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_goaway_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_goaway_frame.h index ecceee6fc0e..b642cfa0372 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_goaway_frame.h +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_goaway_frame.h @@ -8,13 +8,14 @@ #include <ostream> #include <string> +#include "net/third_party/quiche/src/quic/core/quic_constants.h" #include "net/third_party/quiche/src/quic/core/quic_error_codes.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" namespace quic { struct QUIC_EXPORT_PRIVATE QuicGoAwayFrame { - QuicGoAwayFrame(); + QuicGoAwayFrame() = default; QuicGoAwayFrame(QuicControlFrameId control_frame_id, QuicErrorCode error_code, QuicStreamId last_good_stream_id, @@ -25,9 +26,9 @@ struct QUIC_EXPORT_PRIVATE QuicGoAwayFrame { // A unique identifier of this control frame. 0 when this frame is received, // and non-zero when sent. - QuicControlFrameId control_frame_id; - QuicErrorCode error_code; - QuicStreamId last_good_stream_id; + QuicControlFrameId control_frame_id = kInvalidControlFrameId; + QuicErrorCode error_code = QUIC_NO_ERROR; + QuicStreamId last_good_stream_id = 0; std::string reason_phrase; }; diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_handshake_done_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_handshake_done_frame.cc index 6f411a50188..f4a97c1d2e6 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_handshake_done_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_handshake_done_frame.cc @@ -7,8 +7,7 @@ namespace quic { QuicHandshakeDoneFrame::QuicHandshakeDoneFrame() - : QuicInlinedFrame(HANDSHAKE_DONE_FRAME), - control_frame_id(kInvalidControlFrameId) {} + : QuicInlinedFrame(HANDSHAKE_DONE_FRAME) {} QuicHandshakeDoneFrame::QuicHandshakeDoneFrame( QuicControlFrameId control_frame_id) diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_handshake_done_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_handshake_done_frame.h index 48aa3c774a3..c16c169f6a5 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_handshake_done_frame.h +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_handshake_done_frame.h @@ -25,7 +25,7 @@ struct QUIC_EXPORT_PRIVATE QuicHandshakeDoneFrame // A unique identifier of this control frame. 0 when this frame is received, // and non-zero when sent. - QuicControlFrameId control_frame_id; + QuicControlFrameId control_frame_id = kInvalidControlFrameId; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.cc index 6301e72c28f..1726080e2e1 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.cc @@ -7,10 +7,7 @@ namespace quic { QuicMaxStreamsFrame::QuicMaxStreamsFrame() - : QuicInlinedFrame(MAX_STREAMS_FRAME), - control_frame_id(kInvalidControlFrameId), - stream_count(0), - unidirectional(false) {} + : QuicInlinedFrame(MAX_STREAMS_FRAME) {} QuicMaxStreamsFrame::QuicMaxStreamsFrame(QuicControlFrameId control_frame_id, QuicStreamCount stream_count, diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.h index f8c78f9afd4..e1595c046b0 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.h +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.h @@ -30,12 +30,12 @@ struct QUIC_EXPORT_PRIVATE QuicMaxStreamsFrame // A unique identifier of this control frame. 0 when this frame is received, // and non-zero when sent. - QuicControlFrameId control_frame_id; + QuicControlFrameId control_frame_id = kInvalidControlFrameId; // The number of streams that may be opened. - QuicStreamCount stream_count; + QuicStreamCount stream_count = 0; // Whether uni- or bi-directional streams - bool unidirectional; + bool unidirectional = false; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_message_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_message_frame.cc index 196f6e90f95..45748ad0180 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_message_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_message_frame.cc @@ -10,9 +10,6 @@ namespace quic { -QuicMessageFrame::QuicMessageFrame() - : message_id(0), data(nullptr), message_length(0) {} - QuicMessageFrame::QuicMessageFrame(QuicMessageId message_id) : message_id(message_id), data(nullptr), message_length(0) {} diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_message_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_message_frame.h index 5f285135e10..7f0179c95a9 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_message_frame.h +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_message_frame.h @@ -16,7 +16,7 @@ namespace quic { typedef QuicInlinedVector<QuicMemSlice, 1> QuicMessageData; struct QUIC_EXPORT_PRIVATE QuicMessageFrame { - QuicMessageFrame(); + QuicMessageFrame() = default; explicit QuicMessageFrame(QuicMessageId message_id); QuicMessageFrame(QuicMessageId message_id, QuicMemSliceSpan span); QuicMessageFrame(const char* data, QuicPacketLength length); @@ -35,11 +35,11 @@ struct QUIC_EXPORT_PRIVATE QuicMessageFrame { // message_id is only used on the sender side and does not get serialized on // wire. - QuicMessageId message_id; + QuicMessageId message_id = 0; // Not owned, only used on read path. - const char* data; + const char* data = nullptr; // Total length of message_data, must be fit into one packet. - QuicPacketLength message_length; + QuicPacketLength message_length = 0; // The actual message data which is reference counted, used on write path. QuicMessageData message_data; diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_connection_id_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_connection_id_frame.cc index f6c86617a67..d2e8cea2ad2 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_connection_id_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_connection_id_frame.cc @@ -3,15 +3,9 @@ // found in the LICENSE file. #include "net/third_party/quiche/src/quic/core/frames/quic_new_connection_id_frame.h" -#include "net/third_party/quiche/src/quic/core/quic_constants.h" namespace quic { -QuicNewConnectionIdFrame::QuicNewConnectionIdFrame() - : control_frame_id(kInvalidControlFrameId), - connection_id(EmptyQuicConnectionId()), - sequence_number(0) {} - QuicNewConnectionIdFrame::QuicNewConnectionIdFrame( QuicControlFrameId control_frame_id, QuicConnectionId connection_id, diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_connection_id_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_connection_id_frame.h index 441ca1aaf4d..7bd45865f47 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_connection_id_frame.h +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_connection_id_frame.h @@ -7,6 +7,8 @@ #include <ostream> +#include "net/third_party/quiche/src/quic/core/quic_connection_id.h" +#include "net/third_party/quiche/src/quic/core/quic_constants.h" #include "net/third_party/quiche/src/quic/core/quic_error_codes.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/platform/api/quic_uint128.h" @@ -14,7 +16,7 @@ namespace quic { struct QUIC_EXPORT_PRIVATE QuicNewConnectionIdFrame { - QuicNewConnectionIdFrame(); + QuicNewConnectionIdFrame() = default; QuicNewConnectionIdFrame(QuicControlFrameId control_frame_id, QuicConnectionId connection_id, QuicConnectionIdSequenceNumber sequence_number, @@ -27,9 +29,9 @@ struct QUIC_EXPORT_PRIVATE QuicNewConnectionIdFrame { // A unique identifier of this control frame. 0 when this frame is received, // and non-zero when sent. - QuicControlFrameId control_frame_id; - QuicConnectionId connection_id; - QuicConnectionIdSequenceNumber sequence_number; + QuicControlFrameId control_frame_id = kInvalidControlFrameId; + QuicConnectionId connection_id = EmptyQuicConnectionId(); + QuicConnectionIdSequenceNumber sequence_number = 0; QuicUint128 stateless_reset_token; uint64_t retire_prior_to; }; diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.cc index 2dfb97f9017..0178422526c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.cc @@ -4,15 +4,11 @@ #include "net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.h" -#include "net/third_party/quiche/src/quic/core/quic_constants.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" #include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h" namespace quic { -QuicNewTokenFrame::QuicNewTokenFrame() - : control_frame_id(kInvalidControlFrameId) {} - QuicNewTokenFrame::QuicNewTokenFrame(QuicControlFrameId control_frame_id, std::string token) : control_frame_id(control_frame_id), token(token) {} diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.h index 0491477a2dd..abb0eecb2fb 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.h +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.h @@ -9,13 +9,14 @@ #include <ostream> #include "net/third_party/quiche/src/quic/core/quic_buffer_allocator.h" +#include "net/third_party/quiche/src/quic/core/quic_constants.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" namespace quic { struct QUIC_EXPORT_PRIVATE QuicNewTokenFrame { - QuicNewTokenFrame(); + QuicNewTokenFrame() = default; QuicNewTokenFrame(QuicControlFrameId control_frame_id, std::string token); friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( @@ -24,7 +25,7 @@ struct QUIC_EXPORT_PRIVATE QuicNewTokenFrame { // A unique identifier of this control frame. 0 when this frame is received, // and non-zero when sent. - QuicControlFrameId control_frame_id; + QuicControlFrameId control_frame_id = kInvalidControlFrameId; std::string token; }; diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_padding_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_padding_frame.h index 03e0a4041fe..0918f0f2463 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_padding_frame.h +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_padding_frame.h @@ -17,17 +17,17 @@ namespace quic { // A padding frame contains no payload. struct QUIC_EXPORT_PRIVATE QuicPaddingFrame : public QuicInlinedFrame<QuicPaddingFrame> { - QuicPaddingFrame() : QuicInlinedFrame(PADDING_FRAME), num_padding_bytes(-1) {} + QuicPaddingFrame() : QuicInlinedFrame(PADDING_FRAME) {} explicit QuicPaddingFrame(int num_padding_bytes) : QuicInlinedFrame(PADDING_FRAME), num_padding_bytes(num_padding_bytes) {} friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( std::ostream& os, - const QuicPaddingFrame& s); + const QuicPaddingFrame& padding_frame); // -1: full padding to the end of a max-sized packet // otherwise: only pad up to num_padding_bytes bytes - int num_padding_bytes; + int num_padding_bytes = -1; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.cc index 998ae483c07..4a8d1207b73 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.cc @@ -4,15 +4,11 @@ #include "net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.h" -#include "net/third_party/quiche/src/quic/core/quic_constants.h" #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" #include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h" namespace quic { -QuicPathChallengeFrame::QuicPathChallengeFrame() - : control_frame_id(kInvalidControlFrameId) {} - QuicPathChallengeFrame::QuicPathChallengeFrame( QuicControlFrameId control_frame_id, const QuicPathFrameBuffer& data_buff) diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.h index 46a010ae92b..e173117b581 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.h +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.h @@ -8,15 +8,13 @@ #include <memory> #include <ostream> +#include "net/third_party/quiche/src/quic/core/quic_constants.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" namespace quic { -// Size of the entire IETF Quic Path Challenge frame. -const size_t kQuicPathChallengeFrameSize = kQuicPathFrameBufferSize; - struct QUIC_EXPORT_PRIVATE QuicPathChallengeFrame { - QuicPathChallengeFrame(); + QuicPathChallengeFrame() = default; QuicPathChallengeFrame(QuicControlFrameId control_frame_id, const QuicPathFrameBuffer& data_buff); ~QuicPathChallengeFrame(); @@ -27,7 +25,7 @@ struct QUIC_EXPORT_PRIVATE QuicPathChallengeFrame { // A unique identifier of this control frame. 0 when this frame is received, // and non-zero when sent. - QuicControlFrameId control_frame_id; + QuicControlFrameId control_frame_id = kInvalidControlFrameId; QuicPathFrameBuffer data_buffer; }; diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.cc index e652698ab03..4779c6ad25f 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.cc @@ -4,15 +4,11 @@ #include "net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.h" -#include "net/third_party/quiche/src/quic/core/quic_constants.h" #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" #include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h" namespace quic { -QuicPathResponseFrame::QuicPathResponseFrame() - : control_frame_id(kInvalidControlFrameId) {} - QuicPathResponseFrame::QuicPathResponseFrame( QuicControlFrameId control_frame_id, const QuicPathFrameBuffer& data_buff) diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.h index e953ad8aa52..cdb0ba89e7c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.h +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.h @@ -8,15 +8,13 @@ #include <memory> #include <ostream> +#include "net/third_party/quiche/src/quic/core/quic_constants.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" namespace quic { -// Size of the entire IETF Quic Path Response frame. -const size_t kQuicPathResponseFrameSize = kQuicPathFrameBufferSize; - struct QUIC_EXPORT_PRIVATE QuicPathResponseFrame { - QuicPathResponseFrame(); + QuicPathResponseFrame() = default; QuicPathResponseFrame(QuicControlFrameId control_frame_id, const QuicPathFrameBuffer& data_buff); ~QuicPathResponseFrame(); @@ -27,7 +25,7 @@ struct QUIC_EXPORT_PRIVATE QuicPathResponseFrame { // A unique identifier of this control frame. 0 when this frame is received, // and non-zero when sent. - QuicControlFrameId control_frame_id; + QuicControlFrameId control_frame_id = kInvalidControlFrameId; QuicPathFrameBuffer data_buffer; }; diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_ping_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ping_frame.cc index d31efb0aae9..064d9170303 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_ping_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ping_frame.cc @@ -6,8 +6,7 @@ namespace quic { -QuicPingFrame::QuicPingFrame() - : QuicInlinedFrame(PING_FRAME), control_frame_id(kInvalidControlFrameId) {} +QuicPingFrame::QuicPingFrame() : QuicInlinedFrame(PING_FRAME) {} QuicPingFrame::QuicPingFrame(QuicControlFrameId control_frame_id) : QuicInlinedFrame(PING_FRAME), control_frame_id(control_frame_id) {} diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_ping_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ping_frame.h index 352d079951c..5cefdf9c805 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_ping_frame.h +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ping_frame.h @@ -25,7 +25,7 @@ struct QUIC_EXPORT_PRIVATE QuicPingFrame // A unique identifier of this control frame. 0 when this frame is received, // and non-zero when sent. - QuicControlFrameId control_frame_id; + QuicControlFrameId control_frame_id = kInvalidControlFrameId; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_retire_connection_id_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_retire_connection_id_frame.cc index 6828ce41227..0da9e0cfc02 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_retire_connection_id_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_retire_connection_id_frame.cc @@ -3,13 +3,9 @@ // found in the LICENSE file. #include "net/third_party/quiche/src/quic/core/frames/quic_retire_connection_id_frame.h" -#include "net/third_party/quiche/src/quic/core/quic_constants.h" namespace quic { -QuicRetireConnectionIdFrame::QuicRetireConnectionIdFrame() - : control_frame_id(kInvalidControlFrameId), sequence_number(0) {} - QuicRetireConnectionIdFrame::QuicRetireConnectionIdFrame( QuicControlFrameId control_frame_id, QuicConnectionIdSequenceNumber sequence_number) diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_retire_connection_id_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_retire_connection_id_frame.h index 79521f647a0..4451d319546 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_retire_connection_id_frame.h +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_retire_connection_id_frame.h @@ -7,6 +7,7 @@ #include <ostream> +#include "net/third_party/quiche/src/quic/core/quic_constants.h" #include "net/third_party/quiche/src/quic/core/quic_error_codes.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/platform/api/quic_uint128.h" @@ -14,7 +15,7 @@ namespace quic { struct QUIC_EXPORT_PRIVATE QuicRetireConnectionIdFrame { - QuicRetireConnectionIdFrame(); + QuicRetireConnectionIdFrame() = default; QuicRetireConnectionIdFrame(QuicControlFrameId control_frame_id, QuicConnectionIdSequenceNumber sequence_number); @@ -24,8 +25,8 @@ struct QUIC_EXPORT_PRIVATE QuicRetireConnectionIdFrame { // A unique identifier of this control frame. 0 when this frame is received, // and non-zero when sent. - QuicControlFrameId control_frame_id; - QuicConnectionIdSequenceNumber sequence_number; + QuicControlFrameId control_frame_id = kInvalidControlFrameId; + QuicConnectionIdSequenceNumber sequence_number = 0; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_rst_stream_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_rst_stream_frame.cc index 63cf6eaf6a3..41a1fd391fe 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_rst_stream_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_rst_stream_frame.cc @@ -3,16 +3,9 @@ // found in the LICENSE file. #include "net/third_party/quiche/src/quic/core/frames/quic_rst_stream_frame.h" -#include "net/third_party/quiche/src/quic/core/quic_constants.h" namespace quic { -QuicRstStreamFrame::QuicRstStreamFrame() - : control_frame_id(kInvalidControlFrameId), - stream_id(0), - error_code(QUIC_STREAM_NO_ERROR), - byte_offset(0) {} - QuicRstStreamFrame::QuicRstStreamFrame(QuicControlFrameId control_frame_id, QuicStreamId stream_id, QuicRstStreamErrorCode error_code, @@ -20,15 +13,7 @@ QuicRstStreamFrame::QuicRstStreamFrame(QuicControlFrameId control_frame_id, : control_frame_id(control_frame_id), stream_id(stream_id), error_code(error_code), - byte_offset(bytes_written) {} - -QuicRstStreamFrame::QuicRstStreamFrame(QuicControlFrameId control_frame_id, - QuicStreamId stream_id, - uint16_t ietf_error_code, - QuicStreamOffset bytes_written) - : control_frame_id(control_frame_id), - stream_id(stream_id), - ietf_error_code(ietf_error_code), + ietf_error_code(RstStreamErrorCodeToIetfResetStreamErrorCode(error_code)), byte_offset(bytes_written) {} std::ostream& operator<<(std::ostream& os, diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_rst_stream_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_rst_stream_frame.h index 9a9ed56abb0..691a868cbee 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_rst_stream_frame.h +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_rst_stream_frame.h @@ -7,21 +7,18 @@ #include <ostream> +#include "net/third_party/quiche/src/quic/core/quic_constants.h" #include "net/third_party/quiche/src/quic/core/quic_error_codes.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" namespace quic { struct QUIC_EXPORT_PRIVATE QuicRstStreamFrame { - QuicRstStreamFrame(); + QuicRstStreamFrame() = default; QuicRstStreamFrame(QuicControlFrameId control_frame_id, QuicStreamId stream_id, QuicRstStreamErrorCode error_code, QuicStreamOffset bytes_written); - QuicRstStreamFrame(QuicControlFrameId control_frame_id, - QuicStreamId stream_id, - uint16_t ietf_error_code, - QuicStreamOffset bytes_written); friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( std::ostream& os, @@ -29,25 +26,25 @@ struct QUIC_EXPORT_PRIVATE QuicRstStreamFrame { // A unique identifier of this control frame. 0 when this frame is received, // and non-zero when sent. - QuicControlFrameId control_frame_id; + QuicControlFrameId control_frame_id = kInvalidControlFrameId; + + QuicStreamId stream_id = 0; - QuicStreamId stream_id; + // When using Google QUIC: the RST_STREAM error code on the wire. + // When using IETF QUIC: for an outgoing RESET_STREAM frame, the error code + // generated by the application that determines |ietf_error_code| to be sent + // on the wire; for an incoming RESET_STREAM frame, the error code inferred + // from the |ietf_error_code| received on the wire. + QuicRstStreamErrorCode error_code = QUIC_STREAM_NO_ERROR; - // Caller must know whether IETF- or Google- QUIC is in use and - // set the appropriate error code. - union { - QuicRstStreamErrorCode error_code; - // In IETF QUIC the code is up to the app on top of quic, so is - // more general than QuicRstStreamErrorCode allows. - // TODO(fkastenholz): Upgrade to uint64_t - uint16_t ietf_error_code; - }; + // Application error code of RESET_STREAM frame. Used for IETF QUIC only. + uint64_t ietf_error_code = 0; // Used to update flow control windows. On termination of a stream, both // endpoints must inform the peer of the number of bytes they have sent on // that stream. This can be done through normal termination (data packet with // FIN) or through a RST. - QuicStreamOffset byte_offset; + QuicStreamOffset byte_offset = 0; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.cc index 1afd512150a..c4d732ed44d 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.cc @@ -3,15 +3,9 @@ // found in the LICENSE file. #include "net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.h" -#include "net/third_party/quiche/src/quic/core/quic_constants.h" namespace quic { -QuicStopSendingFrame::QuicStopSendingFrame() - : control_frame_id(kInvalidControlFrameId), - stream_id(0), - application_error_code(0) {} - QuicStopSendingFrame::QuicStopSendingFrame( QuicControlFrameId control_frame_id, QuicStreamId stream_id, diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.h index 7ca639d2eb3..8222067d276 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.h +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.h @@ -7,13 +7,14 @@ #include <ostream> +#include "net/third_party/quiche/src/quic/core/quic_constants.h" #include "net/third_party/quiche/src/quic/core/quic_error_codes.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" namespace quic { struct QUIC_EXPORT_PRIVATE QuicStopSendingFrame { - QuicStopSendingFrame(); + QuicStopSendingFrame() = default; QuicStopSendingFrame(QuicControlFrameId control_frame_id, QuicStreamId stream_id, QuicApplicationErrorCode application_error_code); @@ -24,9 +25,9 @@ struct QUIC_EXPORT_PRIVATE QuicStopSendingFrame { // A unique identifier of this control frame. 0 when this frame is received, // and non-zero when sent. - QuicControlFrameId control_frame_id; - QuicStreamId stream_id; - QuicApplicationErrorCode application_error_code; + QuicControlFrameId control_frame_id = kInvalidControlFrameId; + QuicStreamId stream_id = 0; + QuicApplicationErrorCode application_error_code = 0; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_stream_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_stream_frame.cc index 54a5252bb7d..db199998860 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_stream_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_stream_frame.cc @@ -9,8 +9,7 @@ namespace quic { -QuicStreamFrame::QuicStreamFrame() - : QuicStreamFrame(-1, false, 0, nullptr, 0) {} +QuicStreamFrame::QuicStreamFrame() : QuicInlinedFrame(STREAM_FRAME) {} QuicStreamFrame::QuicStreamFrame(QuicStreamId stream_id, bool fin, diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h index fc78ff9df7f..f807ee1e4c9 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h @@ -35,11 +35,13 @@ struct QUIC_EXPORT_PRIVATE QuicStreamFrame bool operator!=(const QuicStreamFrame& rhs) const; - bool fin; - QuicPacketLength data_length; - QuicStreamId stream_id; - const char* data_buffer; // Not owned. - QuicStreamOffset offset; // Location of this data in the stream. + bool fin = false; + QuicPacketLength data_length = 0; + // TODO(wub): Change to a QuicUtils::GetInvalidStreamId when it is not version + // dependent. + QuicStreamId stream_id = -1; + const char* data_buffer = nullptr; // Not owned. + QuicStreamOffset offset = 0; // Location of this data in the stream. QuicStreamFrame(QuicStreamId stream_id, bool fin, diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_streams_blocked_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_streams_blocked_frame.cc index f0579c55b68..9300ce32e51 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_streams_blocked_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_streams_blocked_frame.cc @@ -7,9 +7,7 @@ namespace quic { QuicStreamsBlockedFrame::QuicStreamsBlockedFrame() - : QuicInlinedFrame(STREAMS_BLOCKED_FRAME), - control_frame_id(kInvalidControlFrameId), - unidirectional(false) {} + : QuicInlinedFrame(STREAMS_BLOCKED_FRAME) {} QuicStreamsBlockedFrame::QuicStreamsBlockedFrame( QuicControlFrameId control_frame_id, diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_streams_blocked_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_streams_blocked_frame.h index ff7c7f44621..91c7ac91a84 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_streams_blocked_frame.h +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_streams_blocked_frame.h @@ -30,13 +30,13 @@ struct QUIC_EXPORT_PRIVATE QuicStreamsBlockedFrame // A unique identifier of this control frame. 0 when this frame is received, // and non-zero when sent. - QuicControlFrameId control_frame_id; + QuicControlFrameId control_frame_id = kInvalidControlFrameId; // The number of streams that the sender wishes to exceed QuicStreamCount stream_count; // Whether uni- or bi-directional streams - bool unidirectional; + bool unidirectional = false; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.cc index 81ca125b64c..a4f3ec32c01 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.cc @@ -3,13 +3,9 @@ // found in the LICENSE file. #include "net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.h" -#include "net/third_party/quiche/src/quic/core/quic_constants.h" namespace quic { -QuicWindowUpdateFrame::QuicWindowUpdateFrame() - : control_frame_id(kInvalidControlFrameId) {} - QuicWindowUpdateFrame::QuicWindowUpdateFrame( QuicControlFrameId control_frame_id, QuicStreamId stream_id, diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.h index ff4478528dd..74181f5f1d2 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.h +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.h @@ -7,6 +7,7 @@ #include <ostream> +#include "net/third_party/quiche/src/quic/core/quic_constants.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" namespace quic { @@ -15,7 +16,7 @@ namespace quic { // Based on SPDY's WINDOW_UPDATE frame, but uses an absolute max data bytes // rather than a window delta. struct QUIC_EXPORT_PRIVATE QuicWindowUpdateFrame { - QuicWindowUpdateFrame(); + QuicWindowUpdateFrame() = default; QuicWindowUpdateFrame(QuicControlFrameId control_frame_id, QuicStreamId stream_id, QuicByteCount max_data); @@ -26,7 +27,7 @@ struct QUIC_EXPORT_PRIVATE QuicWindowUpdateFrame { // A unique identifier of this control frame. 0 when this frame is received, // and non-zero when sent. - QuicControlFrameId control_frame_id; + QuicControlFrameId control_frame_id = kInvalidControlFrameId; // The stream this frame applies to. 0 is a special case meaning the overall // connection rather than a specific stream. diff --git a/chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc index cec0ceb9fff..782394427f4 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc @@ -81,108 +81,40 @@ const float kSessionToStreamRatio = 1.5; // Run all tests with the cross products of all versions. struct TestParams { - TestParams(const ParsedQuicVersionVector& client_supported_versions, - const ParsedQuicVersionVector& server_supported_versions, - ParsedQuicVersion negotiated_version, - QuicTag congestion_control_tag) - : client_supported_versions(client_supported_versions), - server_supported_versions(server_supported_versions), - negotiated_version(negotiated_version), - congestion_control_tag(congestion_control_tag) {} + TestParams(const ParsedQuicVersion& version, QuicTag congestion_control_tag) + : version(version), congestion_control_tag(congestion_control_tag) {} friend std::ostream& operator<<(std::ostream& os, const TestParams& p) { - os << "{ server_supported_versions: " - << ParsedQuicVersionVectorToString(p.server_supported_versions); - os << " client_supported_versions: " - << ParsedQuicVersionVectorToString(p.client_supported_versions); - os << " negotiated_version: " - << ParsedQuicVersionToString(p.negotiated_version); + os << "{ version: " << ParsedQuicVersionToString(p.version); os << " congestion_control_tag: " << QuicTagToString(p.congestion_control_tag) << " }"; return os; } - ParsedQuicVersionVector client_supported_versions; - ParsedQuicVersionVector server_supported_versions; - ParsedQuicVersion negotiated_version; + ParsedQuicVersion version; QuicTag congestion_control_tag; }; // Used by ::testing::PrintToStringParamName(). std::string PrintToString(const TestParams& p) { - std::string rv = quiche::QuicheStrCat( - ParsedQuicVersionToString(p.negotiated_version), "_Server_", - ParsedQuicVersionVectorToString(p.server_supported_versions), "_Client_", - ParsedQuicVersionVectorToString(p.client_supported_versions), "_", - QuicTagToString(p.congestion_control_tag)); + std::string rv = + quiche::QuicheStrCat(ParsedQuicVersionToString(p.version), "_", + QuicTagToString(p.congestion_control_tag)); std::replace(rv.begin(), rv.end(), ',', '_'); std::replace(rv.begin(), rv.end(), ' ', '_'); return rv; } // Constructs various test permutations. -std::vector<TestParams> GetTestParams(bool use_tls_handshake) { - // Divide the versions into buckets in which the intra-frame format - // is compatible. When clients encounter QUIC version negotiation - // they simply retransmit all packets using the new version's - // QUIC framing. However, they are unable to change the intra-frame - // layout (for example to change HTTP/2 headers to SPDY/3, or a change in the - // handshake protocol). So these tests need to ensure that clients are never - // attempting to do 0-RTT across incompatible versions. Chromium only - // supports a single version at a time anyway. :) - ParsedQuicVersionVector all_supported_versions = - FilterSupportedVersions(AllSupportedVersions()); - - // Buckets are separated by versions: versions without crypto frames use - // STREAM frames for the handshake, and only have QUIC crypto as the handshake - // protocol. Versions that use CRYPTO frames for the handshake must also be - // split based on the handshake protocol. If the handshake protocol (QUIC - // crypto or TLS) changes, the ClientHello/CHLO must be reconstructed for the - // correct protocol. - ParsedQuicVersionVector version_buckets[3]; - - for (const ParsedQuicVersion& version : all_supported_versions) { - if (!use_tls_handshake && version.handshake_protocol == PROTOCOL_TLS1_3) { - continue; - } - if (!QuicVersionUsesCryptoFrames(version.transport_version)) { - version_buckets[0].push_back(version); - } else if (version.handshake_protocol == PROTOCOL_QUIC_CRYPTO) { - version_buckets[1].push_back(version); - } else { - version_buckets[2].push_back(version); - } - } - +std::vector<TestParams> GetTestParams() { std::vector<TestParams> params; for (const QuicTag congestion_control_tag : {kRENO, kTBBR, kQBIC, kB2ON}) { if (!GetQuicReloadableFlag(quic_allow_client_enabled_bbr_v2) && congestion_control_tag == kB2ON) { continue; } - for (const ParsedQuicVersionVector& client_versions : version_buckets) { - if (FilterSupportedVersions(client_versions).empty()) { - continue; - } - // Add an entry for server and client supporting all versions. - params.push_back(TestParams(client_versions, all_supported_versions, - client_versions.front(), - congestion_control_tag)); - // Test client supporting all versions and server supporting - // 1 version. Simulate an old server and exercise version - // downgrade in the client. Protocol negotiation should - // occur. Skip the i = 0 case because it is essentially the - // same as the default case. - for (size_t i = 1; i < client_versions.size(); ++i) { - ParsedQuicVersionVector server_supported_versions; - server_supported_versions.push_back(client_versions[i]); - if (FilterSupportedVersions(server_supported_versions).empty()) { - continue; - } - params.push_back(TestParams(client_versions, server_supported_versions, - server_supported_versions.front(), - congestion_control_tag)); - } // End of inner version loop. + for (const ParsedQuicVersion& version : CurrentSupportedVersions()) { + params.push_back(TestParams(version, congestion_control_tag)); } // End of outer version loop. } // End of congestion_control_tag loop. @@ -231,14 +163,12 @@ class EndToEndTest : public QuicTestWithParam<TestParams> { server_hostname_("test.example.com"), client_writer_(nullptr), server_writer_(nullptr), - negotiated_version_(UnsupportedQuicVersion()), + version_(GetParam().version), + client_supported_versions_({version_}), + server_supported_versions_(CurrentSupportedVersions()), chlo_multiplier_(0), stream_factory_(nullptr), expected_server_connection_id_length_(kQuicDefaultConnectionIdLength) { - client_supported_versions_ = GetParam().client_supported_versions; - server_supported_versions_ = GetParam().server_supported_versions; - negotiated_version_ = GetParam().negotiated_version; - QUIC_LOG(INFO) << "Using Configuration: " << GetParam(); // Use different flow control windows for client/server. @@ -377,7 +307,7 @@ class EndToEndTest : public QuicTestWithParam<TestParams> { // client as well according to the test parameter. copt.push_back(GetParam().congestion_control_tag); copt.push_back(k2PTO); - if (VersionHasIetfQuicFrames(negotiated_version_.transport_version)) { + if (VersionHasIetfQuicFrames(version_.transport_version)) { copt.push_back(kILD0); } copt.push_back(kPLE1); @@ -496,12 +426,12 @@ class EndToEndTest : public QuicTestWithParam<TestParams> { if (!ServerSendsVersionNegotiation()) { EXPECT_EQ(0u, client_stats.packets_dropped); } - if (!ClientSupportsIetfQuicNotSupportedByServer()) { - // In this case, if client sends 0-RTT POST with v99, receives IETF - // version negotiation packet and speaks a GQUIC version. Server processes - // this connection in time wait list and keeps sending IETF version - // negotiation packet for incoming packets. But these version negotiation - // packets cannot be processed by the client speaking GQUIC. + if (!version_.UsesTls()) { + // Only enforce this for QUIC crypto because accounting of number of + // packets received, processed gets complicated with packets coalescing + // and key dropping. For example, a received undecryptable coalesced + // packet can be processed later and each sub-packet increases + // packets_processed. EXPECT_EQ(client_stats.packets_received, client_stats.packets_processed); } @@ -517,19 +447,10 @@ class EndToEndTest : public QuicTestWithParam<TestParams> { server_thread_->Resume(); } - // Client supports IETF QUIC, while it is not supported by server. - bool ClientSupportsIetfQuicNotSupportedByServer() { - return VersionHasIetfInvariantHeader( - client_supported_versions_[0].transport_version) && - !VersionHasIetfInvariantHeader( - FilterSupportedVersions(GetParam().server_supported_versions)[0] - .transport_version); - } - // Returns true when client starts with an unsupported version, and client // closes connection when version negotiation is received. bool ServerSendsVersionNegotiation() { - return client_supported_versions_[0] != GetParam().negotiated_version; + return client_supported_versions_[0] != version_; } bool SupportsIetfQuicWithTls(ParsedQuicVersion version) { @@ -587,10 +508,10 @@ class EndToEndTest : public QuicTestWithParam<TestParams> { PacketDroppingTestWriter* server_writer_; QuicConfig client_config_; QuicConfig server_config_; + ParsedQuicVersion version_; ParsedQuicVersionVector client_supported_versions_; ParsedQuicVersionVector server_supported_versions_; QuicTagVector client_extra_copts_; - ParsedQuicVersion negotiated_version_; size_t chlo_multiplier_; QuicTestServer::StreamFactory* stream_factory_; std::string pre_shared_key_client_; @@ -603,27 +524,13 @@ class EndToEndTest : public QuicTestWithParam<TestParams> { // Run all end to end tests with all supported versions. INSTANTIATE_TEST_SUITE_P(EndToEndTests, EndToEndTest, - ::testing::ValuesIn(GetTestParams(false)), + ::testing::ValuesIn(GetTestParams()), ::testing::PrintToStringParamName()); -class EndToEndTestWithTls : public EndToEndTest {}; - -INSTANTIATE_TEST_SUITE_P(EndToEndTestsWithTls, - EndToEndTestWithTls, - ::testing::ValuesIn(GetTestParams(true)), - ::testing::PrintToStringParamName()); - -TEST_P(EndToEndTestWithTls, HandshakeSuccessful) { +TEST_P(EndToEndTest, HandshakeSuccessful) { ASSERT_TRUE(Initialize()); EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); server_thread_->WaitForCryptoHandshakeConfirmed(); - // There have been occasions where it seemed that negotiated_version_ and the - // version in the connection are not in sync. If it is happening, it has not - // been recreatable; this assert is here just to check and raise a flag if it - // happens. - ASSERT_EQ(GetClientConnection()->transport_version(), - negotiated_version_.transport_version); - QuicCryptoStream* crypto_stream = QuicSessionPeer::GetMutableCryptoStream(GetClientSession()); QuicStreamSequencer* sequencer = QuicStreamPeer::sequencer(crypto_stream); @@ -632,6 +539,14 @@ TEST_P(EndToEndTestWithTls, HandshakeSuccessful) { crypto_stream = QuicSessionPeer::GetMutableCryptoStream(GetServerSession()); sequencer = QuicStreamPeer::sequencer(crypto_stream); EXPECT_FALSE(QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer)); + + // We've had bugs in the past where the connections could end up on the wrong + // version. This was never diagnosed but could have been due to in-connection + // version negotiation back when that existed. At this point in time, our test + // setup ensures that connections here always use |version_|, but we add this + // sanity check out of paranoia to catch a regression of this type. + EXPECT_EQ(GetClientConnection()->version(), version_); + EXPECT_EQ(GetServerConnection()->version(), version_); } TEST_P(EndToEndTest, SimpleRequestResponse) { @@ -651,15 +566,9 @@ TEST_P(EndToEndTest, SimpleRequestResponse) { } } -TEST_P(EndToEndTestWithTls, SimpleRequestResponse) { - ASSERT_TRUE(Initialize()); - EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); - EXPECT_EQ("200", client_->response_headers()->find(":status")->second); -} - -TEST_P(EndToEndTestWithTls, HandshakeConfirmed) { +TEST_P(EndToEndTest, HandshakeConfirmed) { ASSERT_TRUE(Initialize()); - if (!GetParam().negotiated_version.HasHandshakeDone()) { + if (!version_.HasHandshakeDone()) { return; } EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); @@ -672,7 +581,7 @@ TEST_P(EndToEndTestWithTls, HandshakeConfirmed) { client_->Disconnect(); } -TEST_P(EndToEndTestWithTls, SendAndReceiveCoalescedPackets) { +TEST_P(EndToEndTest, SendAndReceiveCoalescedPackets) { ASSERT_TRUE(Initialize()); if (!GetClientConnection()->version().CanSendCoalescedPackets()) { return; @@ -690,6 +599,11 @@ TEST_P(EndToEndTestWithTls, SendAndReceiveCoalescedPackets) { // Simple transaction, but set a non-default ack delay at the client // and ensure it gets to the server. TEST_P(EndToEndTest, SimpleRequestResponseWithAckDelayChange) { + if (version_.UsesTls()) { + // TODO(b/155316241): Enable this test for TLS. + Initialize(); + return; + } // Force the ACK delay to be something other than the default. // Note that it is sent only if doing IETF QUIC. client_config_.SetMaxAckDelayToSendMs(kDefaultDelayedAckTimeMs + 100u); @@ -715,6 +629,11 @@ TEST_P(EndToEndTest, SimpleRequestResponseWithAckDelayChange) { // Simple transaction, but set a non-default ack exponent at the client // and ensure it gets to the server. TEST_P(EndToEndTest, SimpleRequestResponseWithAckExponentChange) { + if (version_.UsesTls()) { + // TODO(b/155316241): Enable this test for TLS. + Initialize(); + return; + } const uint32_t kClientAckDelayExponent = kDefaultAckDelayExponent + 100u; // Force the ACK exponent to be something other than the default. // Note that it is sent only if doing IETF QUIC. @@ -726,8 +645,7 @@ TEST_P(EndToEndTest, SimpleRequestResponseWithAckExponentChange) { EXPECT_FALSE(client_->client()->EarlyDataAccepted()); EXPECT_FALSE(client_->client()->ReceivedInchoateReject()); - if (VersionHasIetfQuicFrames( - GetParam().negotiated_version.transport_version)) { + if (VersionHasIetfQuicFrames(version_.transport_version)) { // Should be only for IETF QUIC. EXPECT_EQ(kClientAckDelayExponent, GetServerConnection()->framer().peer_ack_delay_exponent()); @@ -757,7 +675,7 @@ TEST_P(EndToEndTest, SimpleRequestResponseForcedVersionNegotiation) { EXPECT_FALSE(client_->client()->ReceivedInchoateReject()); } -TEST_P(EndToEndTestWithTls, ForcedVersionNegotiation) { +TEST_P(EndToEndTest, ForcedVersionNegotiation) { client_supported_versions_.insert(client_supported_versions_.begin(), QuicVersionReservedForNegotiation()); ASSERT_TRUE(Initialize()); @@ -768,7 +686,7 @@ TEST_P(EndToEndTestWithTls, ForcedVersionNegotiation) { } TEST_P(EndToEndTest, SimpleRequestResponseZeroConnectionID) { - if (!GetParam().negotiated_version.AllowsVariableLengthConnectionIds()) { + if (!version_.AllowsVariableLengthConnectionIds()) { ASSERT_TRUE(Initialize()); return; } @@ -781,12 +699,11 @@ TEST_P(EndToEndTest, SimpleRequestResponseZeroConnectionID) { EXPECT_FALSE(client_->client()->EarlyDataAccepted()); EXPECT_FALSE(client_->client()->ReceivedInchoateReject()); EXPECT_EQ(GetClientConnection()->connection_id(), - QuicUtils::CreateZeroConnectionId( - GetParam().negotiated_version.transport_version)); + QuicUtils::CreateZeroConnectionId(version_.transport_version)); } -TEST_P(EndToEndTestWithTls, ZeroConnectionID) { - if (!GetParam().negotiated_version.AllowsVariableLengthConnectionIds()) { +TEST_P(EndToEndTest, ZeroConnectionID) { + if (!version_.AllowsVariableLengthConnectionIds()) { ASSERT_TRUE(Initialize()); return; } @@ -797,12 +714,11 @@ TEST_P(EndToEndTestWithTls, ZeroConnectionID) { EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); EXPECT_EQ("200", client_->response_headers()->find(":status")->second); EXPECT_EQ(GetClientConnection()->connection_id(), - QuicUtils::CreateZeroConnectionId( - GetParam().negotiated_version.transport_version)); + QuicUtils::CreateZeroConnectionId(version_.transport_version)); } -TEST_P(EndToEndTestWithTls, BadConnectionIdLength) { - if (!GetParam().negotiated_version.AllowsVariableLengthConnectionIds()) { +TEST_P(EndToEndTest, BadConnectionIdLength) { + if (!version_.AllowsVariableLengthConnectionIds()) { ASSERT_TRUE(Initialize()); return; } @@ -819,8 +735,8 @@ TEST_P(EndToEndTestWithTls, BadConnectionIdLength) { // Tests a very long (16-byte) initial destination connection ID to make // sure the dispatcher properly replaces it with an 8-byte one. -TEST_P(EndToEndTestWithTls, LongBadConnectionIdLength) { - if (!GetParam().negotiated_version.AllowsVariableLengthConnectionIds()) { +TEST_P(EndToEndTest, LongBadConnectionIdLength) { + if (!version_.AllowsVariableLengthConnectionIds()) { ASSERT_TRUE(Initialize()); return; } @@ -835,8 +751,8 @@ TEST_P(EndToEndTestWithTls, LongBadConnectionIdLength) { .length()); } -TEST_P(EndToEndTestWithTls, ClientConnectionId) { - if (!GetParam().negotiated_version.SupportsClientConnectionIds()) { +TEST_P(EndToEndTest, ClientConnectionId) { + if (!version_.SupportsClientConnectionIds()) { ASSERT_TRUE(Initialize()); return; } @@ -851,8 +767,8 @@ TEST_P(EndToEndTestWithTls, ClientConnectionId) { .length()); } -TEST_P(EndToEndTestWithTls, ForcedVersionNegotiationAndClientConnectionId) { - if (!GetParam().negotiated_version.SupportsClientConnectionIds()) { +TEST_P(EndToEndTest, ForcedVersionNegotiationAndClientConnectionId) { + if (!version_.SupportsClientConnectionIds()) { ASSERT_TRUE(Initialize()); return; } @@ -870,8 +786,8 @@ TEST_P(EndToEndTestWithTls, ForcedVersionNegotiationAndClientConnectionId) { .length()); } -TEST_P(EndToEndTestWithTls, ForcedVersionNegotiationAndBadConnectionIdLength) { - if (!GetParam().negotiated_version.AllowsVariableLengthConnectionIds()) { +TEST_P(EndToEndTest, ForcedVersionNegotiationAndBadConnectionIdLength) { + if (!version_.AllowsVariableLengthConnectionIds()) { ASSERT_TRUE(Initialize()); return; } @@ -891,9 +807,9 @@ TEST_P(EndToEndTestWithTls, ForcedVersionNegotiationAndBadConnectionIdLength) { // Forced Version Negotiation with a client connection ID and a long // connection ID. -TEST_P(EndToEndTestWithTls, ForcedVersNegoAndClientCIDAndLongCID) { - if (!GetParam().negotiated_version.SupportsClientConnectionIds() || - !GetParam().negotiated_version.AllowsVariableLengthConnectionIds()) { +TEST_P(EndToEndTest, ForcedVersNegoAndClientCIDAndLongCID) { + if (!version_.SupportsClientConnectionIds() || + !version_.AllowsVariableLengthConnectionIds()) { ASSERT_TRUE(Initialize()); return; } @@ -918,7 +834,7 @@ TEST_P(EndToEndTestWithTls, ForcedVersNegoAndClientCIDAndLongCID) { } TEST_P(EndToEndTest, MixGoodAndBadConnectionIdLengths) { - if (!GetParam().negotiated_version.AllowsVariableLengthConnectionIds()) { + if (!version_.AllowsVariableLengthConnectionIds()) { ASSERT_TRUE(Initialize()); return; } @@ -957,8 +873,8 @@ TEST_P(EndToEndTest, MixGoodAndBadConnectionIdLengths) { .length()); } -TEST_P(EndToEndTestWithTls, SimpleRequestResponseWithIetfDraftSupport) { - if (!GetParam().negotiated_version.HasIetfQuicFrames()) { +TEST_P(EndToEndTest, SimpleRequestResponseWithIetfDraftSupport) { + if (!version_.HasIetfQuicFrames()) { ASSERT_TRUE(Initialize()); return; } @@ -976,10 +892,15 @@ TEST_P(EndToEndTest, SimpleRequestResponseWithLargeReject) { EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); EXPECT_EQ("200", client_->response_headers()->find(":status")->second); EXPECT_FALSE(client_->client()->EarlyDataAccepted()); - EXPECT_TRUE(client_->client()->ReceivedInchoateReject()); + if (version_.UsesTls()) { + // REJ messages are a QUIC crypto feature, so TLS always returns false. + EXPECT_FALSE(client_->client()->ReceivedInchoateReject()); + } else { + EXPECT_TRUE(client_->client()->ReceivedInchoateReject()); + } } -TEST_P(EndToEndTestWithTls, SimpleRequestResponsev6) { +TEST_P(EndToEndTest, SimpleRequestResponsev6) { server_address_ = QuicSocketAddress(QuicIpAddress::Loopback6(), server_address_.port()); ASSERT_TRUE(Initialize()); @@ -988,7 +909,7 @@ TEST_P(EndToEndTestWithTls, SimpleRequestResponsev6) { EXPECT_EQ("200", client_->response_headers()->find(":status")->second); } -TEST_P(EndToEndTestWithTls, +TEST_P(EndToEndTest, ClientDoesNotAllowServerDataOnServerInitiatedBidirectionalStreams) { set_client_initial_max_stream_data_incoming_bidirectional(0); ASSERT_TRUE(Initialize()); @@ -996,7 +917,7 @@ TEST_P(EndToEndTestWithTls, EXPECT_EQ("200", client_->response_headers()->find(":status")->second); } -TEST_P(EndToEndTestWithTls, +TEST_P(EndToEndTest, ServerDoesNotAllowClientDataOnServerInitiatedBidirectionalStreams) { set_server_initial_max_stream_data_outgoing_bidirectional(0); ASSERT_TRUE(Initialize()); @@ -1004,7 +925,7 @@ TEST_P(EndToEndTestWithTls, EXPECT_EQ("200", client_->response_headers()->find(":status")->second); } -TEST_P(EndToEndTestWithTls, +TEST_P(EndToEndTest, BothEndpointsDisallowDataOnServerInitiatedBidirectionalStreams) { set_client_initial_max_stream_data_incoming_bidirectional(0); set_server_initial_max_stream_data_outgoing_bidirectional(0); @@ -1017,7 +938,7 @@ TEST_P(EndToEndTestWithTls, // initial packet. Undecryptable packets can be seen after the handshake // is complete due to dropping the initial keys at that point, so we only test // for undecryptable packets before then. -TEST_P(EndToEndTestWithTls, NoUndecryptablePacketsBeforeHandshakeComplete) { +TEST_P(EndToEndTest, NoUndecryptablePacketsBeforeHandshakeComplete) { ASSERT_TRUE(Initialize()); EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); @@ -1036,7 +957,7 @@ TEST_P(EndToEndTestWithTls, NoUndecryptablePacketsBeforeHandshakeComplete) { server_thread_->Resume(); } -TEST_P(EndToEndTestWithTls, SeparateFinPacket) { +TEST_P(EndToEndTest, SeparateFinPacket) { ASSERT_TRUE(Initialize()); // Send a request in two parts: the request and then an empty packet with FIN. @@ -1060,7 +981,7 @@ TEST_P(EndToEndTestWithTls, SeparateFinPacket) { EXPECT_EQ("200", client_->response_headers()->find(":status")->second); } -TEST_P(EndToEndTestWithTls, MultipleRequestResponse) { +TEST_P(EndToEndTest, MultipleRequestResponse) { ASSERT_TRUE(Initialize()); EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); @@ -1070,7 +991,7 @@ TEST_P(EndToEndTestWithTls, MultipleRequestResponse) { } TEST_P(EndToEndTest, MultipleRequestResponseZeroConnectionID) { - if (!GetParam().negotiated_version.AllowsVariableLengthConnectionIds()) { + if (!version_.AllowsVariableLengthConnectionIds()) { ASSERT_TRUE(Initialize()); return; } @@ -1084,7 +1005,7 @@ TEST_P(EndToEndTest, MultipleRequestResponseZeroConnectionID) { EXPECT_EQ("200", client_->response_headers()->find(":status")->second); } -TEST_P(EndToEndTestWithTls, MultipleStreams) { +TEST_P(EndToEndTest, MultipleStreams) { // Verifies quic_test_client can track responses of all active streams. ASSERT_TRUE(Initialize()); @@ -1109,7 +1030,7 @@ TEST_P(EndToEndTestWithTls, MultipleStreams) { } } -TEST_P(EndToEndTestWithTls, MultipleClients) { +TEST_P(EndToEndTest, MultipleClients) { ASSERT_TRUE(Initialize()); std::unique_ptr<QuicTestClient> client2(CreateQuicClient(nullptr)); @@ -1134,7 +1055,7 @@ TEST_P(EndToEndTestWithTls, MultipleClients) { EXPECT_EQ("200", client2->response_headers()->find(":status")->second); } -TEST_P(EndToEndTestWithTls, RequestOverMultiplePackets) { +TEST_P(EndToEndTest, RequestOverMultiplePackets) { // Send a large enough request to guarantee fragmentation. std::string huge_request = "/some/path?query=" + std::string(kMaxOutgoingPacketSize, '.'); @@ -1146,7 +1067,7 @@ TEST_P(EndToEndTestWithTls, RequestOverMultiplePackets) { EXPECT_EQ("200", client_->response_headers()->find(":status")->second); } -TEST_P(EndToEndTestWithTls, MultiplePacketsRandomOrder) { +TEST_P(EndToEndTest, MultiplePacketsRandomOrder) { // Send a large enough request to guarantee fragmentation. std::string huge_request = "/some/path?query=" + std::string(kMaxOutgoingPacketSize, '.'); @@ -1160,7 +1081,7 @@ TEST_P(EndToEndTestWithTls, MultiplePacketsRandomOrder) { EXPECT_EQ("200", client_->response_headers()->find(":status")->second); } -TEST_P(EndToEndTestWithTls, PostMissingBytes) { +TEST_P(EndToEndTest, PostMissingBytes) { ASSERT_TRUE(Initialize()); // Add a content length header with no body. @@ -1317,6 +1238,11 @@ TEST_P(EndToEndTest, LargePostNoPacketLossWithDelayAndReordering) { } TEST_P(EndToEndTest, LargePostZeroRTTFailure) { + if (version_.UsesTls()) { + // TODO(b/152551499): Re-enable this test when TLS supports 0-RTT. + Initialize(); + return; + } // Send a request and then disconnect. This prepares the client to attempt // a 0-RTT handshake for the next request. ASSERT_TRUE(Initialize()); @@ -1368,6 +1294,11 @@ TEST_P(EndToEndTest, LargePostZeroRTTFailure) { } TEST_P(EndToEndTest, SynchronousRequestZeroRTTFailure) { + if (version_.UsesTls()) { + // TODO(b/152551499): Re-enable this test when TLS supports 0-RTT. + Initialize(); + return; + } // Send a request and then disconnect. This prepares the client to attempt // a 0-RTT handshake for the next request. ASSERT_TRUE(Initialize()); @@ -1429,6 +1360,10 @@ TEST_P(EndToEndTest, LargePostSynchronousRequest) { EXPECT_FALSE(client_->client()->ReceivedInchoateReject()); client_->Disconnect(); + if (version_.UsesTls()) { + // TODO(b/152551499): remove this when TLS supports 0-RTT. + return; + } // The 0-RTT handshake should succeed. client_->Connect(); @@ -1520,7 +1455,7 @@ TEST_P(EndToEndTest, LargePostSmallBandwidthLargeBuffer) { VerifyCleanConnection(true); } -TEST_P(EndToEndTestWithTls, DoNotSetSendAlarmIfConnectionFlowControlBlocked) { +TEST_P(EndToEndTest, DoNotSetSendAlarmIfConnectionFlowControlBlocked) { // Regression test for b/14677858. // Test that the resume write alarm is not set in QuicConnection::OnCanWrite // if currently connection level flow control blocked. If set, this results in @@ -1561,8 +1496,6 @@ TEST_P(EndToEndTestWithTls, DoNotSetSendAlarmIfConnectionFlowControlBlocked) { EXPECT_FALSE(send_alarm->IsSet()); } -// TODO(nharper): Needs to get turned back to EndToEndTestWithTls -// when we figure out why the test doesn't work on chrome. TEST_P(EndToEndTest, InvalidStream) { ASSERT_TRUE(Initialize()); EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); @@ -1586,8 +1519,8 @@ TEST_P(EndToEndTest, InvalidStream) { EXPECT_THAT(client_->connection_error(), IsError(QUIC_INVALID_STREAM_ID)); } -// Test that if the server will close the connection if the client attempts -// to send a request with overly large headers. +// Test that the server resets the stream if the client sends a request +// with overly large headers. TEST_P(EndToEndTest, LargeHeaders) { ASSERT_TRUE(Initialize()); EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); @@ -1604,16 +1537,17 @@ TEST_P(EndToEndTest, LargeHeaders) { client_->SendCustomSynchronousRequest(headers, body); - if (VersionUsesHttp3(client_->client() - ->client_session() - ->connection() - ->transport_version())) { - EXPECT_THAT(client_->connection_error(), - IsError(QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE)); + if (VersionUsesHttp3(GetClientConnection()->transport_version())) { + // QuicSpdyStream::OnHeadersTooLarge() resets the stream with + // QUIC_HEADERS_TOO_LARGE. This is sent as H3_EXCESSIVE_LOAD, the closest + // HTTP/3 error code, and translated back to QUIC_STREAM_EXCESSIVE_LOAD on + // the receiving side. + EXPECT_THAT(client_->stream_error(), + IsStreamError(QUIC_STREAM_EXCESSIVE_LOAD)); } else { EXPECT_THAT(client_->stream_error(), IsStreamError(QUIC_HEADERS_TOO_LARGE)); - EXPECT_THAT(client_->connection_error(), IsQuicNoError()); } + EXPECT_THAT(client_->connection_error(), IsQuicNoError()); } TEST_P(EndToEndTest, EarlyResponseWithQuicStreamNoError) { @@ -1638,7 +1572,7 @@ TEST_P(EndToEndTest, EarlyResponseWithQuicStreamNoError) { } // TODO(rch): this test seems to cause net_unittests timeouts :| -TEST_P(EndToEndTestWithTls, QUIC_TEST_DISABLED_IN_CHROME(MultipleTermination)) { +TEST_P(EndToEndTest, QUIC_TEST_DISABLED_IN_CHROME(MultipleTermination)) { ASSERT_TRUE(Initialize()); // Set the offset so we won't frame. Otherwise when we pick up termination @@ -1658,11 +1592,8 @@ TEST_P(EndToEndTestWithTls, QUIC_TEST_DISABLED_IN_CHROME(MultipleTermination)) { EXPECT_QUIC_BUG(client_->SendData("eep", true), "Fin already buffered"); } -// TODO(nharper): Needs to get turned back to EndToEndTestWithTls -// when we figure out why the test doesn't work on chrome. TEST_P(EndToEndTest, Timeout) { - client_config_.SetIdleNetworkTimeout(QuicTime::Delta::FromMicroseconds(500), - QuicTime::Delta::FromMicroseconds(500)); + client_config_.SetIdleNetworkTimeout(QuicTime::Delta::FromMicroseconds(500)); // Note: we do NOT ASSERT_TRUE: we may time out during initial handshake: // that's enough to validate timeout in this case. Initialize(); @@ -1671,14 +1602,13 @@ TEST_P(EndToEndTest, Timeout) { } } -TEST_P(EndToEndTestWithTls, MaxDynamicStreamsLimitRespected) { +TEST_P(EndToEndTest, MaxDynamicStreamsLimitRespected) { // Set a limit on maximum number of incoming dynamic streams. // Make sure the limit is respected by the peer. const uint32_t kServerMaxDynamicStreams = 1; server_config_.SetMaxBidirectionalStreamsToSend(kServerMaxDynamicStreams); ASSERT_TRUE(Initialize()); - if (VersionHasIetfQuicFrames( - GetParam().negotiated_version.transport_version)) { + if (VersionHasIetfQuicFrames(version_.transport_version)) { // Do not run this test for /IETF QUIC. This test relies on the fact that // Google QUIC allows a small number of additional streams beyond the // negotiated limit, which is not supported in IETF QUIC. Note that the test @@ -1746,7 +1676,7 @@ TEST_P(EndToEndTest, SetIndependentMaxDynamicStreamsLimits) { client_session->connection()->transport_version()) ? QuicSessionPeer::v99_streamid_manager(client_session) ->max_outgoing_unidirectional_streams() - - client_session->num_expected_unidirectional_static_streams() + kHttp3StaticUnidirectionalStreamCount : QuicSessionPeer::GetStreamIdManager(client_session) ->max_open_outgoing_streams(); EXPECT_EQ(kServerMaxDynamicStreams, @@ -1767,7 +1697,7 @@ TEST_P(EndToEndTest, SetIndependentMaxDynamicStreamsLimits) { server_session->connection()->transport_version()) ? QuicSessionPeer::v99_streamid_manager(server_session) ->max_outgoing_unidirectional_streams() - - server_session->num_expected_unidirectional_static_streams() + kHttp3StaticUnidirectionalStreamCount : QuicSessionPeer::GetStreamIdManager(server_session) ->max_open_outgoing_streams(); EXPECT_EQ(kClientMaxDynamicStreams, @@ -1921,8 +1851,7 @@ TEST_P(EndToEndTest, MinInitialRTT) { } TEST_P(EndToEndTest, 0ByteConnectionId) { - if (VersionHasIetfInvariantHeader( - GetParam().negotiated_version.transport_version)) { + if (VersionHasIetfInvariantHeader(version_.transport_version)) { // SetBytesForConnectionIdToSend only applies to Google QUIC encoding. ASSERT_TRUE(Initialize()); return; @@ -1938,9 +1867,8 @@ TEST_P(EndToEndTest, 0ByteConnectionId) { EXPECT_EQ(CONNECTION_ID_ABSENT, header->source_connection_id_included); } -TEST_P(EndToEndTestWithTls, 8ByteConnectionId) { - if (VersionHasIetfInvariantHeader( - GetParam().negotiated_version.transport_version)) { +TEST_P(EndToEndTest, 8ByteConnectionId) { + if (VersionHasIetfInvariantHeader(version_.transport_version)) { // SetBytesForConnectionIdToSend only applies to Google QUIC encoding. ASSERT_TRUE(Initialize()); return; @@ -1956,9 +1884,8 @@ TEST_P(EndToEndTestWithTls, 8ByteConnectionId) { EXPECT_EQ(CONNECTION_ID_PRESENT, header->destination_connection_id_included); } -TEST_P(EndToEndTestWithTls, 15ByteConnectionId) { - if (VersionHasIetfInvariantHeader( - GetParam().negotiated_version.transport_version)) { +TEST_P(EndToEndTest, 15ByteConnectionId) { + if (VersionHasIetfInvariantHeader(version_.transport_version)) { // SetBytesForConnectionIdToSend only applies to Google QUIC encoding. ASSERT_TRUE(Initialize()); return; @@ -1975,7 +1902,7 @@ TEST_P(EndToEndTestWithTls, 15ByteConnectionId) { EXPECT_EQ(CONNECTION_ID_PRESENT, header->destination_connection_id_included); } -TEST_P(EndToEndTestWithTls, ResetConnection) { +TEST_P(EndToEndTest, ResetConnection) { ASSERT_TRUE(Initialize()); EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); @@ -1986,8 +1913,6 @@ TEST_P(EndToEndTestWithTls, ResetConnection) { EXPECT_EQ("200", client_->response_headers()->find(":status")->second); } -// TODO(nharper): Needs to get turned back to EndToEndTestWithTls -// when we figure out why the test doesn't work on chrome. TEST_P(EndToEndTest, MaxStreamsUberTest) { // Connect with lower fake packet loss than we'd like to test. Until // b/10126687 is fixed, losing handshake packets is pretty brutal. @@ -2011,7 +1936,7 @@ TEST_P(EndToEndTest, MaxStreamsUberTest) { } } -TEST_P(EndToEndTestWithTls, StreamCancelErrorTest) { +TEST_P(EndToEndTest, StreamCancelErrorTest) { ASSERT_TRUE(Initialize()); std::string small_body(256, 'a'); @@ -2027,7 +1952,11 @@ TEST_P(EndToEndTestWithTls, StreamCancelErrorTest) { // Transmit the cancel, and ensure the connection is torn down properly. SetPacketLossPercentage(0); QuicStreamId stream_id = GetNthClientInitiatedBidirectionalId(0); - session->SendRstStream(stream_id, QUIC_STREAM_CANCELLED, 0); + if (session->break_close_loop()) { + session->ResetStream(stream_id, QUIC_STREAM_CANCELLED, 0); + } else { + session->SendRstStream(stream_id, QUIC_STREAM_CANCELLED, 0); + } // WaitForEvents waits 50ms and returns true if there are outstanding // requests. @@ -2131,6 +2060,11 @@ TEST_P(EndToEndTest, NegotiatedInitialCongestionWindow) { } TEST_P(EndToEndTest, DifferentFlowControlWindows) { + if (version_.UsesTls()) { + // TODO(b/155316241): Enable this test for TLS. + Initialize(); + return; + } // Client and server can set different initial flow control receive windows. // These are sent in CHLO/SHLO. Tests that these values are exchanged properly // in the crypto handshake. @@ -2185,6 +2119,11 @@ TEST_P(EndToEndTest, DifferentFlowControlWindows) { // Test negotiation of IFWA connection option. TEST_P(EndToEndTest, NegotiatedServerInitialFlowControlWindow) { + if (version_.UsesTls()) { + // TODO(b/155316241): Enable this test for TLS. + Initialize(); + return; + } const uint32_t kClientStreamIFCW = 123456; const uint32_t kClientSessionIFCW = 234567; set_client_initial_stream_flow_control_receive_window(kClientStreamIFCW); @@ -2395,7 +2334,7 @@ TEST_P(EndToEndTest, FlowControlsSynced) { server_thread_->Resume(); } -TEST_P(EndToEndTestWithTls, RequestWithNoBodyWillNeverSendStreamFrameWithFIN) { +TEST_P(EndToEndTest, RequestWithNoBodyWillNeverSendStreamFrameWithFIN) { // A stream created on receipt of a simple request with no body will never get // a stream frame with a FIN. Verify that we don't keep track of the stream in // the locally closed streams map: it will never be removed if so. @@ -2414,8 +2353,8 @@ TEST_P(EndToEndTestWithTls, RequestWithNoBodyWillNeverSendStreamFrameWithFIN) { server_thread_->Resume(); } -// A TestAckListener verifies that its OnAckNotification method has been -// called exactly once on destruction. +// A TestAckListener verifies that exactly |bytes_to_ack| bytes are acked during +// its lifetime. class TestAckListener : public QuicAckListenerInterface { public: explicit TestAckListener(int bytes_to_ack) : bytes_to_ack_(bytes_to_ack) {} @@ -2449,12 +2388,14 @@ class TestResponseListener : public QuicSpdyClientBase::ResponseListener { } }; -TEST_P(EndToEndTest, AckNotifierWithPacketLossAndBlockedSocket) { +// TODO(dschinazi) Fix this test's flakiness in Chrome. +TEST_P( + EndToEndTest, + QUIC_TEST_DISABLED_IN_CHROME(AckNotifierWithPacketLossAndBlockedSocket)) { // Verify that even in the presence of packet loss and occasionally blocked // socket, an AckNotifierDelegate will get informed that the data it is // interested in has been ACKed. This tests end-to-end ACK notification, and // demonstrates that retransmissions do not break this functionality. - SetPacketLossPercentage(5); ASSERT_TRUE(Initialize()); @@ -2485,6 +2426,12 @@ TEST_P(EndToEndTest, AckNotifierWithPacketLossAndBlockedSocket) { QpackEncoder qpack_encoder(&decoder_stream_error_delegate); qpack_encoder.set_qpack_stream_sender_delegate( &encoder_stream_sender_delegate); + + qpack_encoder.SetMaximumDynamicTableCapacity( + kDefaultQpackMaxDynamicTableCapacity); + qpack_encoder.SetDynamicTableCapacity(kDefaultQpackMaxDynamicTableCapacity); + qpack_encoder.SetMaximumBlockedStreams(kDefaultMaximumBlockedStreams); + std::string encoded_headers = qpack_encoder.EncodeHeaderList(/* stream_id = */ 0, headers, nullptr); header_size = encoded_headers.size(); @@ -2516,7 +2463,7 @@ TEST_P(EndToEndTest, AckNotifierWithPacketLossAndBlockedSocket) { } // Send a public reset from the server. -TEST_P(EndToEndTestWithTls, ServerSendPublicReset) { +TEST_P(EndToEndTest, ServerSendPublicReset) { ASSERT_TRUE(Initialize()); EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); @@ -2554,7 +2501,7 @@ TEST_P(EndToEndTestWithTls, ServerSendPublicReset) { // Send a public reset from the server for a different connection ID. // It should be ignored. -TEST_P(EndToEndTestWithTls, ServerSendPublicResetWithDifferentConnectionId) { +TEST_P(EndToEndTest, ServerSendPublicResetWithDifferentConnectionId) { ASSERT_TRUE(Initialize()); EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); @@ -2607,7 +2554,7 @@ TEST_P(EndToEndTestWithTls, ServerSendPublicResetWithDifferentConnectionId) { // Send a public reset from the client for a different connection ID. // It should be ignored. -TEST_P(EndToEndTestWithTls, ClientSendPublicResetWithDifferentConnectionId) { +TEST_P(EndToEndTest, ClientSendPublicResetWithDifferentConnectionId) { ASSERT_TRUE(Initialize()); // Send the public reset. @@ -2631,8 +2578,7 @@ TEST_P(EndToEndTestWithTls, ClientSendPublicResetWithDifferentConnectionId) { // Send a version negotiation packet from the server for a different // connection ID. It should be ignored. -TEST_P(EndToEndTestWithTls, - ServerSendVersionNegotiationWithDifferentConnectionId) { +TEST_P(EndToEndTest, ServerSendVersionNegotiationWithDifferentConnectionId) { ASSERT_TRUE(Initialize()); EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); @@ -2668,7 +2614,7 @@ TEST_P(EndToEndTestWithTls, // A bad header shouldn't tear down the connection, because the receiver can't // tell the connection ID. -TEST_P(EndToEndTestWithTls, BadPacketHeaderTruncated) { +TEST_P(EndToEndTest, BadPacketHeaderTruncated) { ASSERT_TRUE(Initialize()); // Start the connection. @@ -2699,7 +2645,7 @@ TEST_P(EndToEndTestWithTls, BadPacketHeaderTruncated) { // A bad header shouldn't tear down the connection, because the receiver can't // tell the connection ID. -TEST_P(EndToEndTestWithTls, BadPacketHeaderFlags) { +TEST_P(EndToEndTest, BadPacketHeaderFlags) { ASSERT_TRUE(Initialize()); // Start the connection. @@ -2749,7 +2695,7 @@ TEST_P(EndToEndTestWithTls, BadPacketHeaderFlags) { // Send a packet from the client with bad encrypted data. The server should not // tear down the connection. -TEST_P(EndToEndTestWithTls, BadEncryptedData) { +TEST_P(EndToEndTest, BadEncryptedData) { ASSERT_TRUE(Initialize()); // Start the connection. @@ -2785,7 +2731,7 @@ TEST_P(EndToEndTestWithTls, BadEncryptedData) { EXPECT_EQ("200", client_->response_headers()->find(":status")->second); } -TEST_P(EndToEndTestWithTls, CanceledStreamDoesNotBecomeZombie) { +TEST_P(EndToEndTest, CanceledStreamDoesNotBecomeZombie) { ASSERT_TRUE(Initialize()); EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); // Lose the request. @@ -3033,7 +2979,7 @@ TEST_P(EndToEndTest, EarlyResponseFinRecording) { server_thread_->Resume(); } -TEST_P(EndToEndTestWithTls, Trailers) { +TEST_P(EndToEndTest, Trailers) { // Test sending and receiving HTTP/2 Trailers (trailing HEADERS frames). ASSERT_TRUE(Initialize()); EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); @@ -3117,7 +3063,7 @@ class EndToEndTestServerPush : public EndToEndTest { // Run all server push end to end tests with all supported versions. INSTANTIATE_TEST_SUITE_P(EndToEndTestsServerPush, EndToEndTestServerPush, - ::testing::ValuesIn(GetTestParams(false)), + ::testing::ValuesIn(GetTestParams()), ::testing::PrintToStringParamName()); TEST_P(EndToEndTestServerPush, ServerPush) { @@ -3177,6 +3123,11 @@ TEST_P(EndToEndTestServerPush, ServerPush) { } TEST_P(EndToEndTestServerPush, ServerPushUnderLimit) { + if (version_.UsesTls()) { + // TODO(b/155316241): Enable this test for TLS. + Initialize(); + return; + } // Tests that sending a request which has 4 push resources will trigger server // to push those 4 resources and client can handle pushed resources and match // them with requests later. @@ -3226,6 +3177,11 @@ TEST_P(EndToEndTestServerPush, ServerPushUnderLimit) { } TEST_P(EndToEndTestServerPush, ServerPushOverLimitNonBlocking) { + if (version_.UsesTls()) { + // TODO(b/155316241): Enable this test for TLS. + Initialize(); + return; + } // Tests that when streams are not blocked by flow control or congestion // control, pushing even more resources than max number of open outgoing // streams should still work because all response streams get closed @@ -3284,6 +3240,11 @@ TEST_P(EndToEndTestServerPush, ServerPushOverLimitNonBlocking) { } TEST_P(EndToEndTestServerPush, ServerPushOverLimitWithBlocking) { + if (version_.UsesTls()) { + // TODO(b/155316241): Enable this test for TLS. + Initialize(); + return; + } // Tests that when server tries to send more large resources(large enough to // be blocked by flow control window or congestion control window) than max // open outgoing streams , server can open upto max number of outgoing @@ -3495,16 +3456,17 @@ TEST_P(EndToEndTest, WayTooLongRequestHeaders) { headers[":path"] = "/foo"; headers[":scheme"] = "https"; headers[":authority"] = server_hostname_; - headers["key"] = std::string(64 * 1024, 'a'); + headers["key"] = std::string(64 * 1024 * 1024, 'a'); client_->SendMessage(headers, ""); client_->WaitForResponse(); - - QuicErrorCode expected_error = - GetQuicReloadableFlag(spdy_enable_granular_decompress_errors) - ? QUIC_HPACK_INDEX_VARINT_ERROR - : QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE; - EXPECT_THAT(client_->connection_error(), IsError(expected_error)); + if (VersionUsesHttp3(version_.transport_version)) { + EXPECT_THAT(client_->connection_error(), + IsError(QUIC_QPACK_DECOMPRESSION_FAILED)); + } else { + EXPECT_THAT(client_->connection_error(), + IsError(QUIC_HPACK_INDEX_VARINT_ERROR)); + } } class WindowUpdateObserver : public QuicConnectionDebugVisitor { @@ -3550,7 +3512,7 @@ TEST_P(EndToEndTest, WindowUpdateInAck) { EXPECT_EQ(0u, observer.num_ping_frames()); } -TEST_P(EndToEndTestWithTls, SendStatelessResetTokenInShlo) { +TEST_P(EndToEndTest, SendStatelessResetTokenInShlo) { ASSERT_TRUE(Initialize()); EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); QuicConfig* config = client_->client()->session()->config(); @@ -3564,6 +3526,10 @@ TEST_P(EndToEndTestWithTls, SendStatelessResetTokenInShlo) { // Regression test for b/116200989. TEST_P(EndToEndTest, SendStatelessResetIfServerConnectionClosedLocallyDuringHandshake) { + if (!GetQuicReloadableFlag(quic_notify_handshaker_on_connection_close)) { + ASSERT_TRUE(Initialize()); + return; + } connect_to_server_on_initialize_ = false; ASSERT_TRUE(Initialize()); @@ -3668,6 +3634,16 @@ TEST_P(EndToEndTest, PreSharedKey) { QuicTime::Delta::FromSeconds(5)); pre_shared_key_client_ = "foobar"; pre_shared_key_server_ = "foobar"; + + if (version_.UsesTls()) { + // TODO(b/154162689) add PSK support to QUIC+TLS. + bool ok; + EXPECT_QUIC_BUG(ok = Initialize(), + "QUIC client pre-shared keys not yet supported with TLS"); + EXPECT_FALSE(ok); + return; + } + ASSERT_TRUE(Initialize()); ASSERT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); @@ -3682,6 +3658,16 @@ TEST_P(EndToEndTest, QUIC_TEST_DISABLED_IN_CHROME(PreSharedKeyMismatch)) { QuicTime::Delta::FromSeconds(1)); pre_shared_key_client_ = "foo"; pre_shared_key_server_ = "bar"; + + if (version_.UsesTls()) { + // TODO(b/154162689) add PSK support to QUIC+TLS. + bool ok; + EXPECT_QUIC_BUG(ok = Initialize(), + "QUIC client pre-shared keys not yet supported with TLS"); + EXPECT_FALSE(ok); + return; + } + // One of two things happens when Initialize() returns: // 1. Crypto handshake has completed, and it is unsuccessful. Initialize() // returns false. @@ -3700,6 +3686,16 @@ TEST_P(EndToEndTest, QUIC_TEST_DISABLED_IN_CHROME(PreSharedKeyNoClient)) { client_config_.set_max_idle_time_before_crypto_handshake( QuicTime::Delta::FromSeconds(1)); pre_shared_key_server_ = "foobar"; + + if (version_.UsesTls()) { + // TODO(b/154162689) add PSK support to QUIC+TLS. + bool ok; + EXPECT_QUIC_BUG(ok = Initialize(), + "QUIC server pre-shared keys not yet supported with TLS"); + EXPECT_FALSE(ok); + return; + } + ASSERT_FALSE(Initialize() && client_->client()->WaitForCryptoHandshakeConfirmed()); EXPECT_THAT(client_->connection_error(), IsError(QUIC_HANDSHAKE_TIMEOUT)); @@ -3712,6 +3708,16 @@ TEST_P(EndToEndTest, QUIC_TEST_DISABLED_IN_CHROME(PreSharedKeyNoServer)) { client_config_.set_max_idle_time_before_crypto_handshake( QuicTime::Delta::FromSeconds(1)); pre_shared_key_client_ = "foobar"; + + if (version_.UsesTls()) { + // TODO(b/154162689) add PSK support to QUIC+TLS. + bool ok; + EXPECT_QUIC_BUG(ok = Initialize(), + "QUIC client pre-shared keys not yet supported with TLS"); + EXPECT_FALSE(ok); + return; + } + ASSERT_FALSE(Initialize() && client_->client()->WaitForCryptoHandshakeConfirmed()); EXPECT_THAT(client_->connection_error(), IsError(QUIC_HANDSHAKE_TIMEOUT)); @@ -3770,13 +3776,14 @@ TEST_P(EndToEndTest, ResetStreamOnTtlExpires) { } TEST_P(EndToEndTest, SendMessages) { + if (!VersionSupportsMessageFrames(version_.transport_version)) { + Initialize(); + return; + } ASSERT_TRUE(Initialize()); EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); QuicSession* client_session = GetClientSession(); QuicConnection* client_connection = client_session->connection(); - if (!VersionSupportsMessageFrames(client_connection->transport_version())) { - return; - } SetPacketLossPercentage(30); ASSERT_GT(kMaxOutgoingPacketSize, @@ -3806,7 +3813,7 @@ TEST_P(EndToEndTest, SendMessages) { for (size_t i = 2; i <= kTestMaxNumberOfMessages; ++i) { size_t message_length = random->RandUint64() % - client_session->GetCurrentLargestMessagePayload() + + client_session->GetGuaranteedLargestMessagePayload() + 1; MessageResult result = client_session->SendMessage(MakeSpan( client_session->connection() @@ -3856,11 +3863,16 @@ class EndToEndPacketReorderingTest : public EndToEndTest { INSTANTIATE_TEST_SUITE_P(EndToEndPacketReorderingTests, EndToEndPacketReorderingTest, - ::testing::ValuesIn(GetTestParams(false)), + ::testing::ValuesIn(GetTestParams()), ::testing::PrintToStringParamName()); TEST_P(EndToEndPacketReorderingTest, ReorderedConnectivityProbing) { ASSERT_TRUE(Initialize()); + if (version_.HasIetfQuicFrames()) { + // TODO(b/143909619): Reenable this test when supporting IETF connection + // migration. + return; + } // Finish one request to make sure handshake established. EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); @@ -3904,6 +3916,11 @@ TEST_P(EndToEndPacketReorderingTest, ReorderedConnectivityProbing) { } TEST_P(EndToEndPacketReorderingTest, Buffer0RttRequest) { + if (version_.UsesTls()) { + // TODO(b/152551499): Re-enable this test when TLS supports 0-RTT. + Initialize(); + return; + } ASSERT_TRUE(Initialize()); // Finish one request to make sure handshake established. client_->SendSynchronousRequest("/foo"); @@ -3930,22 +3947,59 @@ TEST_P(EndToEndPacketReorderingTest, Buffer0RttRequest) { client_->WaitForResponse(); EXPECT_EQ(kBarResponseBody, client_->response_body()); QuicConnectionStats client_stats = GetClientConnection()->GetStats(); - EXPECT_EQ(0u, client_stats.packets_lost); + if (GetQuicReloadableFlag(quic_advance_ack_timeout_update)) { + // Client sends CHLO in packet 1 and retransmitted in packet 2. Because of + // the delay, server processes packet 2 and later drops packet 1. ACK is + // bundled with SHLO, such that 1 can be detected loss by time threshold. + EXPECT_LE(0u, client_stats.packets_lost); + } else { + EXPECT_EQ(0u, client_stats.packets_lost); + } EXPECT_TRUE(client_->client()->EarlyDataAccepted()); } +// This observer is used to check whether stream write side is closed when +// receiving STOP_SENDING (which ends up as noop). +class StopSendingObserver : public QuicConnectionDebugVisitor { + public: + explicit StopSendingObserver(QuicTestClient* client) + : num_stop_sending_frames_(0), + client_(client), + stream_write_side_closed_before_receiving_stop_sending_(false) {} + + void OnStopSendingFrame(const QuicStopSendingFrame& /*frame*/) override { + ++num_stop_sending_frames_; + stream_write_side_closed_before_receiving_stop_sending_ = + static_cast<QuicSimpleClientStream*>(client_->latest_created_stream()) + ->write_side_closed(); + } + + size_t num_stop_sending_frames() const { return num_stop_sending_frames_; } + + bool stream_write_side_closed_before_receiving_stop_sending() const { + return stream_write_side_closed_before_receiving_stop_sending_; + } + + private: + size_t num_stop_sending_frames_; + QuicTestClient* client_; + bool stream_write_side_closed_before_receiving_stop_sending_; +}; + // Test that STOP_SENDING makes it to the peer. Create a stream and send a // STOP_SENDING. The receiver should get a call to QuicStream::OnStopSending. TEST_P(EndToEndTest, SimpleStopSendingTest) { const uint16_t kStopSendingTestCode = 123; ASSERT_TRUE(Initialize()); - if (!VersionHasIetfQuicFrames(negotiated_version_.transport_version)) { + if (!VersionHasIetfQuicFrames(version_.transport_version)) { return; } QuicSession* client_session = GetClientSession(); ASSERT_NE(nullptr, client_session); + StopSendingObserver observer(client_.get()); QuicConnection* client_connection = client_session->connection(); ASSERT_NE(nullptr, client_connection); + client_connection->set_debug_visitor(&observer); std::string response_body(1305, 'a'); SpdyHeaderBlock response_headers; @@ -3960,16 +4014,9 @@ TEST_P(EndToEndTest, SimpleStopSendingTest) { client_->WaitForDelayedAcks(); QuicSession* session = GetClientSession(); - const QuicPacketCount packets_sent_before = - session->connection()->GetStats().packets_sent; QuicStreamId stream_id = session->next_outgoing_bidirectional_stream_id(); client_->SendRequest("/test_url"); - - // Expect exactly one packet is sent from the block above. - ASSERT_EQ(packets_sent_before + 1, - session->connection()->GetStats().packets_sent); - // Wait for the connection to become idle. client_->WaitForDelayedAcks(); @@ -3980,8 +4027,12 @@ TEST_P(EndToEndTest, SimpleStopSendingTest) { // Ensure the stream has been write closed upon receiving STOP_SENDING. EXPECT_EQ(stream_id, client_stream->id()); EXPECT_TRUE(client_stream->write_side_closed()); - EXPECT_EQ(kStopSendingTestCode, - static_cast<uint16_t>(client_stream->stream_error())); + client_->WaitUntil( + -1, [&observer]() { return observer.num_stop_sending_frames() > 0; }); + if (!observer.stream_write_side_closed_before_receiving_stop_sending()) { + EXPECT_EQ(kStopSendingTestCode, + static_cast<uint16_t>(client_stream->stream_error())); + } } TEST_P(EndToEndTest, SimpleStopSendingRstStreamTest) { @@ -4036,15 +4087,18 @@ class BadShloPacketWriter : public QuicPacketWriterWrapper { }; TEST_P(EndToEndTest, ZeroRttProtectedConnectionClose) { + if (version_.UsesTls() || + !VersionHasIetfInvariantHeader(version_.transport_version)) { + // TODO(b/152551499): Re-enable this test when TLS supports 0-RTT. + // Only runs for IETF QUIC header. + Initialize(); + return; + } // This test ensures ZERO_RTT_PROTECTED connection close could close a client // which has switched to forward secure. connect_to_server_on_initialize_ = - !VersionHasIetfInvariantHeader(negotiated_version_.transport_version); + !VersionHasIetfInvariantHeader(version_.transport_version); ASSERT_TRUE(Initialize()); - if (!VersionHasIetfInvariantHeader(negotiated_version_.transport_version)) { - // Only runs for IETF QUIC header. - return; - } server_thread_->Pause(); QuicDispatcher* dispatcher = QuicServerPeer::GetDispatcher(server_thread_->server()); @@ -4100,9 +4154,9 @@ TEST_P(EndToEndTest, ForwardSecureConnectionClose) { // This test ensures ZERO_RTT_PROTECTED connection close is sent to a client // which has ZERO_RTT_PROTECTED encryption level. connect_to_server_on_initialize_ = - !VersionHasIetfInvariantHeader(negotiated_version_.transport_version); + !VersionHasIetfInvariantHeader(version_.transport_version); ASSERT_TRUE(Initialize()); - if (!VersionHasIetfInvariantHeader(negotiated_version_.transport_version)) { + if (!VersionHasIetfInvariantHeader(version_.transport_version)) { // Only runs for IETF QUIC header. return; } @@ -4130,7 +4184,7 @@ TEST_P(EndToEndTest, ForwardSecureConnectionClose) { TEST_P(EndToEndTest, TooBigStreamIdClosesConnection) { // Has to be before version test, see EndToEndTest::TearDown() ASSERT_TRUE(Initialize()); - if (!VersionHasIetfQuicFrames(negotiated_version_.transport_version)) { + if (!VersionHasIetfQuicFrames(version_.transport_version)) { // Only runs for IETF QUIC. return; } @@ -4162,12 +4216,15 @@ TEST_P(EndToEndTest, TooBigStreamIdClosesConnection) { } TEST_P(EndToEndTest, TestMaxPushId) { - // Has to be before version test, see EndToEndTest::TearDown() - ASSERT_TRUE(Initialize()); - if (!VersionHasIetfQuicFrames(negotiated_version_.transport_version)) { + if (version_.UsesTls() || + !VersionHasIetfQuicFrames(version_.transport_version)) { + // TODO(b/155316241): Enable this test for TLS. // Only runs for IETF QUIC. + Initialize(); return; } + // Has to be before version test, see EndToEndTest::TearDown() + ASSERT_TRUE(Initialize()); EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); static_cast<QuicSpdySession*>(client_->client()->session()) @@ -4182,12 +4239,8 @@ TEST_P(EndToEndTest, TestMaxPushId) { ->CanCreatePushStreamWithId(kMaxQuicStreamId)); } -TEST_P(EndToEndTest, CustomTransportParameters) { - if (GetParam().negotiated_version.handshake_protocol != PROTOCOL_TLS1_3) { - Initialize(); - return; - } - +TEST_P(EndToEndTest, DISABLED_CustomTransportParameters) { + // TODO(b/155316241): Enable this test. constexpr auto kCustomParameter = static_cast<TransportParameters::TransportParameterId>(0xff34); client_config_.custom_transport_parameters_to_send()[kCustomParameter] = diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_constants.h b/chromium/net/third_party/quiche/src/quic/core/http/http_constants.h index fbf30696de7..17afe1bea19 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/http_constants.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/http_constants.h @@ -20,6 +20,9 @@ const uint64_t kServerPushStream = 0x01; const uint64_t kQpackEncoderStream = 0x02; const uint64_t kQpackDecoderStream = 0x03; +// This includes control stream, QPACK encoder stream, and QPACK decoder stream. +const QuicStreamCount kHttp3StaticUnidirectionalStreamCount = 3; + // HTTP/3 and QPACK settings identifiers. // https://quicwg.org/base-drafts/draft-ietf-quic-http.html#settings-parameters // https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#configuration diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.cc b/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.cc index 87f9919d296..d6c97ee7add 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.cc @@ -11,6 +11,7 @@ #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" #include "net/third_party/quiche/src/quic/platform/api/quic_fallthrough.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" namespace quic { @@ -34,6 +35,50 @@ HttpDecoder::HttpDecoder(Visitor* visitor) HttpDecoder::~HttpDecoder() {} +// static +bool HttpDecoder::DecodeSettings(const char* data, + QuicByteCount len, + SettingsFrame* frame) { + QuicDataReader reader(data, len); + uint64_t frame_type; + if (!reader.ReadVarInt62(&frame_type)) { + QUIC_DLOG(ERROR) << "Unable to read frame type."; + return false; + } + + if (frame_type != static_cast<uint64_t>(HttpFrameType::SETTINGS)) { + QUIC_DLOG(ERROR) << "Invalid frame type " << frame_type; + return false; + } + + quiche::QuicheStringPiece frame_contents; + if (!reader.ReadStringPieceVarInt62(&frame_contents)) { + QUIC_DLOG(ERROR) << "Failed to read SETTINGS frame contents"; + return false; + } + + QuicDataReader frame_reader(frame_contents); + + while (!frame_reader.IsDoneReading()) { + uint64_t id; + if (!frame_reader.ReadVarInt62(&id)) { + QUIC_DLOG(ERROR) << "Unable to read setting identifier."; + return false; + } + uint64_t content; + if (!frame_reader.ReadVarInt62(&content)) { + QUIC_DLOG(ERROR) << "Unable to read setting value."; + return false; + } + auto result = frame->values.insert({id, content}); + if (!result.second) { + QUIC_DLOG(ERROR) << "Duplicate setting identifier."; + return false; + } + } + return true; +} + QuicByteCount HttpDecoder::ProcessInput(const char* data, QuicByteCount len) { DCHECK_EQ(QUIC_NO_ERROR, error_); DCHECK_NE(STATE_ERROR, state_); diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.h b/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.h index 3650bef572e..1551aa7d275 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.h @@ -131,6 +131,13 @@ class QUIC_EXPORT_PRIVATE HttpDecoder { // occurred. QuicByteCount ProcessInput(const char* data, QuicByteCount len); + // Decode settings frame from |data|. + // Upon successful decoding, |frame| will be populated, and returns true. + // This method is not used for regular processing of incoming data. + static bool DecodeSettings(const char* data, + QuicByteCount len, + SettingsFrame* frame); + // Returns an error code other than QUIC_NO_ERROR if and only if // Visitor::OnError() has been called. QuicErrorCode error() const { return error_; } diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_decoder_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/http_decoder_test.cc index 2e8885c9dd7..86a1b6932ec 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/http_decoder_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/http_decoder_test.cc @@ -39,42 +39,79 @@ class MockVisitor : public HttpDecoder::Visitor { ~MockVisitor() override = default; // Called if an error is detected. - MOCK_METHOD1(OnError, void(HttpDecoder* decoder)); - - MOCK_METHOD1(OnCancelPushFrame, bool(const CancelPushFrame& frame)); - MOCK_METHOD1(OnMaxPushIdFrame, bool(const MaxPushIdFrame& frame)); - MOCK_METHOD1(OnGoAwayFrame, bool(const GoAwayFrame& frame)); - MOCK_METHOD1(OnSettingsFrameStart, bool(QuicByteCount header_length)); - MOCK_METHOD1(OnSettingsFrame, bool(const SettingsFrame& frame)); - - MOCK_METHOD2(OnDataFrameStart, - bool(QuicByteCount header_length, QuicByteCount payload_length)); - MOCK_METHOD1(OnDataFramePayload, bool(quiche::QuicheStringPiece payload)); - MOCK_METHOD0(OnDataFrameEnd, bool()); - - MOCK_METHOD2(OnHeadersFrameStart, - bool(QuicByteCount header_length, QuicByteCount payload_length)); - MOCK_METHOD1(OnHeadersFramePayload, bool(quiche::QuicheStringPiece payload)); - MOCK_METHOD0(OnHeadersFrameEnd, bool()); - - MOCK_METHOD1(OnPushPromiseFrameStart, bool(QuicByteCount header_length)); - MOCK_METHOD3(OnPushPromiseFramePushId, - bool(PushId push_id, - QuicByteCount push_id_length, - QuicByteCount header_block_length)); - MOCK_METHOD1(OnPushPromiseFramePayload, - bool(quiche::QuicheStringPiece payload)); - MOCK_METHOD0(OnPushPromiseFrameEnd, bool()); - - MOCK_METHOD1(OnPriorityUpdateFrameStart, bool(QuicByteCount header_length)); - MOCK_METHOD1(OnPriorityUpdateFrame, bool(const PriorityUpdateFrame& frame)); - - MOCK_METHOD3(OnUnknownFrameStart, - bool(uint64_t frame_type, - QuicByteCount header_length, - QuicByteCount payload_length)); - MOCK_METHOD1(OnUnknownFramePayload, bool(quiche::QuicheStringPiece payload)); - MOCK_METHOD0(OnUnknownFrameEnd, bool()); + MOCK_METHOD(void, OnError, (HttpDecoder*), (override)); + + MOCK_METHOD(bool, + OnCancelPushFrame, + (const CancelPushFrame& frame), + (override)); + MOCK_METHOD(bool, + OnMaxPushIdFrame, + (const MaxPushIdFrame& frame), + (override)); + MOCK_METHOD(bool, OnGoAwayFrame, (const GoAwayFrame& frame), (override)); + MOCK_METHOD(bool, + OnSettingsFrameStart, + (QuicByteCount header_length), + (override)); + MOCK_METHOD(bool, OnSettingsFrame, (const SettingsFrame& frame), (override)); + + MOCK_METHOD(bool, + OnDataFrameStart, + (QuicByteCount header_length, QuicByteCount payload_length), + (override)); + MOCK_METHOD(bool, + OnDataFramePayload, + (quiche::QuicheStringPiece payload), + (override)); + MOCK_METHOD(bool, OnDataFrameEnd, (), (override)); + + MOCK_METHOD(bool, + OnHeadersFrameStart, + (QuicByteCount header_length, QuicByteCount payload_length), + (override)); + MOCK_METHOD(bool, + OnHeadersFramePayload, + (quiche::QuicheStringPiece payload), + (override)); + MOCK_METHOD(bool, OnHeadersFrameEnd, (), (override)); + + MOCK_METHOD(bool, + OnPushPromiseFrameStart, + (QuicByteCount header_length), + (override)); + MOCK_METHOD(bool, + OnPushPromiseFramePushId, + (PushId push_id, + QuicByteCount push_id_length, + QuicByteCount header_block_length), + (override)); + MOCK_METHOD(bool, + OnPushPromiseFramePayload, + (quiche::QuicheStringPiece payload), + (override)); + MOCK_METHOD(bool, OnPushPromiseFrameEnd, (), (override)); + + MOCK_METHOD(bool, + OnPriorityUpdateFrameStart, + (QuicByteCount header_length), + (override)); + MOCK_METHOD(bool, + OnPriorityUpdateFrame, + (const PriorityUpdateFrame& frame), + (override)); + + MOCK_METHOD(bool, + OnUnknownFrameStart, + (uint64_t frame_type, + QuicByteCount header_length, + QuicByteCount payload_length), + (override)); + MOCK_METHOD(bool, + OnUnknownFramePayload, + (quiche::QuicheStringPiece payload), + (override)); + MOCK_METHOD(bool, OnUnknownFrameEnd, (), (override)); }; class HttpDecoderTest : public QuicTest { @@ -1035,6 +1072,43 @@ TEST_F(HttpDecoderTest, CorruptPriorityUpdateFrame) { } } +TEST_F(HttpDecoderTest, DecodeSettings) { + std::string input = quiche::QuicheTextUtils::HexDecode( + "04" // type (SETTINGS) + "07" // length + "01" // identifier (SETTINGS_QPACK_MAX_TABLE_CAPACITY) + "02" // content + "06" // identifier (SETTINGS_MAX_HEADER_LIST_SIZE) + "05" // content + "4100" // identifier, encoded on 2 bytes (0x40), value is 256 (0x100) + "04"); // content + + SettingsFrame frame; + frame.values[1] = 2; + frame.values[6] = 5; + frame.values[256] = 4; + + SettingsFrame out; + EXPECT_TRUE(HttpDecoder::DecodeSettings(input.data(), input.size(), &out)); + EXPECT_EQ(frame, out); + + // non-settings frame. + input = quiche::QuicheTextUtils::HexDecode( + "0D" // type (MAX_PUSH_ID) + "01" // length + "01"); // Push Id + + EXPECT_FALSE(HttpDecoder::DecodeSettings(input.data(), input.size(), &out)); + + // Corrupt SETTINGS. + input = quiche::QuicheTextUtils::HexDecode( + "04" // type (SETTINGS) + "01" // length + "42"); // First byte of setting identifier, indicating a 2-byte varint62. + + EXPECT_FALSE(HttpDecoder::DecodeSettings(input.data(), input.size(), &out)); +} + } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info_test.cc index 27d9fe89630..a5996260d23 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info_test.cc @@ -52,7 +52,7 @@ class MockQuicSpdyClientSession : public QuicSpdyClientSession { void set_authorized(bool authorized) { authorized_ = authorized; } - MOCK_METHOD1(CloseStream, void(QuicStreamId stream_id)); + MOCK_METHOD(void, CloseStream, (QuicStreamId stream_id), (override)); private: QuicCryptoClientConfig crypto_config_; @@ -227,7 +227,9 @@ TEST_F(QuicClientPromisedInfoTest, PushPromiseMismatch) { EXPECT_CALL(*connection_, SendControlFrame(_)); EXPECT_CALL(*connection_, OnStreamReset(promise_id_, QUIC_PROMISE_VARY_MISMATCH)); - EXPECT_CALL(session_, CloseStream(promise_id_)); + if (!session_.break_close_loop()) { + EXPECT_CALL(session_, CloseStream(promise_id_)); + } promised->HandleClientRequest(client_request_, &delegate); } @@ -303,7 +305,9 @@ TEST_F(QuicClientPromisedInfoTest, PushPromiseWaitCancels) { session_.GetOrCreateStream(promise_id_); // Cancel the promised stream. - EXPECT_CALL(session_, CloseStream(promise_id_)); + if (!session_.break_close_loop()) { + EXPECT_CALL(session_, CloseStream(promise_id_)); + } EXPECT_CALL(*connection_, SendControlFrame(_)); EXPECT_CALL(*connection_, OnStreamReset(promise_id_, QUIC_STREAM_CANCELLED)); promised->Cancel(); @@ -327,11 +331,17 @@ TEST_F(QuicClientPromisedInfoTest, PushPromiseDataClosed) { promise_stream->OnStreamHeaderList(false, headers.uncompressed_header_bytes(), headers); - EXPECT_CALL(session_, CloseStream(promise_id_)); + if (!session_.break_close_loop()) { + EXPECT_CALL(session_, CloseStream(promise_id_)); + } EXPECT_CALL(*connection_, SendControlFrame(_)); EXPECT_CALL(*connection_, OnStreamReset(promise_id_, QUIC_STREAM_PEER_GOING_AWAY)); - session_.SendRstStream(promise_id_, QUIC_STREAM_PEER_GOING_AWAY, 0); + if (session_.break_close_loop()) { + session_.ResetStream(promise_id_, QUIC_STREAM_PEER_GOING_AWAY, 0); + } else { + session_.SendRstStream(promise_id_, QUIC_STREAM_PEER_GOING_AWAY, 0); + } // Now initiate rendezvous. TestPushPromiseDelegate delegate(/*match=*/true); diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index_test.cc index 3ca377eb729..0fc903a7283 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index_test.cc @@ -40,7 +40,7 @@ class MockQuicSpdyClientSession : public QuicSpdyClientSession { delete; ~MockQuicSpdyClientSession() override {} - MOCK_METHOD1(CloseStream, void(QuicStreamId stream_id)); + MOCK_METHOD(void, CloseStream, (QuicStreamId stream_id), (override)); private: QuicCryptoClientConfig crypto_config_; diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_header_list.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_header_list.cc index cbf60ceb252..cbfc2e9f73b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_header_list.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_header_list.cc @@ -7,10 +7,10 @@ #include <limits> #include <string> +#include "net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" -#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" namespace quic { @@ -43,7 +43,7 @@ void QuicHeaderList::OnHeader(quiche::QuicheStringPiece name, if (current_header_list_size_ < max_header_list_size_) { current_header_list_size_ += name.size(); current_header_list_size_ += value.size(); - current_header_list_size_ += spdy::kPerHeaderOverhead; + current_header_list_size_ += QpackEntry::kSizeOverhead; header_list_.emplace_back(std::string(name), std::string(value)); } } diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream_test.cc index 9395a708225..d9e1c8e8107 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream_test.cc @@ -78,66 +78,90 @@ class MockQuicHpackDebugVisitor : public QuicHpackDebugVisitor { MockQuicHpackDebugVisitor& operator=(const MockQuicHpackDebugVisitor&) = delete; - MOCK_METHOD1(OnUseEntry, void(QuicTime::Delta elapsed)); + MOCK_METHOD(void, OnUseEntry, (QuicTime::Delta elapsed), (override)); }; namespace { class MockVisitor : public SpdyFramerVisitorInterface { public: - MOCK_METHOD1(OnError, - void(http2::Http2DecoderAdapter::SpdyFramerError error)); - MOCK_METHOD3(OnDataFrameHeader, - void(SpdyStreamId stream_id, size_t length, bool fin)); - MOCK_METHOD3(OnStreamFrameData, - void(SpdyStreamId stream_id, const char* data, size_t len)); - MOCK_METHOD1(OnStreamEnd, void(SpdyStreamId stream_id)); - MOCK_METHOD2(OnStreamPadding, void(SpdyStreamId stream_id, size_t len)); - MOCK_METHOD1(OnHeaderFrameStart, - SpdyHeadersHandlerInterface*(SpdyStreamId stream_id)); - MOCK_METHOD1(OnHeaderFrameEnd, void(SpdyStreamId stream_id)); - MOCK_METHOD3(OnControlFrameHeaderData, - bool(SpdyStreamId stream_id, - const char* header_data, - size_t len)); - MOCK_METHOD2(OnRstStream, - void(SpdyStreamId stream_id, SpdyErrorCode error_code)); - MOCK_METHOD0(OnSettings, void()); - MOCK_METHOD2(OnSetting, void(SpdySettingsId id, uint32_t value)); - MOCK_METHOD0(OnSettingsAck, void()); - MOCK_METHOD0(OnSettingsEnd, void()); - MOCK_METHOD2(OnPing, void(SpdyPingId unique_id, bool is_ack)); - MOCK_METHOD2(OnGoAway, - void(SpdyStreamId last_accepted_stream_id, - SpdyErrorCode error_code)); - MOCK_METHOD7(OnHeaders, - void(SpdyStreamId stream_id, - bool has_priority, - int weight, - SpdyStreamId parent_stream_id, - bool exclusive, - bool fin, - bool end)); - MOCK_METHOD2(OnWindowUpdate, - void(SpdyStreamId stream_id, int delta_window_size)); - MOCK_METHOD1(OnBlocked, void(SpdyStreamId stream_id)); - MOCK_METHOD3(OnPushPromise, - void(SpdyStreamId stream_id, - SpdyStreamId promised_stream_id, - bool end)); - MOCK_METHOD2(OnContinuation, void(SpdyStreamId stream_id, bool end)); - MOCK_METHOD3(OnAltSvc, - void(SpdyStreamId stream_id, - quiche::QuicheStringPiece origin, - const SpdyAltSvcWireFormat::AlternativeServiceVector& - altsvc_vector)); - MOCK_METHOD4(OnPriority, - void(SpdyStreamId stream_id, - SpdyStreamId parent_stream_id, - int weight, - bool exclusive)); - MOCK_METHOD2(OnUnknownFrame, - bool(SpdyStreamId stream_id, uint8_t frame_type)); + MOCK_METHOD(void, + OnError, + (http2::Http2DecoderAdapter::SpdyFramerError error), + (override)); + MOCK_METHOD(void, + OnDataFrameHeader, + (SpdyStreamId stream_id, size_t length, bool fin), + (override)); + MOCK_METHOD(void, + OnStreamFrameData, + (SpdyStreamId stream_id, const char*, size_t len), + (override)); + MOCK_METHOD(void, OnStreamEnd, (SpdyStreamId stream_id), (override)); + MOCK_METHOD(void, + OnStreamPadding, + (SpdyStreamId stream_id, size_t len), + (override)); + MOCK_METHOD(SpdyHeadersHandlerInterface*, + OnHeaderFrameStart, + (SpdyStreamId stream_id), + (override)); + MOCK_METHOD(void, OnHeaderFrameEnd, (SpdyStreamId stream_id), (override)); + MOCK_METHOD(void, + OnRstStream, + (SpdyStreamId stream_id, SpdyErrorCode error_code), + (override)); + MOCK_METHOD(void, OnSettings, (), (override)); + MOCK_METHOD(void, OnSetting, (SpdySettingsId id, uint32_t value), (override)); + MOCK_METHOD(void, OnSettingsAck, (), (override)); + MOCK_METHOD(void, OnSettingsEnd, (), (override)); + MOCK_METHOD(void, OnPing, (SpdyPingId unique_id, bool is_ack), (override)); + MOCK_METHOD(void, + OnGoAway, + (SpdyStreamId last_accepted_stream_id, SpdyErrorCode error_code), + (override)); + MOCK_METHOD(void, + OnHeaders, + (SpdyStreamId stream_id, + bool has_priority, + int weight, + SpdyStreamId parent_stream_id, + bool exclusive, + bool fin, + bool end), + (override)); + MOCK_METHOD(void, + OnWindowUpdate, + (SpdyStreamId stream_id, int delta_window_size), + (override)); + MOCK_METHOD(void, + OnPushPromise, + (SpdyStreamId stream_id, + SpdyStreamId promised_stream_id, + bool end), + (override)); + MOCK_METHOD(void, + OnContinuation, + (SpdyStreamId stream_id, bool end), + (override)); + MOCK_METHOD( + void, + OnAltSvc, + (SpdyStreamId stream_id, + quiche::QuicheStringPiece origin, + const SpdyAltSvcWireFormat::AlternativeServiceVector& altsvc_vector), + (override)); + MOCK_METHOD(void, + OnPriority, + (SpdyStreamId stream_id, + SpdyStreamId parent_stream_id, + int weight, + bool exclusive), + (override)); + MOCK_METHOD(bool, + OnUnknownFrame, + (SpdyStreamId stream_id, uint8_t frame_type), + (override)); }; struct TestParams { @@ -350,8 +374,8 @@ class QuicHeadersStreamTest : public QuicTestWithParam<TestParams> { return next_promised_stream_id_ += next_stream_id_; } - static const bool kFrameComplete = true; - static const bool kHasPriority = true; + static constexpr bool kFrameComplete = true; + static constexpr bool kHasPriority = true; MockQuicConnectionHelper helper_; MockAlarmFactory alarm_factory_; diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.cc index 17c6ecc55cc..d24e3ddaa88 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.cc @@ -91,10 +91,7 @@ bool QuicReceiveControlStream::OnMaxPushIdFrame(const MaxPushIdFrame& frame) { return false; } - // TODO(b/124216424): Signal error if received push ID is smaller than a - // previously received value. - spdy_session()->OnMaxPushIdFrame(frame.push_id); - return true; + return spdy_session()->OnMaxPushIdFrame(frame.push_id); } bool QuicReceiveControlStream::OnGoAwayFrame(const GoAwayFrame& frame) { @@ -134,12 +131,7 @@ bool QuicReceiveControlStream::OnSettingsFrameStart( bool QuicReceiveControlStream::OnSettingsFrame(const SettingsFrame& frame) { QUIC_DVLOG(1) << "Control Stream " << id() << " received settings frame: " << frame; - if (spdy_session_->debug_visitor() != nullptr) { - spdy_session_->debug_visitor()->OnSettingsFrameReceived(frame); - } - for (const auto& setting : frame.values) { - spdy_session_->OnSetting(setting.first, setting.second); - } + spdy_session_->OnSettingsFrame(frame); return true; } diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc index 759c5a55a89..27db719fccd 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc @@ -201,15 +201,10 @@ bool QuicServerSessionBase::ShouldCreateIncomingStream(QuicStreamId id) { return false; } - if (GetQuicReloadableFlag(quic_create_incoming_stream_bug)) { - if (QuicUtils::IsServerInitiatedStreamId(transport_version(), id)) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_create_incoming_stream_bug, 1, 2); - QUIC_BUG << "ShouldCreateIncomingStream called with server initiated " - "stream ID."; - return false; - } else { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_create_incoming_stream_bug, 2, 2); - } + if (QuicUtils::IsServerInitiatedStreamId(transport_version(), id)) { + QUIC_BUG << "ShouldCreateIncomingStream called with server initiated " + "stream ID."; + return false; } if (QuicUtils::IsServerInitiatedStreamId(transport_version(), id)) { diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base_test.cc index 98cdf4927fc..c482856b61b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base_test.cc @@ -236,7 +236,7 @@ TEST_P(QuicServerSessionBaseTest, CloseStreamDueToReset) { QuicStreamFrame data1(GetNthClientInitiatedBidirectionalId(0), false, 0, quiche::QuicheStringPiece("HT")); session_->OnStreamFrame(data1); - EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams()); + EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); // Send a reset (and expect the peer to send a RST in response). QuicRstStreamFrame rst1(kInvalidControlFrameId, @@ -258,13 +258,12 @@ TEST_P(QuicServerSessionBaseTest, CloseStreamDueToReset) { InjectStopSendingFrame(GetNthClientInitiatedBidirectionalId(0), QUIC_ERROR_PROCESSING_STREAM); - EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); - + EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); // Send the same two bytes of payload in a new packet. session_->OnStreamFrame(data1); // The stream should not be re-opened. - EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); + EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); EXPECT_TRUE(connection_->connected()); } @@ -289,15 +288,14 @@ TEST_P(QuicServerSessionBaseTest, NeverOpenStreamDueToReset) { InjectStopSendingFrame(GetNthClientInitiatedBidirectionalId(0), QUIC_ERROR_PROCESSING_STREAM); - EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); - + EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); // Send two bytes of payload. QuicStreamFrame data1(GetNthClientInitiatedBidirectionalId(0), false, 0, quiche::QuicheStringPiece("HT")); session_->OnStreamFrame(data1); // The stream should never be opened, now that the reset is received. - EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); + EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); EXPECT_TRUE(connection_->connected()); } @@ -309,7 +307,7 @@ TEST_P(QuicServerSessionBaseTest, AcceptClosedStream) { quiche::QuicheStringPiece("\2\0\0\0\0\0\0\0HT")); session_->OnStreamFrame(frame1); session_->OnStreamFrame(frame2); - EXPECT_EQ(2u, session_->GetNumOpenIncomingStreams()); + EXPECT_EQ(2u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); // Send a reset (and expect the peer to send a RST in response). QuicRstStreamFrame rst(kInvalidControlFrameId, @@ -341,7 +339,7 @@ TEST_P(QuicServerSessionBaseTest, AcceptClosedStream) { session_->OnStreamFrame(frame3); session_->OnStreamFrame(frame4); // The stream should never be opened, now that the reset is received. - EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams()); + EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); EXPECT_TRUE(connection_->connected()); } @@ -361,7 +359,7 @@ TEST_P(QuicServerSessionBaseTest, MaxOpenStreams) { EXPECT_EQ(kMaxStreamsForTest + kMaxStreamsMinimumIncrement, session_->max_open_incoming_bidirectional_streams()); } - EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); + EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); QuicStreamId stream_id = GetNthClientInitiatedBidirectionalId(0); // Open the max configured number of streams, should be no problem. for (size_t i = 0; i < kMaxStreamsForTest; ++i) { @@ -407,7 +405,7 @@ TEST_P(QuicServerSessionBaseTest, MaxAvailableBidirectionalStreams) { const size_t kAvailableStreamLimit = session_->MaxAvailableBidirectionalStreams(); - EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); + EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateStream( session_.get(), GetNthClientInitiatedBidirectionalId(0))); @@ -477,22 +475,25 @@ class MockQuicCryptoServerStream : public QuicCryptoServerStream { delete; ~MockQuicCryptoServerStream() override {} - MOCK_METHOD1(SendServerConfigUpdate, - void(const CachedNetworkParameters* cached_network_parameters)); + MOCK_METHOD(void, + SendServerConfigUpdate, + (const CachedNetworkParameters*), + (override)); }; class MockTlsServerHandshaker : public TlsServerHandshaker { public: explicit MockTlsServerHandshaker(QuicServerSessionBase* session, - SSL_CTX* ssl_ctx, - ProofSource* proof_source) - : TlsServerHandshaker(session, ssl_ctx, proof_source) {} + const QuicCryptoServerConfig& crypto_config) + : TlsServerHandshaker(session, crypto_config) {} MockTlsServerHandshaker(const MockTlsServerHandshaker&) = delete; MockTlsServerHandshaker& operator=(const MockTlsServerHandshaker&) = delete; ~MockTlsServerHandshaker() override {} - MOCK_METHOD1(SendServerConfigUpdate, - void(const CachedNetworkParameters* cached_network_parameters)); + MOCK_METHOD(void, + SendServerConfigUpdate, + (const CachedNetworkParameters*), + (override)); }; TEST_P(QuicServerSessionBaseTest, BandwidthEstimates) { @@ -532,8 +533,7 @@ TEST_P(QuicServerSessionBaseTest, BandwidthEstimates) { quic_crypto_stream); } else { tls_server_stream = - new MockTlsServerHandshaker(session_.get(), crypto_config_.ssl_ctx(), - crypto_config_.proof_source()); + new MockTlsServerHandshaker(session_.get(), crypto_config_); QuicServerSessionBasePeer::SetCryptoStream(session_.get(), tls_server_stream); } diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.cc index 07b9c7aac84..6127e1b682e 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.cc @@ -136,15 +136,10 @@ bool QuicSpdyClientSession::ShouldCreateIncomingStream(QuicStreamId id) { return false; } - if (GetQuicReloadableFlag(quic_create_incoming_stream_bug)) { - if (QuicUtils::IsClientInitiatedStreamId(transport_version(), id)) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_create_incoming_stream_bug, 1, 2); - QUIC_BUG << "ShouldCreateIncomingStream called with client initiated " - "stream ID."; - return false; - } else { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_create_incoming_stream_bug, 2, 2); - } + if (QuicUtils::IsClientInitiatedStreamId(transport_version(), id)) { + QUIC_BUG << "ShouldCreateIncomingStream called with client initiated " + "stream ID."; + return false; } if (QuicUtils::IsClientInitiatedStreamId(transport_version(), id)) { @@ -191,7 +186,7 @@ QuicSpdyClientSession::CreateQuicCryptoStream() { return std::make_unique<QuicCryptoClientStream>( server_id_, this, crypto_config_->proof_verifier()->CreateDefaultContext(), crypto_config_, - this); + this, /*has_application_state = */ true); } bool QuicSpdyClientSession::IsAuthorized(const std::string& /*authority*/) { diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc index b8dae4903b2..63de57c31bc 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc @@ -105,6 +105,8 @@ void QuicSpdyClientSessionBase::OnPromiseHeaderList( bool QuicSpdyClientSessionBase::HandlePromised(QuicStreamId /* associated_id */, QuicStreamId promised_id, const SpdyHeaderBlock& headers) { + // TODO(b/136295430): Do not treat |promised_id| as a stream ID when using + // IETF QUIC. // Due to pathalogical packet re-ordering, it is possible that // frames for the promised stream have already arrived, and the // promised stream could be active or closed. @@ -202,7 +204,11 @@ void QuicSpdyClientSessionBase::ResetPromised( QuicStreamId id, QuicRstStreamErrorCode error_code) { DCHECK(QuicUtils::IsServerInitiatedStreamId(transport_version(), id)); - SendRstStream(id, error_code, 0); + if (break_close_loop()) { + ResetStream(id, error_code, 0); + } else { + SendRstStream(id, error_code, 0); + } if (!IsOpenStream(id) && !IsClosedStream(id)) { MaybeIncreaseLargestPeerStreamId(id); } @@ -216,8 +222,27 @@ void QuicSpdyClientSessionBase::CloseStreamInner(QuicStreamId stream_id, } } +void QuicSpdyClientSessionBase::OnStreamClosed(QuicStreamId stream_id) { + DCHECK(break_close_loop()); + QuicSpdySession::OnStreamClosed(stream_id); + if (!VersionUsesHttp3(transport_version())) { + headers_stream()->MaybeReleaseSequencerBuffer(); + } +} + bool QuicSpdyClientSessionBase::ShouldReleaseHeadersStreamSequencerBuffer() { return !HasActiveRequestStreams() && promised_by_id_.empty(); } +void QuicSpdyClientSessionBase::OnSettingsFrame(const SettingsFrame& frame) { + QuicSpdySession::OnSettingsFrame(frame); + std::unique_ptr<char[]> buffer; + QuicByteCount frame_length = + HttpEncoder::SerializeSettingsFrame(frame, &buffer); + auto serialized_data = std::make_unique<ApplicationState>( + buffer.get(), buffer.get() + frame_length); + static_cast<QuicCryptoClientStreamBase*>(GetMutableCryptoStream()) + ->OnApplicationState(std::move(serialized_data)); +} + } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h index 7d4ba01141a..a109d185a46 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h @@ -24,8 +24,7 @@ class QuicSpdyClientStream; // to authority constraints). Clients should use this map to enforce // session affinity for requests corresponding to cross-origin push // promised streams. -using QuicPromisedByUrlMap = - QuicUnorderedMap<std::string, QuicClientPromisedInfo*>; +using QuicPromisedByUrlMap = QuicHashMap<std::string, QuicClientPromisedInfo*>; // The maximum time a promises stream can be reserved without being // claimed by a client request. @@ -105,6 +104,9 @@ class QUIC_EXPORT_PRIVATE QuicSpdyClientSessionBase // Release headers stream's sequencer buffer if it's empty. void CloseStreamInner(QuicStreamId stream_id, bool rst_sent) override; + // Release headers stream's sequencer buffer if it's empty. + void OnStreamClosed(QuicStreamId stream_id) override; + // Returns true if there are no active requests and no promised streams. bool ShouldReleaseHeadersStreamSequencerBuffer() override; @@ -117,11 +119,14 @@ class QUIC_EXPORT_PRIVATE QuicSpdyClientSessionBase return push_promise_index_; } + // Override to serialize the settings and pass it down to the handshaker. + void OnSettingsFrame(const SettingsFrame& frame) override; + private: // For QuicSpdyClientStream to detect that a response corresponds to a // promise. using QuicPromisedByIdMap = - QuicUnorderedMap<QuicStreamId, std::unique_ptr<QuicClientPromisedInfo>>; + QuicHashMap<QuicStreamId, std::unique_ptr<QuicClientPromisedInfo>>; // As per rfc7540, section 10.5: track promise streams in "reserved // (remote)". The primary key is URL from the promise request diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc index da05a15f6d6..7d4ae810115 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc @@ -11,9 +11,14 @@ #include "net/third_party/quiche/src/quic/core/crypto/null_decrypter.h" #include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h" +#include "net/third_party/quiche/src/quic/core/http/http_constants.h" +#include "net/third_party/quiche/src/quic/core/http/http_frames.h" #include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h" #include "net/third_party/quiche/src/quic/core/http/spdy_server_push_utils.h" +#include "net/third_party/quiche/src/quic/core/quic_constants.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/core/quic_versions.h" +#include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h" #include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" @@ -27,6 +32,7 @@ #include "net/third_party/quiche/src/quic/test_tools/quic_session_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/simple_session_cache.h" #include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h" #include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" @@ -81,11 +87,14 @@ class TestQuicSpdyClientSession : public QuicSpdyClientSession { class QuicSpdyClientSessionTest : public QuicTestWithParam<ParsedQuicVersion> { protected: QuicSpdyClientSessionTest() - : crypto_config_(crypto_test_utils::ProofVerifierForTesting()), - promised_stream_id_( + : promised_stream_id_( QuicUtils::GetInvalidStreamId(GetParam().transport_version)), associated_stream_id_( QuicUtils::GetInvalidStreamId(GetParam().transport_version)) { + auto client_cache = std::make_unique<test::SimpleSessionCache>(); + client_session_cache_ = client_cache.get(); + crypto_config_ = std::make_unique<QuicCryptoClientConfig>( + crypto_test_utils::ProofVerifierForTesting(), std::move(client_cache)); Initialize(); // Advance the time, because timers do not like uninitialized times. connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1)); @@ -103,7 +112,7 @@ class QuicSpdyClientSessionTest : public QuicTestWithParam<ParsedQuicVersion> { SupportedVersions(GetParam())); session_ = std::make_unique<TestQuicSpdyClientSession>( DefaultQuicConfig(), SupportedVersions(GetParam()), connection_, - QuicServerId(kServerHostname, kPort, false), &crypto_config_, + QuicServerId(kServerHostname, kPort, false), crypto_config_.get(), &push_promise_index_); session_->Initialize(); push_promise_[":path"] = "/bar"; @@ -157,13 +166,13 @@ class QuicSpdyClientSessionTest : public QuicTestWithParam<ParsedQuicVersion> { session_->GetMutableCryptoStream()); QuicConfig config = DefaultQuicConfig(); if (VersionHasIetfQuicFrames(connection_->transport_version())) { - config.SetMaxUnidirectionalStreamsToSend( - server_max_incoming_streams + - session_->num_expected_unidirectional_static_streams()); + config.SetMaxUnidirectionalStreamsToSend(server_max_incoming_streams); config.SetMaxBidirectionalStreamsToSend(server_max_incoming_streams); } else { config.SetMaxBidirectionalStreamsToSend(server_max_incoming_streams); } + SetQuicReloadableFlag(quic_enable_tls_resumption, true); + SetQuicReloadableFlag(quic_enable_zero_rtt_for_tls, true); std::unique_ptr<QuicCryptoServerConfig> crypto_config = crypto_test_utils::CryptoServerConfigForTesting(); crypto_test_utils::HandshakeWithFakeServer( @@ -171,7 +180,20 @@ class QuicSpdyClientSessionTest : public QuicTestWithParam<ParsedQuicVersion> { stream, AlpnForVersion(connection_->version())); } - QuicCryptoClientConfig crypto_config_; + void CreateConnection() { + connection_ = new PacketSavingConnection(&helper_, &alarm_factory_, + Perspective::IS_CLIENT, + SupportedVersions(GetParam())); + // Advance the time, because timers do not like uninitialized times. + connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1)); + session_ = std::make_unique<TestQuicSpdyClientSession>( + DefaultQuicConfig(), SupportedVersions(GetParam()), connection_, + QuicServerId(kServerHostname, kPort, false), crypto_config_.get(), + &push_promise_index_); + session_->Initialize(); + } + + std::unique_ptr<QuicCryptoClientConfig> crypto_config_; MockQuicConnectionHelper helper_; MockAlarmFactory alarm_factory_; PacketSavingConnection* connection_; @@ -181,6 +203,7 @@ class QuicSpdyClientSessionTest : public QuicTestWithParam<ParsedQuicVersion> { std::string promise_url_; QuicStreamId promised_stream_id_; QuicStreamId associated_stream_id_; + test::SimpleSessionCache* client_session_cache_; }; INSTANTIATE_TEST_SUITE_P(Tests, @@ -239,13 +262,6 @@ TEST_P(QuicSpdyClientSessionTest, NoEncryptionAfterInitialEncryption) { } TEST_P(QuicSpdyClientSessionTest, MaxNumStreamsWithNoFinOrRst) { - if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) { - // This test relies on the MIDS transport parameter, which is not yet - // supported in TLS 1.3. - // TODO(nharper): Add support for Transport Parameters in the TLS handshake. - return; - } - uint32_t kServerMaxIncomingStreams = 1; CompleteCryptoHandshake(kServerMaxIncomingStreams); @@ -256,26 +272,13 @@ TEST_P(QuicSpdyClientSessionTest, MaxNumStreamsWithNoFinOrRst) { // Close the stream, but without having received a FIN or a RST_STREAM // or MAX_STREAMS (V99) and check that a new one can not be created. session_->CloseStream(stream->id()); - EXPECT_EQ(1u, session_->GetNumOpenOutgoingStreams()); + EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); stream = session_->CreateOutgoingBidirectionalStream(); EXPECT_FALSE(stream); - - if (VersionHasIetfQuicFrames(GetParam().transport_version)) { - EXPECT_EQ(1u, - QuicSessionPeer::v99_bidirectional_stream_id_manager(&*session_) - ->outgoing_stream_count()); - } } TEST_P(QuicSpdyClientSessionTest, MaxNumStreamsWithRst) { - if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) { - // This test relies on the MIDS transport parameter, which is not yet - // supported in TLS 1.3. - // TODO(nharper): Add support for Transport Parameters in the TLS handshake. - return; - } - uint32_t kServerMaxIncomingStreams = 1; CompleteCryptoHandshake(kServerMaxIncomingStreams); @@ -288,7 +291,7 @@ TEST_P(QuicSpdyClientSessionTest, MaxNumStreamsWithRst) { session_->OnRstStream(QuicRstStreamFrame(kInvalidControlFrameId, stream->id(), QUIC_RST_ACKNOWLEDGEMENT, 0)); // Check that a new one can be created. - EXPECT_EQ(0u, session_->GetNumOpenOutgoingStreams()); + EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); if (VersionHasIetfQuicFrames(GetParam().transport_version)) { // In V99 the stream limit increases only if we get a MAX_STREAMS // frame; pretend we got one. @@ -309,12 +312,6 @@ TEST_P(QuicSpdyClientSessionTest, MaxNumStreamsWithRst) { } TEST_P(QuicSpdyClientSessionTest, ResetAndTrailers) { - if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) { - // This test relies on the MIDS transport parameter, which is not yet - // supported in TLS 1.3. - // TODO(nharper): Add support for Transport Parameters in the TLS handshake. - return; - } // Tests the situation in which the client sends a RST at the same time that // the server sends trailing headers (trailers). Receipt of the trailers by // the client should result in all outstanding stream state being tidied up @@ -346,11 +343,15 @@ TEST_P(QuicSpdyClientSessionTest, ResetAndTrailers) { .Times(AtLeast(1)) .WillRepeatedly(Invoke(&ClearControlFrame)); EXPECT_CALL(*connection_, OnStreamReset(_, _)).Times(1); - session_->SendRstStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY, 0); + if (session_->break_close_loop()) { + session_->ResetStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY, 0); + } else { + session_->SendRstStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY, 0); + } // A new stream cannot be created as the reset stream still counts as an open // outgoing stream until closed by the server. - EXPECT_EQ(1u, session_->GetNumOpenOutgoingStreams()); + EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); stream = session_->CreateOutgoingBidirectionalStream(); EXPECT_EQ(nullptr, stream); @@ -365,7 +366,7 @@ TEST_P(QuicSpdyClientSessionTest, ResetAndTrailers) { // The stream is now complete from the client's perspective, and it should // be able to create a new outgoing stream. - EXPECT_EQ(0u, session_->GetNumOpenOutgoingStreams()); + EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); if (VersionHasIetfQuicFrames(GetParam().transport_version)) { QuicMaxStreamsFrame frame(0, 2, /*unidirectional=*/false); @@ -398,7 +399,11 @@ TEST_P(QuicSpdyClientSessionTest, ReceivedMalformedTrailersAfterSendingRst) { .Times(AtLeast(1)) .WillRepeatedly(Invoke(&ClearControlFrame)); EXPECT_CALL(*connection_, OnStreamReset(_, _)).Times(1); - session_->SendRstStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY, 0); + if (session_->break_close_loop()) { + session_->ResetStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY, 0); + } else { + session_->SendRstStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY, 0); + } // The stream receives trailers with final byte offset, but the header value // is non-numeric and should be treated as malformed. @@ -534,11 +539,6 @@ TEST_P(QuicSpdyClientSessionTest, InvalidPacketReceived) { // A packet with invalid framing should cause a connection to be closed. TEST_P(QuicSpdyClientSessionTest, InvalidFramedPacketReceived) { const ParsedQuicVersion version = GetParam(); - if (version.handshake_protocol == PROTOCOL_TLS1_3) { - // TODO(nharper, b/112643533): Figure out why this test fails when TLS is - // enabled and fix it. - return; - } QuicSocketAddress server_address(TestPeerIPAddress(), kTestPort); QuicSocketAddress client_address(TestPeerIPAddress(), kTestPort); if (version.KnowsWhichDecrypterToUse()) { @@ -584,8 +584,7 @@ TEST_P(QuicSpdyClientSessionTest, PushPromiseOnPromiseHeaders) { CompleteCryptoHandshake(); if (VersionHasIetfQuicFrames(connection_->transport_version())) { - session_->SetMaxPushId(GetNthServerInitiatedUnidirectionalStreamId( - connection_->transport_version(), 10)); + session_->SetMaxPushId(10); } MockQuicSpdyClientStream* stream = static_cast<MockQuicSpdyClientStream*>( @@ -605,25 +604,28 @@ TEST_P(QuicSpdyClientSessionTest, PushPromiseStreamIdTooHigh) { session_.get(), std::make_unique<QuicSpdyClientStream>( stream_id, session_.get(), BIDIRECTIONAL)); + QuicHeaderList headers; + headers.OnHeaderBlockStart(); + headers.OnHeader(":path", "/bar"); + headers.OnHeader(":authority", "www.google.com"); + headers.OnHeader(":method", "GET"); + headers.OnHeader(":scheme", "https"); + headers.OnHeaderBlockEnd(0, 0); + if (VersionHasIetfQuicFrames(connection_->transport_version())) { - session_->SetMaxPushId(GetNthServerInitiatedUnidirectionalStreamId( - connection_->transport_version(), 10)); + session_->SetMaxPushId(10); // TODO(b/136295430) Use PushId to represent Push IDs instead of // QuicStreamId. EXPECT_CALL( *connection_, CloseConnection(QUIC_INVALID_STREAM_ID, "Received push stream id higher than MAX_PUSH_ID.", _)); + const PushId promise_id = 11; + session_->OnPromiseHeaderList(stream_id, promise_id, 0, headers); + return; } - auto promise_id = GetNthServerInitiatedUnidirectionalStreamId( + const QuicStreamId promise_id = GetNthServerInitiatedUnidirectionalStreamId( connection_->transport_version(), 11); - auto headers = QuicHeaderList(); - headers.OnHeaderBlockStart(); - headers.OnHeader(":path", "/bar"); - headers.OnHeader(":authority", "www.google.com"); - headers.OnHeader(":method", "GET"); - headers.OnHeader(":scheme", "https"); - headers.OnHeaderBlockEnd(0, 0); session_->OnPromiseHeaderList(stream_id, promise_id, 0, headers); } @@ -647,8 +649,7 @@ TEST_P(QuicSpdyClientSessionTest, PushPromiseOutOfOrder) { CompleteCryptoHandshake(); if (VersionHasIetfQuicFrames(connection_->transport_version())) { - session_->SetMaxPushId(GetNthServerInitiatedUnidirectionalStreamId( - connection_->transport_version(), 10)); + session_->SetMaxPushId(10); } MockQuicSpdyClientStream* stream = static_cast<MockQuicSpdyClientStream*>( @@ -852,7 +853,12 @@ TEST_P(QuicSpdyClientSessionTest, ResetPromised) { EXPECT_CALL(*connection_, SendControlFrame(_)); EXPECT_CALL(*connection_, OnStreamReset(promised_stream_id_, QUIC_STREAM_PEER_GOING_AWAY)); - session_->SendRstStream(promised_stream_id_, QUIC_STREAM_PEER_GOING_AWAY, 0); + if (session_->break_close_loop()) { + session_->ResetStream(promised_stream_id_, QUIC_STREAM_PEER_GOING_AWAY, 0); + } else { + session_->SendRstStream(promised_stream_id_, QUIC_STREAM_PEER_GOING_AWAY, + 0); + } QuicClientPromisedInfo* promised = session_->GetPromisedById(promised_stream_id_); EXPECT_NE(promised, nullptr); @@ -939,6 +945,108 @@ TEST_P(QuicSpdyClientSessionTest, TooManyPushPromises) { } } +// Test that upon receiving HTTP/3 SETTINGS, the settings are serialized and +// stored into client session cache. +TEST_P(QuicSpdyClientSessionTest, OnSettingsFrame) { + // This feature is HTTP/3 only + if (!VersionUsesHttp3(session_->transport_version())) { + return; + } + CompleteCryptoHandshake(); + SettingsFrame settings; + settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 2; + settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5; + settings.values[256] = 4; // unknown setting + char application_state[] = {// type (SETTINGS) + 0x04, + // length + 0x07, + // identifier (SETTINGS_QPACK_MAX_TABLE_CAPACITY) + 0x01, + // content + 0x02, + // identifier (SETTINGS_MAX_HEADER_LIST_SIZE) + 0x06, + // content + 0x05, + // identifier (256 in variable length integer) + 0x40 + 0x01, 0x00, + // content + 0x04}; + ApplicationState expected(std::begin(application_state), + std::end(application_state)); + session_->OnSettingsFrame(settings); + EXPECT_EQ(expected, + *client_session_cache_ + ->Lookup(QuicServerId(kServerHostname, kPort, false), nullptr) + ->application_state); +} + +TEST_P(QuicSpdyClientSessionTest, IetfZeroRttSetup) { + // This feature is HTTP/3 only + if (!VersionUsesHttp3(session_->transport_version())) { + return; + } + CompleteCryptoHandshake(); + EXPECT_FALSE(session_->GetCryptoStream()->IsResumption()); + SettingsFrame settings; + settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 2; + settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5; + settings.values[256] = 4; // unknown setting + session_->OnSettingsFrame(settings); + + CreateConnection(); + // Session configs should be in initial state. + EXPECT_EQ(0u, session_->flow_controller()->send_window_offset()); + EXPECT_EQ(std::numeric_limits<size_t>::max(), + session_->max_outbound_header_list_size()); + session_->CryptoConnect(); + + // The client session should have a basic setup ready before the handshake + // succeeds. + EXPECT_EQ(kInitialSessionFlowControlWindowForTest, + session_->flow_controller()->send_window_offset()); + auto* id_manager = QuicSessionPeer::v99_streamid_manager(session_.get()); + EXPECT_EQ(kDefaultMaxStreamsPerConnection, + id_manager->max_outgoing_bidirectional_streams()); + EXPECT_EQ( + kDefaultMaxStreamsPerConnection + kHttp3StaticUnidirectionalStreamCount, + id_manager->max_outgoing_unidirectional_streams()); + auto* control_stream = + QuicSpdySessionPeer::GetSendControlStream(session_.get()); + EXPECT_EQ(kInitialStreamFlowControlWindowForTest, + control_stream->flow_controller()->send_window_offset()); + EXPECT_EQ(5u, session_->max_outbound_header_list_size()); + + // Complete the handshake with a different config. + QuicCryptoClientStream* stream = + static_cast<QuicCryptoClientStream*>(session_->GetMutableCryptoStream()); + QuicConfig config = DefaultQuicConfig(); + config.SetInitialMaxStreamDataBytesUnidirectionalToSend( + kInitialStreamFlowControlWindowForTest + 1); + config.SetInitialSessionFlowControlWindowToSend( + kInitialSessionFlowControlWindowForTest + 1); + config.SetMaxBidirectionalStreamsToSend(kDefaultMaxStreamsPerConnection + 1); + config.SetMaxUnidirectionalStreamsToSend(kDefaultMaxStreamsPerConnection + 1); + SetQuicReloadableFlag(quic_enable_tls_resumption, true); + std::unique_ptr<QuicCryptoServerConfig> crypto_config = + crypto_test_utils::CryptoServerConfigForTesting(); + crypto_test_utils::HandshakeWithFakeServer( + &config, crypto_config.get(), &helper_, &alarm_factory_, connection_, + stream, AlpnForVersion(connection_->version())); + + EXPECT_TRUE(session_->GetCryptoStream()->IsResumption()); + EXPECT_EQ(kInitialSessionFlowControlWindowForTest + 1, + session_->flow_controller()->send_window_offset()); + EXPECT_EQ(kDefaultMaxStreamsPerConnection + 1, + id_manager->max_outgoing_bidirectional_streams()); + EXPECT_EQ(kDefaultMaxStreamsPerConnection + + kHttp3StaticUnidirectionalStreamCount + 1, + id_manager->max_outgoing_unidirectional_streams()); + EXPECT_EQ(kInitialStreamFlowControlWindowForTest + 1, + control_stream->flow_controller()->send_window_offset()); +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream_test.cc index 50224cbde29..fdc0e298371 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream_test.cc @@ -46,7 +46,7 @@ class MockQuicSpdyClientSession : public QuicSpdyClientSession { delete; ~MockQuicSpdyClientSession() override = default; - MOCK_METHOD1(CloseStream, void(QuicStreamId stream_id)); + MOCK_METHOD(void, CloseStream, (QuicStreamId stream_id), (override)); private: QuicCryptoClientConfig crypto_config_; diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base_test.cc index 1a8eef2935f..b3cc147b59f 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base_test.cc @@ -7,6 +7,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_stream_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" using testing::_; @@ -50,7 +51,7 @@ TEST_F(QuicSpdyServerStreamBaseTest, SendQuicRstStreamNoErrorWithEarlyResponse) { stream_->StopReading(); EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(1); - stream_->set_fin_sent(true); + QuicStreamPeer::SetFinSent(stream_); stream_->CloseWriteSide(); } diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.cc index 11351438f3c..27643c87294 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.cc @@ -376,7 +376,9 @@ QuicSpdySession::QuicSpdySession( config, supported_versions, /*num_expected_unidirectional_static_streams = */ - VersionUsesHttp3(connection->transport_version()) ? 3 : 0), + VersionUsesHttp3(connection->transport_version()) + ? kHttp3StaticUnidirectionalStreamCount + : 0), send_control_stream_(nullptr), receive_control_stream_(nullptr), qpack_encoder_receive_stream_(nullptr), @@ -397,7 +399,8 @@ QuicSpdySession::QuicSpdySession( spdy_framer_(SpdyFramer::ENABLE_COMPRESSION), spdy_framer_visitor_(new SpdyFramerVisitor(this)), server_push_enabled_(true), - ietf_server_push_enabled_(false), + ietf_server_push_enabled_( + GetQuicFlag(FLAGS_quic_enable_http3_server_push)), destruction_indicator_(123456789), debug_visitor_(nullptr), http3_goaway_received_(false), @@ -447,8 +450,6 @@ void QuicSpdySession::Initialize() { headers_stream_ = headers_stream.get(); ActivateStream(std::move(headers_stream)); } else { - ConfigureMaxDynamicStreamsToSend( - config()->GetMaxUnidirectionalStreamsToSend()); qpack_encoder_ = std::make_unique<QpackEncoder>(this); qpack_decoder_ = std::make_unique<QpackDecoder>(qpack_maximum_dynamic_table_capacity_, @@ -739,8 +740,6 @@ void QuicSpdySession::SendInitialData() { SendMaxPushId(); http3_max_push_id_sent_ = true; } - qpack_decoder_send_stream_->MaybeSendStreamType(); - qpack_encoder_send_stream_->MaybeSendStreamType(); } QpackEncoder* QuicSpdySession::qpack_encoder() { @@ -785,24 +784,8 @@ void QuicSpdySession::OnNewEncryptionKeyAvailable( EncryptionLevel level, std::unique_ptr<QuicEncrypter> encrypter) { QuicSession::OnNewEncryptionKeyAvailable(level, std::move(encrypter)); - if (GetQuicRestartFlag(quic_send_settings_on_write_key_available) && - IsEncryptionEstablished()) { + if (IsEncryptionEstablished()) { // Send H3 SETTINGs once encryption is established. - QUIC_RESTART_FLAG_COUNT_N(quic_send_settings_on_write_key_available, 2, 2); - SendInitialData(); - } -} - -void QuicSpdySession::SetDefaultEncryptionLevel(quic::EncryptionLevel level) { - QuicSession::SetDefaultEncryptionLevel(level); - if (!GetQuicRestartFlag(quic_send_settings_on_write_key_available)) { - SendInitialData(); - } -} - -void QuicSpdySession::OnOneRttKeysAvailable() { - QuicSession::OnOneRttKeysAvailable(); - if (!GetQuicRestartFlag(quic_send_settings_on_write_key_available)) { SendInitialData(); } } @@ -873,6 +856,34 @@ void QuicSpdySession::OnPromiseHeaderList( ConnectionCloseBehavior::SILENT_CLOSE); } +bool QuicSpdySession::SetApplicationState(ApplicationState* cached_state) { + DCHECK_EQ(perspective(), Perspective::IS_CLIENT); + DCHECK(VersionUsesHttp3(transport_version())); + + SettingsFrame out; + if (!HttpDecoder::DecodeSettings( + reinterpret_cast<char*>(cached_state->data()), cached_state->size(), + &out)) { + return false; + } + + // TODO(b/153726130): Add OnSettingsFrameResumed() in debug visitor. + for (const auto& setting : out.values) { + OnSetting(setting.first, setting.second); + } + return true; +} + +void QuicSpdySession::OnSettingsFrame(const SettingsFrame& frame) { + DCHECK(VersionUsesHttp3(transport_version())); + if (debug_visitor_ != nullptr) { + debug_visitor_->OnSettingsFrameReceived(frame); + } + for (const auto& setting : frame.values) { + OnSetting(setting.first, setting.second); + } +} + void QuicSpdySession::OnSetting(uint64_t id, uint64_t value) { if (VersionUsesHttp3(transport_version())) { // SETTINGS frame received on the control stream. @@ -1153,10 +1164,9 @@ bool QuicSpdySession::ProcessPendingStream(PendingStream* pending) { return true; } default: - SendStopSending( - static_cast<QuicApplicationErrorCode>( - QuicHttp3ErrorCode::IETF_QUIC_HTTP3_STREAM_CREATION_ERROR), - pending->id()); + SendStopSending(static_cast<QuicApplicationErrorCode>( + QuicHttp3ErrorCode::STREAM_CREATION_ERROR), + pending->id()); pending->StopReading(); } return false; @@ -1211,7 +1221,7 @@ void QuicSpdySession::OnCanCreateNewOutgoingStream(bool unidirectional) { } } -void QuicSpdySession::SetMaxPushId(QuicStreamId max_push_id) { +void QuicSpdySession::SetMaxPushId(PushId max_push_id) { DCHECK(VersionUsesHttp3(transport_version())); DCHECK_EQ(Perspective::IS_CLIENT, perspective()); if (max_push_id_.has_value()) { @@ -1234,7 +1244,7 @@ void QuicSpdySession::SetMaxPushId(QuicStreamId max_push_id) { } } -bool QuicSpdySession::OnMaxPushIdFrame(QuicStreamId max_push_id) { +bool QuicSpdySession::OnMaxPushIdFrame(PushId max_push_id) { DCHECK(VersionUsesHttp3(transport_version())); DCHECK_EQ(Perspective::IS_SERVER, perspective()); @@ -1245,17 +1255,26 @@ bool QuicSpdySession::OnMaxPushIdFrame(QuicStreamId max_push_id) { QUIC_DVLOG(1) << "Setting max_push_id to: " << max_push_id << " from unset"; } - quiche::QuicheOptional<QuicStreamId> old_max_push_id = max_push_id_; + quiche::QuicheOptional<PushId> old_max_push_id = max_push_id_; max_push_id_ = max_push_id; - if (!old_max_push_id.has_value() || - max_push_id_.value() > old_max_push_id.value()) { + if (!old_max_push_id.has_value() || max_push_id > old_max_push_id.value()) { OnCanCreateNewOutgoingStream(true); return true; } // Equal value is not considered an error. - return max_push_id_.value() >= old_max_push_id.value(); + if (max_push_id < old_max_push_id.value()) { + CloseConnectionWithDetails( + QUIC_HTTP_INVALID_MAX_PUSH_ID, + quiche::QuicheStrCat( + "MAX_PUSH_ID received with value ", max_push_id, + " which is smaller that previously received value ", + old_max_push_id.value())); + return false; + } + + return true; } void QuicSpdySession::SendMaxPushId() { @@ -1274,7 +1293,7 @@ void QuicSpdySession::EnableServerPush() { ietf_server_push_enabled_ = true; } -bool QuicSpdySession::CanCreatePushStreamWithId(QuicStreamId push_id) { +bool QuicSpdySession::CanCreatePushStreamWithId(PushId push_id) { DCHECK(VersionUsesHttp3(transport_version())); return ietf_server_push_enabled_ && max_push_id_.has_value() && diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.h index 93fa09d9762..703dffaf41e 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.h @@ -246,6 +246,9 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession // client. bool server_push_enabled() const; + // Called when the control stream receives HTTP/3 SETTINGS. + virtual void OnSettingsFrame(const SettingsFrame& frame); + // Called when a setting is parsed from an incoming SETTINGS frame. void OnSetting(uint64_t id, uint64_t value); @@ -308,14 +311,14 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession // This method must only be called if protocol is IETF QUIC and perspective is // client. |max_push_id| must be greater than or equal to current // |max_push_id_|. - void SetMaxPushId(QuicStreamId max_push_id); + void SetMaxPushId(PushId max_push_id); // Sets |max_push_id_|. // This method must only be called if protocol is IETF QUIC and perspective is // server. It must only be called if a MAX_PUSH_ID frame is received. // Returns whether |max_push_id| is greater than or equal to current // |max_push_id_|. - bool OnMaxPushIdFrame(QuicStreamId max_push_id); + bool OnMaxPushIdFrame(PushId max_push_id); // Enables server push. // Must only be called when using IETF QUIC, for which server push is disabled @@ -332,8 +335,7 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession // For a client this means that SetMaxPushId() has been called with // |max_push_id| greater than or equal to |push_id|. // Must only be called when using IETF QUIC. - // TODO(b/136295430): Use sequential PUSH IDs instead of stream IDs. - bool CanCreatePushStreamWithId(QuicStreamId push_id); + bool CanCreatePushStreamWithId(PushId push_id); int32_t destruction_indicator() const { return destruction_indicator_; } @@ -375,6 +377,9 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession void OnStreamCreated(QuicSpdyStream* stream); + // Decode SETTINGS from |cached_state| and apply it to the session. + bool SetApplicationState(ApplicationState* cached_state) override; + protected: // Override CreateIncomingStream(), CreateOutgoingBidirectionalStream() and // CreateOutgoingUnidirectionalStream() with QuicSpdyStream return type to @@ -418,9 +423,6 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession EncryptionLevel level, std::unique_ptr<QuicEncrypter> encrypter) override; - void SetDefaultEncryptionLevel(quic::EncryptionLevel level) override; - void OnOneRttKeysAvailable() override; - // Optional, enables instrumentation related to go/quic-hpack. void SetHpackEncoderDebugVisitor( std::unique_ptr<QuicHpackDebugVisitor> visitor); @@ -444,9 +446,6 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession // Initializes HTTP/3 unidirectional streams if not yet initialzed. virtual void MaybeInitializeHttp3UnidirectionalStreams(); - void set_max_uncompressed_header_bytes( - size_t set_max_uncompressed_header_bytes); - void SendMaxPushId(); private: @@ -540,7 +539,7 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession // initial MAX_PUSH_ID frame. // For a client after 1-RTT keys are available, the push ID in the most // recently sent MAX_PUSH_ID frame. - quiche::QuicheOptional<QuicStreamId> max_push_id_; + quiche::QuicheOptional<PushId> max_push_id_; // An integer used for live check. The indicator is assigned a value in // constructor. As long as it is not the assigned value, that would indicate diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc index 20078062e94..8b78d7f0883 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc @@ -97,7 +97,8 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker { EXPECT_TRUE( session()->config()->FillTransportParameters(&transport_parameters)); error = session()->config()->ProcessTransportParameters( - transport_parameters, CLIENT, &error_details); + transport_parameters, CLIENT, /* is_resumption = */ false, + &error_details); } else { CryptoHandshakeMessage msg; session()->config()->ToHandshakeMessage(&msg, transport_version()); @@ -137,13 +138,14 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker { } void OnPacketDecrypted(EncryptionLevel /*level*/) override {} void OnOneRttPacketAcknowledged() override {} + void OnHandshakePacketSent() override {} void OnHandshakeDoneReceived() override {} - MOCK_METHOD0(OnCanWrite, void()); + MOCK_METHOD(void, OnCanWrite, (), (override)); bool HasPendingCryptoRetransmission() const override { return false; } - MOCK_CONST_METHOD0(HasPendingRetransmission, bool()); + MOCK_METHOD(bool, HasPendingRetransmission, (), (const, override)); private: using QuicCryptoStream::session; @@ -158,7 +160,7 @@ class TestHeadersStream : public QuicHeadersStream { explicit TestHeadersStream(QuicSpdySession* session) : QuicHeadersStream(session) {} - MOCK_METHOD0(OnCanWrite, void()); + MOCK_METHOD(void, OnCanWrite, (), (override)); }; class TestStream : public QuicSpdyStream { @@ -173,11 +175,13 @@ class TestStream : public QuicSpdyStream { void OnBodyAvailable() override {} - MOCK_METHOD0(OnCanWrite, void()); - MOCK_METHOD4(RetransmitStreamData, - bool(QuicStreamOffset, QuicByteCount, bool, TransmissionType)); + MOCK_METHOD(void, OnCanWrite, (), (override)); + MOCK_METHOD(bool, + RetransmitStreamData, + (QuicStreamOffset, QuicByteCount, bool, TransmissionType), + (override)); - MOCK_CONST_METHOD0(HasPendingRetransmission, bool()); + MOCK_METHOD(bool, HasPendingRetransmission, (), (const, override)); }; class TestSession : public QuicSpdySession { @@ -221,9 +225,9 @@ class TestSession : public QuicSpdySession { TestStream* CreateIncomingStream(QuicStreamId id) override { // Enforce the limit on the number of open streams. - if (GetNumOpenIncomingStreams() + 1 > - max_open_incoming_bidirectional_streams() && - !VersionHasIetfQuicFrames(connection()->transport_version())) { + if (!VersionHasIetfQuicFrames(connection()->transport_version()) && + GetNumOpenIncomingStreams() + 1 > + max_open_incoming_bidirectional_streams()) { connection()->CloseConnection( QUIC_TOO_MANY_OPEN_STREAMS, "Too many streams!", ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); @@ -343,8 +347,7 @@ class QuicSpdySessionTestBase : public QuicTestWithParam<ParsedQuicVersion> { kInitialSessionFlowControlWindowForTest); if (VersionUsesHttp3(transport_version())) { QuicConfigPeer::SetReceivedMaxUnidirectionalStreams( - session_.config(), - session_.num_expected_unidirectional_static_streams()); + session_.config(), kHttp3StaticUnidirectionalStreamCount); } QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow( session_.config(), kMinimumFlowControlSendWindow); @@ -424,6 +427,15 @@ class QuicSpdySessionTestBase : public QuicTestWithParam<ParsedQuicVersion> { return std::string(priority_buffer.get(), priority_frame_length); } + std::string SerializeMaxPushIdFrame(PushId push_id) { + MaxPushIdFrame max_push_id_frame; + max_push_id_frame.push_id = push_id; + std::unique_ptr<char[]> buffer; + QuicByteCount frame_length = + HttpEncoder::SerializeMaxPushIdFrame(max_push_id_frame, &buffer); + return std::string(buffer.get(), frame_length); + } + QuicStreamId StreamCountToId(QuicStreamCount stream_count, Perspective perspective, bool bidirectional) { @@ -1115,7 +1127,7 @@ TEST_P(QuicSpdySessionTestServer, RstStreamBeforeHeadersDecompressed) { QuicStreamFrame data1(GetNthClientInitiatedBidirectionalId(0), false, 0, quiche::QuicheStringPiece("HT")); session_.OnStreamFrame(data1); - EXPECT_EQ(1u, session_.GetNumOpenIncomingStreams()); + EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_)); if (!VersionHasIetfQuicFrames(transport_version())) { // For version99, OnStreamReset gets called because of the STOP_SENDING, @@ -1152,7 +1164,7 @@ TEST_P(QuicSpdySessionTestServer, RstStreamBeforeHeadersDecompressed) { session_.OnStopSendingFrame(stop_sending); } - EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams()); + EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_)); // Connection should remain alive. EXPECT_TRUE(connection_->connected()); } @@ -1590,7 +1602,8 @@ TEST_P(QuicSpdySessionTestServer, TooLowUnidirectionalStreamLimitHttp3) { EXPECT_CALL( *connection_, - CloseConnection(_, "New unidirectional stream limit is too low.", _)); + CloseConnection( + _, "new unidirectional limit 2 decreases the current limit: 3", _)); session_.OnConfigNegotiated(); } @@ -1764,10 +1777,59 @@ TEST_P(QuicSpdySessionTestServer, DrainingStreamsDoNotCountAsOpened) { for (QuicStreamId i = kFirstStreamId; i < kFinalStreamId; i += IdDelta()) { QuicStreamFrame data1(i, true, 0, quiche::QuicheStringPiece("HT")); session_.OnStreamFrame(data1); - EXPECT_EQ(1u, session_.GetNumOpenIncomingStreams()); - session_.StreamDraining(i); - EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams()); + EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_)); + session_.StreamDraining(i, /*unidirectional=*/false); + EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_)); + } +} + +TEST_P(QuicSpdySessionTestServer, ReduceMaxPushId) { + if (!VersionUsesHttp3(transport_version())) { + return; } + + StrictMock<MockHttp3DebugVisitor> debug_visitor; + session_.set_debug_visitor(&debug_visitor); + + // Use an arbitrary stream id for incoming control stream. + QuicStreamId stream_id = + GetNthClientInitiatedUnidirectionalStreamId(transport_version(), 3); + char type[] = {kControlStream}; + quiche::QuicheStringPiece stream_type(type, 1); + + QuicStreamOffset offset = 0; + QuicStreamFrame data1(stream_id, false, offset, stream_type); + offset += stream_type.length(); + EXPECT_CALL(debug_visitor, OnPeerControlStreamCreated(stream_id)); + session_.OnStreamFrame(data1); + EXPECT_EQ(stream_id, + QuicSpdySessionPeer::GetReceiveControlStream(&session_)->id()); + + SettingsFrame settings; + std::string settings_frame = EncodeSettings(settings); + QuicStreamFrame data2(stream_id, false, offset, settings_frame); + offset += settings_frame.length(); + + EXPECT_CALL(debug_visitor, OnSettingsFrameReceived(settings)); + session_.OnStreamFrame(data2); + + std::string max_push_id_frame1 = SerializeMaxPushIdFrame(/* push_id = */ 3); + QuicStreamFrame data3(stream_id, false, offset, max_push_id_frame1); + offset += max_push_id_frame1.length(); + + EXPECT_CALL(debug_visitor, OnMaxPushIdFrameReceived(_)); + session_.OnStreamFrame(data3); + + std::string max_push_id_frame2 = SerializeMaxPushIdFrame(/* push_id = */ 1); + QuicStreamFrame data4(stream_id, false, offset, max_push_id_frame2); + + EXPECT_CALL(debug_visitor, OnMaxPushIdFrameReceived(_)); + EXPECT_CALL(*connection_, + CloseConnection(QUIC_HTTP_INVALID_MAX_PUSH_ID, + "MAX_PUSH_ID received with value 1 which is " + "smaller that previously received value 3", + _)); + session_.OnStreamFrame(data4); } class QuicSpdySessionTestClient : public QuicSpdySessionTestBase { @@ -1794,7 +1856,7 @@ TEST_P(QuicSpdySessionTestClient, BadStreamFramePendingStream) { return; } - EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams()); + EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_)); QuicStreamId stream_id1 = GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 0); // A bad stream frame with no data and no fin. @@ -1941,7 +2003,7 @@ TEST_P(QuicSpdySessionTestClient, Http3ServerPush) { return; } - EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams()); + EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_)); // Push unidirectional stream is type 0x01. std::string frame_type1 = quiche::QuicheTextUtils::HexDecode("01"); @@ -1950,7 +2012,7 @@ TEST_P(QuicSpdySessionTestClient, Http3ServerPush) { session_.OnStreamFrame(QuicStreamFrame(stream_id1, /* fin = */ false, /* offset = */ 0, frame_type1)); - EXPECT_EQ(1u, session_.GetNumOpenIncomingStreams()); + EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_)); QuicStream* stream = session_.GetOrCreateStream(stream_id1); EXPECT_EQ(1u, stream->flow_controller()->bytes_consumed()); EXPECT_EQ(1u, session_.flow_controller()->bytes_consumed()); @@ -1962,7 +2024,7 @@ TEST_P(QuicSpdySessionTestClient, Http3ServerPush) { session_.OnStreamFrame(QuicStreamFrame(stream_id2, /* fin = */ false, /* offset = */ 0, frame_type2)); - EXPECT_EQ(2u, session_.GetNumOpenIncomingStreams()); + EXPECT_EQ(2u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_)); stream = session_.GetOrCreateStream(stream_id2); EXPECT_EQ(4u, stream->flow_controller()->bytes_consumed()); EXPECT_EQ(5u, session_.flow_controller()->bytes_consumed()); @@ -1973,7 +2035,7 @@ TEST_P(QuicSpdySessionTestClient, Http3ServerPushOutofOrderFrame) { return; } - EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams()); + EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_)); // Push unidirectional stream is type 0x01. std::string frame_type = quiche::QuicheTextUtils::HexDecode("01"); @@ -1991,10 +2053,10 @@ TEST_P(QuicSpdySessionTestClient, Http3ServerPushOutofOrderFrame) { // Receiving some stream data without stream type does not open the stream. session_.OnStreamFrame(data2); - EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams()); + EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_)); session_.OnStreamFrame(data1); - EXPECT_EQ(1u, session_.GetNumOpenIncomingStreams()); + EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_)); QuicStream* stream = session_.GetOrCreateStream(stream_id); EXPECT_EQ(3u, stream->flow_controller()->highest_received_byte_offset()); } @@ -2273,7 +2335,7 @@ TEST_P(QuicSpdySessionTestServer, SimplePendingStreamType) { QuicStopSendingFrame* stop_sending = frame.stop_sending_frame; EXPECT_EQ(stream_id, stop_sending->stream_id); - EXPECT_EQ(QuicHttp3ErrorCode::IETF_QUIC_HTTP3_STREAM_CREATION_ERROR, + EXPECT_EQ(QuicHttp3ErrorCode::STREAM_CREATION_ERROR, static_cast<QuicHttp3ErrorCode>( stop_sending->application_error_code)); @@ -2418,8 +2480,6 @@ TEST_P(QuicSpdySessionTestServer, ReceiveControlStream) { EXPECT_NE(5u, session_.max_outbound_header_list_size()); EXPECT_NE(42u, QpackEncoderPeer::maximum_blocked_streams(qpack_encoder)); - EXPECT_CALL(*writer_, WritePacket(_, _, _, _, _)) - .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0))); EXPECT_CALL(debug_visitor, OnSettingsFrameReceived(settings)); session_.OnStreamFrame(frame); @@ -2542,7 +2602,7 @@ TEST_P(QuicSpdySessionTestClient, ResetAfterInvalidIncomingStreamType) { session_.OnStreamFrame(frame); // There are no active streams. - EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams()); + EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_)); // The pending stream is still around, because it did not receive a FIN. PendingStream* pending = @@ -2869,9 +2929,6 @@ TEST_P(QuicSpdySessionTestServer, FineGrainedHpackErrorCodes) { return; } - QuicFlagSaver flag_saver; - SetQuicReloadableFlag(spdy_enable_granular_decompress_errors, true); - QuicStreamId request_stream_id = 5; session_.CreateIncomingStream(request_stream_id); @@ -3025,7 +3082,7 @@ TEST_P(QuicSpdySessionTestClient, SendInitialMaxPushIdIfSet) { StrictMock<MockHttp3DebugVisitor> debug_visitor; session_.set_debug_visitor(&debug_visitor); - const QuicStreamId max_push_id = 5; + const PushId max_push_id = 5; session_.SetMaxPushId(max_push_id); InSequence s; diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc index c376d010c8f..51f7c5c9525 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc @@ -192,7 +192,6 @@ QuicSpdyStream::QuicSpdyStream(QuicStreamId id, headers_decompressed_(false), header_list_size_limit_exceeded_(false), headers_payload_length_(0), - trailers_payload_length_(0), trailers_decompressed_(false), trailers_consumed_(false), http_decoder_visitor_(std::make_unique<HttpDecoderVisitor>(this)), @@ -229,7 +228,6 @@ QuicSpdyStream::QuicSpdyStream(PendingStream* pending, headers_decompressed_(false), header_list_size_limit_exceeded_(false), headers_payload_length_(0), - trailers_payload_length_(0), trailers_decompressed_(false), trailers_consumed_(false), http_decoder_visitor_(std::make_unique<HttpDecoderVisitor>(this)), @@ -285,7 +283,7 @@ size_t QuicSpdyStream::WriteHeaders( // set and write side needs to be closed without actually sending a FIN on // this stream. // TODO(rch): Add test to ensure fin_sent_ is set whenever a fin is sent. - set_fin_sent(true); + SetFinSent(); CloseWriteSide(); } return bytes_written; @@ -352,7 +350,7 @@ size_t QuicSpdyStream::WriteTrailers( // If trailers are sent on the headers stream, then |fin_sent_| needs to be // set without actually sending a FIN on this stream. if (!VersionUsesHttp3(transport_version())) { - set_fin_sent(kFin); + SetFinSent(); // Also, write side of this stream needs to be closed. However, only do // this if there is no more buffered data, otherwise it will never be sent. @@ -569,10 +567,7 @@ void QuicSpdyStream::OnHeadersDecoded(QuicHeaderList headers, debug_visitor->OnHeadersDecoded(id(), headers); } - const QuicByteCount frame_length = headers_decompressed_ - ? trailers_payload_length_ - : headers_payload_length_; - OnStreamHeaderList(/* fin = */ false, frame_length, headers); + OnStreamHeaderList(/* fin = */ false, headers_payload_length_, headers); } else { if (debug_visitor) { debug_visitor->OnPushPromiseDecoded(id(), promised_stream_id, headers); @@ -620,16 +615,7 @@ void QuicSpdyStream::MaybeSendPriorityUpdateFrame() { } void QuicSpdyStream::OnHeadersTooLarge() { - if (VersionUsesHttp3(transport_version())) { - // TODO(b/124216424): Reset stream with H3_REQUEST_CANCELLED (if client) - // or with H3_REQUEST_REJECTED (if server). - std::string error_message = - quiche::QuicheStrCat("Too large headers received on stream ", id()); - OnUnrecoverableError(QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE, - error_message); - } else { - Reset(QUIC_HEADERS_TOO_LARGE); - } + Reset(QUIC_HEADERS_TOO_LARGE); } void QuicSpdyStream::OnInitialHeadersComplete( @@ -962,6 +948,8 @@ bool QuicSpdyStream::OnHeadersFrameStart(QuicByteCount header_length, payload_length); } + headers_payload_length_ = payload_length; + if (trailers_decompressed_) { stream_delegate()->OnStreamError( QUIC_HTTP_INVALID_FRAME_SEQUENCE_ON_SPDY_STREAM, @@ -983,15 +971,6 @@ bool QuicSpdyStream::OnHeadersFramePayload(quiche::QuicheStringPiece payload) { DCHECK(VersionUsesHttp3(transport_version())); DCHECK(qpack_decoded_headers_accumulator_); - // TODO(b/152518220): Save |payload_length| argument of OnHeadersFrameStart() - // instead of accumulating payload length in |headers_payload_length_| or - // |trailers_payload_length_|. - if (headers_decompressed_) { - trailers_payload_length_ += payload.length(); - } else { - headers_payload_length_ += payload.length(); - } - qpack_decoded_headers_accumulator_->Decode(payload); // |qpack_decoded_headers_accumulator_| is reset if an error is detected. @@ -1040,7 +1019,7 @@ bool QuicSpdyStream::OnPushPromiseFramePushId( id(), push_id, header_block_length); } - // TODO(renjietang): Check max push id and handle errors. + // TODO(b/151749109): Check max push id and handle errors. spdy_session_->OnPushPromise(id(), push_id); sequencer()->MarkConsumed(body_manager_.OnNonBody(push_id_length)); @@ -1139,7 +1118,7 @@ size_t QuicSpdyStream::WriteHeadersImpl( encoded_headers.size() + encoder_stream_sent_byte_count, header_block.TotalBytesUsed()); - return encoded_headers.size() + encoder_stream_sent_byte_count; + return encoded_headers.size(); } #undef ENDPOINT // undef for jumbo builds diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h index abf3ef4b78e..61bc1fb35c9 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h @@ -300,10 +300,8 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream // Contains a copy of the decompressed header (name, value) pairs until they // are consumed via Readv. QuicHeaderList header_list_; - // Length of HEADERS frame payload. + // Length of most recently received HEADERS frame payload. QuicByteCount headers_payload_length_; - // Length of TRAILERS frame payload. - QuicByteCount trailers_payload_length_; // True if the trailers have been completely decompressed. bool trailers_decompressed_; diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_test.cc index fab6d86a415..bafb0f282f0 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_test.cc @@ -39,6 +39,7 @@ using spdy::kV3LowestPriority; using spdy::SpdyHeaderBlock; using spdy::SpdyPriority; using testing::_; +using testing::AnyNumber; using testing::AtLeast; using testing::ElementsAre; using testing::Invoke; @@ -46,6 +47,7 @@ using testing::InvokeWithoutArgs; using testing::MatchesRegex; using testing::Pair; using testing::Return; +using testing::SaveArg; using testing::StrictMock; namespace quic { @@ -82,7 +84,8 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker { EXPECT_TRUE( session()->config()->FillTransportParameters(&transport_parameters)); error = session()->config()->ProcessTransportParameters( - transport_parameters, CLIENT, &error_details); + transport_parameters, CLIENT, /* is_resumption = */ false, + &error_details); } else { CryptoHandshakeMessage msg; session()->config()->ToHandshakeMessage(&msg, transport_version()); @@ -122,13 +125,16 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker { } void OnPacketDecrypted(EncryptionLevel /*level*/) override {} void OnOneRttPacketAcknowledged() override {} + void OnHandshakePacketSent() override {} + void OnConnectionClosed(QuicErrorCode /*error*/, + ConnectionCloseSource /*source*/) override {} void OnHandshakeDoneReceived() override {} - MOCK_METHOD0(OnCanWrite, void()); + MOCK_METHOD(void, OnCanWrite, (), (override)); bool HasPendingCryptoRetransmission() const override { return false; } - MOCK_CONST_METHOD0(HasPendingRetransmission, bool()); + MOCK_METHOD(bool, HasPendingRetransmission, (), (const, override)); private: using QuicCryptoStream::session; @@ -144,7 +150,8 @@ class TestStream : public QuicSpdyStream { QuicSpdySession* session, bool should_process_data) : QuicSpdyStream(id, session, BIDIRECTIONAL), - should_process_data_(should_process_data) {} + should_process_data_(should_process_data), + headers_payload_length_(0) {} ~TestStream() override = default; using QuicSpdyStream::set_ack_listener; @@ -163,7 +170,7 @@ class TestStream : public QuicSpdyStream { data_ += std::string(buffer, bytes_read); } - MOCK_METHOD1(WriteHeadersMock, void(bool fin)); + MOCK_METHOD(void, WriteHeadersMock, (bool fin), ()); size_t WriteHeadersImpl(spdy::SpdyHeaderBlock header_block, bool fin, @@ -174,7 +181,8 @@ class TestStream : public QuicSpdyStream { if (VersionUsesHttp3(transport_version())) { // In this case, call QuicSpdyStream::WriteHeadersImpl() that does the // actual work of closing the stream. - QuicSpdyStream::WriteHeadersImpl(saved_headers_.Clone(), fin, nullptr); + return QuicSpdyStream::WriteHeadersImpl(saved_headers_.Clone(), fin, + nullptr); } return 0; } @@ -187,10 +195,20 @@ class TestStream : public QuicSpdyStream { return QuicStream::sequencer(); } + void OnStreamHeaderList(bool fin, + size_t frame_len, + const QuicHeaderList& header_list) override { + headers_payload_length_ = frame_len; + QuicSpdyStream::OnStreamHeaderList(fin, frame_len, header_list); + } + + size_t headers_payload_length() const { return headers_payload_length_; } + private: bool should_process_data_; spdy::SpdyHeaderBlock saved_headers_; std::string data_; + size_t headers_payload_length_; }; class TestSession : public MockQuicSpdySession { @@ -306,6 +324,7 @@ class QuicSpdyStreamTest : public QuicTestWithParam<ParsedQuicVersion> { &helper_, &alarm_factory_, perspective, SupportedVersions(GetParam())); session_ = std::make_unique<StrictMock<TestSession>>(connection_); session_->Initialize(); + connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1)); ON_CALL(*session_, WritevData(_, _, _, _, _, _)) .WillByDefault( Invoke(session_.get(), &MockQuicSpdySession::ConsumeData)); @@ -337,18 +356,9 @@ class QuicSpdyStreamTest : public QuicTestWithParam<ParsedQuicVersion> { EXPECT_CALL(*session_, WritevData(send_control_stream->id(), _, _, _, _, _)) .Times(num_control_stream_writes); - auto qpack_decoder_stream = - QuicSpdySessionPeer::GetQpackDecoderSendStream(session_.get()); - EXPECT_CALL(*session_, - WritevData(qpack_decoder_stream->id(), 1, 0, _, _, _)); - auto qpack_encoder_stream = - QuicSpdySessionPeer::GetQpackEncoderSendStream(session_.get()); - EXPECT_CALL(*session_, - WritevData(qpack_encoder_stream->id(), 1, 0, _, _, _)); } TestCryptoStream* crypto_stream = session_->GetMutableCryptoStream(); - EXPECT_CALL(*crypto_stream, HasPendingRetransmission()) - .Times(testing::AnyNumber()); + EXPECT_CALL(*crypto_stream, HasPendingRetransmission()).Times(AnyNumber()); if (connection_->version().HasHandshakeDone() && session_->perspective() == Perspective::IS_SERVER) { @@ -399,6 +409,21 @@ class QuicSpdyStreamTest : public QuicTestWithParam<ParsedQuicVersion> { return quiche::QuicheStrCat(headers_frame_header, payload); } + // Construct PUSH_PROMISE frame with given payload. + std::string SerializePushPromiseFrame(PushId push_id, + quiche::QuicheStringPiece payload) { + PushPromiseFrame frame; + frame.push_id = push_id; + frame.headers = payload; + std::unique_ptr<char[]> push_promise_buffer; + QuicByteCount push_promise_frame_header_length = + HttpEncoder::SerializePushPromiseFrameWithOnlyPushId( + frame, &push_promise_buffer); + quiche::QuicheStringPiece push_promise_frame_header( + push_promise_buffer.get(), push_promise_frame_header_length); + return quiche::QuicheStrCat(push_promise_frame_header, payload); + } + std::string DataFrame(quiche::QuicheStringPiece payload) { std::unique_ptr<char[]> data_buffer; QuicByteCount data_frame_header_length = @@ -479,15 +504,18 @@ TEST_P(QuicSpdyStreamTest, ProcessTooLargeHeaderList) { QuicStreamFrame frame(stream_->id(), false, 0, headers); - EXPECT_CALL( - *connection_, - CloseConnection(QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE, - MatchesRegex("Too large headers received on stream \\d+"), - _)); + EXPECT_CALL(*session_, + SendRstStream(stream_->id(), QUIC_HEADERS_TOO_LARGE, 0)); - stream_->OnStreamFrame(frame); + auto qpack_decoder_stream = + QuicSpdySessionPeer::GetQpackDecoderSendStream(session_.get()); + // Stream type and stream cancellation. + EXPECT_CALL(*session_, + WritevData(qpack_decoder_stream->id(), _, _, NO_FIN, _, _)) + .Times(2); - EXPECT_TRUE(stream_->header_list().empty()); + stream_->OnStreamFrame(frame); + EXPECT_THAT(stream_->stream_error(), IsStreamError(QUIC_HEADERS_TOO_LARGE)); } TEST_P(QuicSpdyStreamTest, ProcessHeaderListWithFin) { @@ -880,6 +908,7 @@ TEST_P(QuicSpdyStreamTest, StreamFlowControlBlocked) { } EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) .WillOnce(Return(QuicConsumedData(kWindow - kHeaderLength, true))); + EXPECT_CALL(*session_, SendBlocked(_)); EXPECT_CALL(*connection_, SendControlFrame(_)); stream_->WriteOrBufferBody(body, false); @@ -899,7 +928,7 @@ TEST_P(QuicSpdyStreamTest, StreamFlowControlNoWindowUpdateIfNotConsumed) { Initialize(!kShouldProcessData); // Expect no WINDOW_UPDATE frames to be sent. - EXPECT_CALL(*connection_, SendWindowUpdate(_, _)).Times(0); + EXPECT_CALL(*session_, SendWindowUpdate(_, _)).Times(0); // Set a small flow control receive window. const uint64_t kWindow = 36; @@ -993,6 +1022,7 @@ TEST_P(QuicSpdyStreamTest, StreamFlowControlWindowUpdate) { QuicStreamFrame frame2(GetNthClientInitiatedBidirectionalId(0), false, kWindow / 3 + header_length, quiche::QuicheStringPiece(data)); + EXPECT_CALL(*session_, SendWindowUpdate(_, _)); EXPECT_CALL(*connection_, SendControlFrame(_)); stream_->OnStreamFrame(frame2); EXPECT_EQ(kWindow, QuicFlowControllerPeer::ReceiveWindowSize( @@ -1065,6 +1095,7 @@ TEST_P(QuicSpdyStreamTest, ConnectionFlowControlWindowUpdate) { // Now receive a further single byte on one stream - again this does not // trigger a stream WINDOW_UPDATE, but now the connection flow control window // is over half full and thus a connection WINDOW_UPDATE is sent. + EXPECT_CALL(*session_, SendWindowUpdate(_, _)); EXPECT_CALL(*connection_, SendControlFrame(_)); QuicStreamFrame frame3(GetNthClientInitiatedBidirectionalId(0), false, body.length() + header_length, @@ -1151,8 +1182,7 @@ TEST_P(QuicSpdyStreamTest, StreamFlowControlFinNotBlocked) { std::string body = ""; bool fin = true; - EXPECT_CALL(*connection_, - SendBlocked(GetNthClientInitiatedBidirectionalId(0))) + EXPECT_CALL(*session_, SendBlocked(GetNthClientInitiatedBidirectionalId(0))) .Times(0); EXPECT_CALL(*session_, WritevData(_, 0, _, FIN, _, _)); @@ -2148,8 +2178,14 @@ TEST_P(QuicSpdyStreamTest, ImmediateHeaderDecodingWithDynamicTableEntries) { std::string headers = HeadersFrame(encoded_headers); EXPECT_CALL(debug_visitor, OnHeadersFrameReceived(stream_->id(), encoded_headers.length())); - // Decoder stream type and header acknowledgement. - EXPECT_CALL(*session_, WritevData(decoder_send_stream->id(), _, _, _, _, _)); + // Decoder stream type. + EXPECT_CALL(*session_, + WritevData(decoder_send_stream->id(), /* write_length = */ 1, + /* offset = */ 0, _, _, _)); + // Header acknowledgement. + EXPECT_CALL(*session_, + WritevData(decoder_send_stream->id(), /* write_length = */ 1, + /* offset = */ 1, _, _, _)); EXPECT_CALL(debug_visitor, OnHeadersDecoded(stream_->id(), _)); stream_->OnStreamFrame(QuicStreamFrame(stream_->id(), false, 0, headers)); @@ -2216,8 +2252,14 @@ TEST_P(QuicSpdyStreamTest, BlockedHeaderDecoding) { auto decoder_send_stream = QuicSpdySessionPeer::GetQpackDecoderSendStream(session_.get()); - // Decoder stream type and header acknowledgement. - EXPECT_CALL(*session_, WritevData(decoder_send_stream->id(), _, _, _, _, _)); + // Decoder stream type. + EXPECT_CALL(*session_, + WritevData(decoder_send_stream->id(), /* write_length = */ 1, + /* offset = */ 0, _, _, _)); + // Header acknowledgement. + EXPECT_CALL(*session_, + WritevData(decoder_send_stream->id(), /* write_length = */ 1, + /* offset = */ 1, _, _, _)); EXPECT_CALL(debug_visitor, OnHeadersDecoded(stream_->id(), _)); // Deliver dynamic table entry to decoder. session_->qpack_decoder()->OnInsertWithoutNameReference("foo", "bar"); @@ -2247,6 +2289,7 @@ TEST_P(QuicSpdyStreamTest, BlockedHeaderDecoding) { // Decoding is blocked because dynamic table entry has not been received yet. EXPECT_FALSE(stream_->trailers_decompressed()); + // Header acknowledgement. EXPECT_CALL(*session_, WritevData(decoder_send_stream->id(), _, _, _, _, _)); EXPECT_CALL(debug_visitor, OnHeadersDecoded(stream_->id(), _)); // Deliver second dynamic table entry to decoder. @@ -2341,8 +2384,14 @@ TEST_P(QuicSpdyStreamTest, AsyncErrorDecodingTrailers) { auto decoder_send_stream = QuicSpdySessionPeer::GetQpackDecoderSendStream(session_.get()); - // The stream byte will be written in the first byte. - EXPECT_CALL(*session_, WritevData(decoder_send_stream->id(), _, _, _, _, _)); + // Decoder stream type. + EXPECT_CALL(*session_, + WritevData(decoder_send_stream->id(), /* write_length = */ 1, + /* offset = */ 0, _, _, _)); + // Header acknowledgement. + EXPECT_CALL(*session_, + WritevData(decoder_send_stream->id(), /* write_length = */ 1, + /* offset = */ 1, _, _, _)); // Deliver dynamic table entry to decoder. session_->qpack_decoder()->OnInsertWithoutNameReference("foo", "bar"); EXPECT_TRUE(stream_->headers_decompressed()); @@ -2607,13 +2656,7 @@ TEST_P(QuicSpdyStreamTest, PushPromiseOnDataStream) { std::string headers = EncodeQpackHeaders(pushed_headers); const QuicStreamId push_id = 1; - PushPromiseFrame push_promise; - push_promise.push_id = push_id; - push_promise.headers = headers; - std::unique_ptr<char[]> buffer; - uint64_t length = HttpEncoder::SerializePushPromiseFrameWithOnlyPushId( - push_promise, &buffer); - std::string data = std::string(buffer.get(), length) + headers; + std::string data = SerializePushPromiseFrame(push_id, headers); QuicStreamFrame frame(stream_->id(), false, 0, data); EXPECT_CALL(debug_visitor, OnPushPromiseFrameReceived(stream_->id(), push_id, @@ -2622,11 +2665,40 @@ TEST_P(QuicSpdyStreamTest, PushPromiseOnDataStream) { OnPushPromiseDecoded(stream_->id(), push_id, AsHeaderList(pushed_headers))); EXPECT_CALL(*session_, - OnPromiseHeaderList(stream_->id(), push_promise.push_id, - headers.length(), _)); + OnPromiseHeaderList(stream_->id(), push_id, headers.length(), _)); stream_->OnStreamFrame(frame); } +// Regression test for b/152518220. +TEST_P(QuicSpdyStreamTest, + OnStreamHeaderBlockArgumentDoesNotIncludePushedHeaderBlock) { + Initialize(kShouldProcessData); + if (!UsesHttp3()) { + return; + } + + std::string pushed_headers = EncodeQpackHeaders({{"foo", "bar"}}); + const QuicStreamId push_id = 1; + std::string push_promise_frame = + SerializePushPromiseFrame(push_id, pushed_headers); + QuicStreamOffset offset = 0; + QuicStreamFrame frame1(stream_->id(), /* fin = */ false, offset, + push_promise_frame); + offset += push_promise_frame.length(); + + EXPECT_CALL(*session_, OnPromiseHeaderList(stream_->id(), push_id, + pushed_headers.length(), _)); + stream_->OnStreamFrame(frame1); + + std::string headers = + EncodeQpackHeaders({{":method", "GET"}, {":path", "/"}}); + std::string headers_frame = HeadersFrame(headers); + QuicStreamFrame frame2(stream_->id(), /* fin = */ false, offset, + headers_frame); + stream_->OnStreamFrame(frame2); + EXPECT_EQ(headers.length(), stream_->headers_payload_length()); +} + // Close connection if a DATA frame is received before a HEADERS frame. TEST_P(QuicSpdyStreamTest, DataBeforeHeaders) { if (!UsesHttp3()) { @@ -2794,7 +2866,14 @@ TEST_P(QuicSpdyStreamTest, StreamCancellationWhenStreamReset) { auto qpack_decoder_stream = QuicSpdySessionPeer::GetQpackDecoderSendStream(session_.get()); - EXPECT_CALL(*session_, WritevData(qpack_decoder_stream->id(), 1, 1, _, _, _)); + // Stream type. + EXPECT_CALL(*session_, + WritevData(qpack_decoder_stream->id(), /* write_length = */ 1, + /* offset = */ 0, _, _, _)); + // Stream cancellation. + EXPECT_CALL(*session_, + WritevData(qpack_decoder_stream->id(), /* write_length = */ 1, + /* offset = */ 1, _, _, _)); EXPECT_CALL(*session_, SendRstStream(stream_->id(), QUIC_STREAM_CANCELLED, 0)); @@ -2812,12 +2891,57 @@ TEST_P(QuicSpdyStreamTest, StreamCancellationOnResetReceived) { auto qpack_decoder_stream = QuicSpdySessionPeer::GetQpackDecoderSendStream(session_.get()); - EXPECT_CALL(*session_, WritevData(qpack_decoder_stream->id(), 1, 1, _, _, _)); + // Stream type. + EXPECT_CALL(*session_, + WritevData(qpack_decoder_stream->id(), /* write_length = */ 1, + /* offset = */ 0, _, _, _)); + // Stream cancellation. + EXPECT_CALL(*session_, + WritevData(qpack_decoder_stream->id(), /* write_length = */ 1, + /* offset = */ 1, _, _, _)); stream_->OnStreamReset(QuicRstStreamFrame( kInvalidControlFrameId, stream_->id(), QUIC_STREAM_CANCELLED, 0)); } +TEST_P(QuicSpdyStreamTest, WriteHeadersReturnValue) { + if (!UsesHttp3()) { + return; + } + + Initialize(kShouldProcessData); + testing::InSequence s; + + // Enable QPACK dynamic table. + session_->OnSetting(SETTINGS_QPACK_MAX_TABLE_CAPACITY, 1024); + session_->OnSetting(SETTINGS_QPACK_BLOCKED_STREAMS, 1); + + EXPECT_CALL(*stream_, WriteHeadersMock(true)); + + QpackSendStream* encoder_stream = + QuicSpdySessionPeer::GetQpackEncoderSendStream(session_.get()); + EXPECT_CALL(*session_, WritevData(encoder_stream->id(), _, _, _, _, _)) + .Times(AnyNumber()); + + // HEADERS frame header. + EXPECT_CALL(*session_, + WritevData(stream_->id(), _, /* offset = */ 0, _, _, _)); + // HEADERS frame payload. + size_t headers_frame_payload_length = 0; + EXPECT_CALL(*session_, WritevData(stream_->id(), _, _, _, _, _)) + .WillOnce( + DoAll(SaveArg<1>(&headers_frame_payload_length), + Invoke(session_.get(), &MockQuicSpdySession::ConsumeData))); + + SpdyHeaderBlock request_headers; + request_headers["foo"] = "bar"; + size_t write_headers_return_value = + stream_->WriteHeaders(std::move(request_headers), /*fin=*/true, nullptr); + EXPECT_TRUE(stream_->fin_sent()); + + EXPECT_EQ(headers_frame_payload_length, write_headers_return_value); +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.cc b/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.cc index 6e8f13a10d6..6120f850bbc 100644 --- a/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.cc +++ b/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.cc @@ -29,12 +29,27 @@ LegacyQuicStreamIdManager::LegacyQuicStreamIdManager( ? (QuicVersionUsesCryptoFrames(transport_version_) ? QuicUtils::GetInvalidStreamId(transport_version_) : QuicUtils::GetCryptoStreamId(transport_version_)) - : QuicUtils::GetInvalidStreamId(transport_version_)) {} + : QuicUtils::GetInvalidStreamId(transport_version_)), + num_open_incoming_streams_(0), + num_open_outgoing_streams_(0), + handles_accounting_( + GetQuicReloadableFlag(quic_stream_id_manager_handles_accounting)) { + if (handles_accounting_) { + QUIC_RELOADABLE_FLAG_COUNT(quic_stream_id_manager_handles_accounting); + } +} LegacyQuicStreamIdManager::~LegacyQuicStreamIdManager() {} bool LegacyQuicStreamIdManager::CanOpenNextOutgoingStream( size_t current_num_open_outgoing_streams) const { + if (handles_accounting_) { + DCHECK_LE(num_open_outgoing_streams_, max_open_outgoing_streams_); + QUIC_DLOG_IF(INFO, num_open_outgoing_streams_ == max_open_outgoing_streams_) + << "Failed to create a new outgoing stream. " + << "Already " << num_open_outgoing_streams_ << " open."; + return num_open_outgoing_streams_ < max_open_outgoing_streams_; + } if (current_num_open_outgoing_streams >= max_open_outgoing_streams_) { QUIC_DLOG(INFO) << "Failed to create a new outgoing stream. " << "Already " << current_num_open_outgoing_streams @@ -46,6 +61,9 @@ bool LegacyQuicStreamIdManager::CanOpenNextOutgoingStream( bool LegacyQuicStreamIdManager::CanOpenIncomingStream( size_t current_num_open_incoming_streams) const { + if (handles_accounting_) { + return num_open_incoming_streams_ < max_open_incoming_streams_; + } // Check if the new number of open streams would cause the number of // open streams to exceed the limit. return current_num_open_incoming_streams < max_open_incoming_streams_; @@ -102,6 +120,26 @@ QuicStreamId LegacyQuicStreamIdManager::GetNextOutgoingStreamId() { return id; } +void LegacyQuicStreamIdManager::ActivateStream(bool is_incoming) { + DCHECK(handles_accounting_); + if (is_incoming) { + ++num_open_incoming_streams_; + return; + } + ++num_open_outgoing_streams_; +} + +void LegacyQuicStreamIdManager::OnStreamClosed(bool is_incoming) { + DCHECK(handles_accounting_); + if (is_incoming) { + QUIC_BUG_IF(num_open_incoming_streams_ == 0); + --num_open_incoming_streams_; + return; + } + QUIC_BUG_IF(num_open_outgoing_streams_ == 0); + --num_open_outgoing_streams_; +} + bool LegacyQuicStreamIdManager::IsAvailableStream(QuicStreamId id) const { if (!IsIncomingStream(id)) { // Stream IDs under next_ougoing_stream_id_ are either open or previously diff --git a/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.h b/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.h index 1a94905e41a..6c1309ebbc9 100644 --- a/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.h @@ -46,6 +46,12 @@ class QUIC_EXPORT_PRIVATE LegacyQuicStreamIdManager { // underlying counter. QuicStreamId GetNextOutgoingStreamId(); + // Called when a new stream is open. + void ActivateStream(bool is_incoming); + + // Called when a stream ID is closed. + void OnStreamClosed(bool is_incoming); + // Return true if |id| is peer initiated. bool IsIncomingStream(QuicStreamId id) const; @@ -82,6 +88,15 @@ class QUIC_EXPORT_PRIVATE LegacyQuicStreamIdManager { size_t GetNumAvailableStreams() const; + size_t num_open_incoming_streams() const { + return num_open_incoming_streams_; + } + size_t num_open_outgoing_streams() const { + return num_open_outgoing_streams_; + } + + bool handles_accounting() const { return handles_accounting_; } + private: friend class test::QuicSessionPeer; @@ -99,9 +114,20 @@ class QUIC_EXPORT_PRIVATE LegacyQuicStreamIdManager { // Set of stream ids that are less than the largest stream id that has been // received, but are nonetheless available to be created. - QuicUnorderedSet<QuicStreamId> available_streams_; + QuicHashSet<QuicStreamId> available_streams_; QuicStreamId largest_peer_created_stream_id_; + + // A counter for peer initiated open streams. Used when handles_accounting_ is + // true. + size_t num_open_incoming_streams_; + + // A counter for self initiated open streams. Used when handles_accounting_ is + // true. + size_t num_open_outgoing_streams_; + + // Latched value of quic_stream_id_manager_handles_accounting. + const bool handles_accounting_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager_test.cc index bd37ffe338e..00654b48c45 100644 --- a/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager_test.cc @@ -78,15 +78,31 @@ INSTANTIATE_TEST_SUITE_P(Tests, ::testing::PrintToStringParamName()); TEST_P(LegacyQuicStreamIdManagerTest, CanOpenNextOutgoingStream) { + if (GetQuicReloadableFlag(quic_stream_id_manager_handles_accounting)) { + for (size_t i = 0; i < manager_.max_open_outgoing_streams() - 1; ++i) { + manager_.ActivateStream(/*is_incoming=*/false); + } + } EXPECT_TRUE(manager_.CanOpenNextOutgoingStream( manager_.max_open_outgoing_streams() - 1)); + if (GetQuicReloadableFlag(quic_stream_id_manager_handles_accounting)) { + manager_.ActivateStream(/*is_incoming=*/false); + } EXPECT_FALSE( manager_.CanOpenNextOutgoingStream(manager_.max_open_outgoing_streams())); } TEST_P(LegacyQuicStreamIdManagerTest, CanOpenIncomingStream) { + if (GetQuicReloadableFlag(quic_stream_id_manager_handles_accounting)) { + for (size_t i = 0; i < manager_.max_open_incoming_streams() - 1; ++i) { + manager_.ActivateStream(/*is_incoming=*/true); + } + } EXPECT_TRUE( manager_.CanOpenIncomingStream(manager_.max_open_incoming_streams() - 1)); + if (GetQuicReloadableFlag(quic_stream_id_manager_handles_accounting)) { + manager_.ActivateStream(/*is_incoming=*/true); + } EXPECT_FALSE( manager_.CanOpenIncomingStream(manager_.max_open_incoming_streams())); } diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.cc index 7aa0f1125d2..6469dd266b5 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.cc @@ -5,16 +5,11 @@ #include "net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.h" #include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h" +#include "net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" namespace quic { -namespace { - -size_t kHeaderFieldSizeOverhead = 32; - -} - QpackDecodedHeadersAccumulator::QpackDecodedHeadersAccumulator( QuicStreamId id, QpackDecoder* qpack_decoder, @@ -44,7 +39,7 @@ void QpackDecodedHeadersAccumulator::OnHeaderDecoded( } uncompressed_header_bytes_including_overhead_ += - name.size() + value.size() + kHeaderFieldSizeOverhead; + name.size() + value.size() + QpackEntry::kSizeOverhead; if (uncompressed_header_bytes_including_overhead_ > max_header_list_size_) { header_list_size_limit_exceeded_ = true; diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc index c98f8543ffa..93e2561f367 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc @@ -42,11 +42,14 @@ const char* const kHeaderAcknowledgement = "\x81"; class MockVisitor : public QpackDecodedHeadersAccumulator::Visitor { public: ~MockVisitor() override = default; - MOCK_METHOD2(OnHeadersDecoded, - void(QuicHeaderList headers, - bool header_list_size_limit_exceeded)); - MOCK_METHOD1(OnHeaderDecodingError, - void(quiche::QuicheStringPiece error_message)); + MOCK_METHOD(void, + OnHeadersDecoded, + (QuicHeaderList headers, bool header_list_size_limit_exceeded), + (override)); + MOCK_METHOD(void, + OnHeaderDecodingError, + (quiche::QuicheStringPiece error_message), + (override)); }; } // anonymous namespace diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver_test.cc index 44a2286a244..70d2450662a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver_test.cc @@ -19,10 +19,16 @@ class MockDelegate : public QpackDecoderStreamReceiver::Delegate { public: ~MockDelegate() override = default; - MOCK_METHOD1(OnInsertCountIncrement, void(uint64_t increment)); - MOCK_METHOD1(OnHeaderAcknowledgement, void(QuicStreamId stream_id)); - MOCK_METHOD1(OnStreamCancellation, void(QuicStreamId stream_id)); - MOCK_METHOD1(OnErrorDetected, void(quiche::QuicheStringPiece error_message)); + MOCK_METHOD(void, OnInsertCountIncrement, (uint64_t increment), (override)); + MOCK_METHOD(void, + OnHeaderAcknowledgement, + (QuicStreamId stream_id), + (override)); + MOCK_METHOD(void, OnStreamCancellation, (QuicStreamId stream_id), (override)); + MOCK_METHOD(void, + OnErrorDetected, + (quiche::QuicheStringPiece error_message), + (override)); }; class QpackDecoderStreamReceiverTest : public QuicTest { diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc index 2b30e982ea7..db7ec794268 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc @@ -80,6 +80,11 @@ QpackEncoder::Instructions QpackEncoder::FirstPassEncode( const spdy::SpdyHeaderBlock& header_list, QpackBlockingManager::IndexSet* referred_indices, QuicByteCount* encoder_stream_sent_byte_count) { + // If previous instructions are buffered in |encoder_stream_sender_|, + // do not count them towards the current header block. + const QuicByteCount initial_encoder_stream_buffered_byte_count = + encoder_stream_sender_.BufferedByteCount(); + Instructions instructions; instructions.reserve(header_list.size()); @@ -266,10 +271,16 @@ QpackEncoder::Instructions QpackEncoder::FirstPassEncode( } } - const QuicByteCount sent_byte_count = encoder_stream_sender_.Flush(); + const QuicByteCount encoder_stream_buffered_byte_count = + encoder_stream_sender_.BufferedByteCount(); + DCHECK_GE(encoder_stream_buffered_byte_count, + initial_encoder_stream_buffered_byte_count); if (encoder_stream_sent_byte_count) { - *encoder_stream_sent_byte_count = sent_byte_count; + *encoder_stream_sent_byte_count = + encoder_stream_buffered_byte_count - + initial_encoder_stream_buffered_byte_count; } + encoder_stream_sender_.Flush(); ++header_list_count_; @@ -374,7 +385,8 @@ void QpackEncoder::SetMaximumDynamicTableCapacity( void QpackEncoder::SetDynamicTableCapacity(uint64_t dynamic_table_capacity) { encoder_stream_sender_.SendSetDynamicTableCapacity(dynamic_table_capacity); - encoder_stream_sender_.Flush(); + // Do not flush encoder stream. This write can safely be delayed until more + // instructions are written. bool success = header_table_.SetDynamicTableCapacity(dynamic_table_capacity); DCHECK(success); diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver_test.cc index b5edd5f1472..71b6d3438e4 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver_test.cc @@ -19,16 +19,22 @@ class MockDelegate : public QpackEncoderStreamReceiver::Delegate { public: ~MockDelegate() override = default; - MOCK_METHOD3(OnInsertWithNameReference, - void(bool is_static, - uint64_t name_index, - quiche::QuicheStringPiece value)); - MOCK_METHOD2(OnInsertWithoutNameReference, - void(quiche::QuicheStringPiece name, - quiche::QuicheStringPiece value)); - MOCK_METHOD1(OnDuplicate, void(uint64_t index)); - MOCK_METHOD1(OnSetDynamicTableCapacity, void(uint64_t capacity)); - MOCK_METHOD1(OnErrorDetected, void(quiche::QuicheStringPiece error_message)); + MOCK_METHOD(void, + OnInsertWithNameReference, + (bool is_static, + uint64_t name_index, + quiche::QuicheStringPiece value), + (override)); + MOCK_METHOD(void, + OnInsertWithoutNameReference, + (quiche::QuicheStringPiece name, quiche::QuicheStringPiece value), + (override)); + MOCK_METHOD(void, OnDuplicate, (uint64_t index), (override)); + MOCK_METHOD(void, OnSetDynamicTableCapacity, (uint64_t capacity), (override)); + MOCK_METHOD(void, + OnErrorDetected, + (quiche::QuicheStringPiece error_message), + (override)); }; class QpackEncoderStreamReceiverTest : public QuicTest { diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.cc index 19311b6aeb9..0ae1aae7ff1 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.cc @@ -44,15 +44,13 @@ void QpackEncoderStreamSender::SendSetDynamicTableCapacity(uint64_t capacity) { QpackInstructionWithValues::SetDynamicTableCapacity(capacity), &buffer_); } -QuicByteCount QpackEncoderStreamSender::Flush() { +void QpackEncoderStreamSender::Flush() { if (buffer_.empty()) { - return 0; + return; } delegate_->WriteStreamData(buffer_); - const QuicByteCount bytes_written = buffer_.size(); buffer_.clear(); - return bytes_written; } } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h index 5701db54ffe..dee23c50d5b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h @@ -38,9 +38,11 @@ class QUIC_EXPORT_PRIVATE QpackEncoderStreamSender { // 5.2.4. Set Dynamic Table Capacity void SendSetDynamicTableCapacity(uint64_t capacity); + // Returns number of buffered bytes. + QuicByteCount BufferedByteCount() const { return buffer_.size(); } + // Writes all buffered instructions on the encoder stream. - // Returns the number of bytes written. - QuicByteCount Flush(); + void Flush(); // delegate must be set if dynamic table capacity is not zero. void set_qpack_stream_sender_delegate(QpackStreamSenderDelegate* delegate) { diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender_test.cc index b3fd5f9de6a..ea45acc1abd 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender_test.cc @@ -27,24 +27,29 @@ class QpackEncoderStreamSenderTest : public QuicTest { }; TEST_F(QpackEncoderStreamSenderTest, InsertWithNameReference) { + EXPECT_EQ(0u, stream_.BufferedByteCount()); + // Static, index fits in prefix, empty value. std::string expected_encoded_data = quiche::QuicheTextUtils::HexDecode("c500"); EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data))); stream_.SendInsertWithNameReference(true, 5, ""); - EXPECT_EQ(expected_encoded_data.size(), stream_.Flush()); + EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount()); + stream_.Flush(); // Static, index fits in prefix, Huffman encoded value. expected_encoded_data = quiche::QuicheTextUtils::HexDecode("c28294e7"); EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data))); stream_.SendInsertWithNameReference(true, 2, "foo"); - EXPECT_EQ(expected_encoded_data.size(), stream_.Flush()); + EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount()); + stream_.Flush(); // Not static, index does not fit in prefix, not Huffman encoded value. expected_encoded_data = quiche::QuicheTextUtils::HexDecode("bf4a03626172"); EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data))); stream_.SendInsertWithNameReference(false, 137, "bar"); - EXPECT_EQ(expected_encoded_data.size(), stream_.Flush()); + EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount()); + stream_.Flush(); // Value length does not fit in prefix. // 'Z' would be Huffman encoded to 8 bits, so no Huffman encoding is used. @@ -55,29 +60,35 @@ TEST_F(QpackEncoderStreamSenderTest, InsertWithNameReference) { "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"); EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data))); stream_.SendInsertWithNameReference(false, 42, std::string(127, 'Z')); - EXPECT_EQ(expected_encoded_data.size(), stream_.Flush()); + EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount()); + stream_.Flush(); } TEST_F(QpackEncoderStreamSenderTest, InsertWithoutNameReference) { + EXPECT_EQ(0u, stream_.BufferedByteCount()); + // Empty name and value. std::string expected_encoded_data = quiche::QuicheTextUtils::HexDecode("4000"); EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data))); stream_.SendInsertWithoutNameReference("", ""); - EXPECT_EQ(expected_encoded_data.size(), stream_.Flush()); + EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount()); + stream_.Flush(); // Huffman encoded short strings. expected_encoded_data = quiche::QuicheTextUtils::HexDecode("6294e78294e7"); EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data))); stream_.SendInsertWithoutNameReference("foo", "foo"); - EXPECT_EQ(expected_encoded_data.size(), stream_.Flush()); + EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount()); + stream_.Flush(); // Not Huffman encoded short strings. expected_encoded_data = quiche::QuicheTextUtils::HexDecode("4362617203626172"); EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data))); stream_.SendInsertWithoutNameReference("bar", "bar"); - EXPECT_EQ(expected_encoded_data.size(), stream_.Flush()); + EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount()); + stream_.Flush(); // Not Huffman encoded long strings; length does not fit on prefix. // 'Z' would be Huffman encoded to 8 bits, so no Huffman encoding is used. @@ -90,35 +101,46 @@ TEST_F(QpackEncoderStreamSenderTest, InsertWithoutNameReference) { EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data))); stream_.SendInsertWithoutNameReference(std::string(31, 'Z'), std::string(127, 'Z')); - EXPECT_EQ(expected_encoded_data.size(), stream_.Flush()); + EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount()); + stream_.Flush(); } TEST_F(QpackEncoderStreamSenderTest, Duplicate) { + EXPECT_EQ(0u, stream_.BufferedByteCount()); + // Small index fits in prefix. std::string expected_encoded_data = quiche::QuicheTextUtils::HexDecode("11"); EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data))); stream_.SendDuplicate(17); - EXPECT_EQ(expected_encoded_data.size(), stream_.Flush()); + EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount()); + stream_.Flush(); // Large index requires two extension bytes. expected_encoded_data = quiche::QuicheTextUtils::HexDecode("1fd503"); EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data))); stream_.SendDuplicate(500); - EXPECT_EQ(expected_encoded_data.size(), stream_.Flush()); + EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount()); + stream_.Flush(); } TEST_F(QpackEncoderStreamSenderTest, SetDynamicTableCapacity) { + EXPECT_EQ(0u, stream_.BufferedByteCount()); + // Small capacity fits in prefix. std::string expected_encoded_data = quiche::QuicheTextUtils::HexDecode("31"); EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data))); stream_.SendSetDynamicTableCapacity(17); - EXPECT_EQ(expected_encoded_data.size(), stream_.Flush()); + EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount()); + stream_.Flush(); + EXPECT_EQ(0u, stream_.BufferedByteCount()); // Large capacity requires two extension bytes. expected_encoded_data = quiche::QuicheTextUtils::HexDecode("3fd503"); EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data))); stream_.SendSetDynamicTableCapacity(500); - EXPECT_EQ(expected_encoded_data.size(), stream_.Flush()); + EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount()); + stream_.Flush(); + EXPECT_EQ(0u, stream_.BufferedByteCount()); } // No writes should happen until Flush is called. @@ -142,13 +164,17 @@ TEST_F(QpackEncoderStreamSenderTest, Coalesce) { "11"); // Duplicate entry. EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data))); - EXPECT_EQ(expected_encoded_data.size(), stream_.Flush()); + EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount()); + stream_.Flush(); + EXPECT_EQ(0u, stream_.BufferedByteCount()); } // No writes should happen if QpackEncoderStreamSender::Flush() is called // when the buffer is empty. TEST_F(QpackEncoderStreamSenderTest, FlushEmpty) { - EXPECT_EQ(0u, stream_.Flush()); + EXPECT_EQ(0u, stream_.BufferedByteCount()); + stream_.Flush(); + EXPECT_EQ(0u, stream_.BufferedByteCount()); } } // namespace diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test.cc index 212257cedb6..e0d21c53269 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test.cc @@ -12,6 +12,7 @@ #include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_test_utils.h" #include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_header_table_peer.h" #include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" #include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h" @@ -213,11 +214,6 @@ TEST_F(QpackEncoderTest, InvalidHeaderAcknowledgement) { TEST_F(QpackEncoderTest, DynamicTable) { encoder_.SetMaximumBlockedStreams(1); encoder_.SetMaximumDynamicTableCapacity(4096); - - // Set Dynamic Table Capacity instruction. - EXPECT_CALL( - encoder_stream_sender_delegate_, - WriteStreamData(Eq(quiche::QuicheTextUtils::HexDecode("3fe11f")))); encoder_.SetDynamicTableCapacity(4096); spdy::SpdyHeaderBlock header_list; @@ -226,6 +222,9 @@ TEST_F(QpackEncoderTest, DynamicTable) { "baz"); // name matches dynamic entry header_list["cookie"] = "baz"; // name matches static entry + // Set Dynamic Table Capacity instruction. + std::string set_dyanamic_table_capacity = + quiche::QuicheTextUtils::HexDecode("3fe11f"); // Insert three entries into the dynamic table. std::string insert_entries = quiche::QuicheTextUtils::HexDecode( "62" // insert without name reference @@ -236,7 +235,8 @@ TEST_F(QpackEncoderTest, DynamicTable) { "c5" // insert with name reference, static index 5 "0362617a"); // value "baz" EXPECT_CALL(encoder_stream_sender_delegate_, - WriteStreamData(Eq(insert_entries))); + WriteStreamData(Eq(quiche::QuicheStrCat( + set_dyanamic_table_capacity, insert_entries)))); EXPECT_EQ(quiche::QuicheTextUtils::HexDecode( "0400" // prefix @@ -250,10 +250,6 @@ TEST_F(QpackEncoderTest, DynamicTable) { TEST_F(QpackEncoderTest, SmallDynamicTable) { encoder_.SetMaximumBlockedStreams(1); encoder_.SetMaximumDynamicTableCapacity(QpackEntry::Size("foo", "bar")); - - // Set Dynamic Table Capacity instruction. - EXPECT_CALL(encoder_stream_sender_delegate_, - WriteStreamData(Eq(quiche::QuicheTextUtils::HexDecode("3f07")))); encoder_.SetDynamicTableCapacity(QpackEntry::Size("foo", "bar")); spdy::SpdyHeaderBlock header_list; @@ -263,13 +259,17 @@ TEST_F(QpackEncoderTest, SmallDynamicTable) { header_list["cookie"] = "baz"; // name matches static entry header_list["bar"] = "baz"; // no match + // Set Dynamic Table Capacity instruction. + std::string set_dyanamic_table_capacity = + quiche::QuicheTextUtils::HexDecode("3f07"); // Insert one entry into the dynamic table. std::string insert_entry = quiche::QuicheTextUtils::HexDecode( "62" // insert without name reference "94e7" // Huffman-encoded name "foo" "03626172"); // value "bar" EXPECT_CALL(encoder_stream_sender_delegate_, - WriteStreamData(Eq(insert_entry))); + WriteStreamData(Eq(quiche::QuicheStrCat( + set_dyanamic_table_capacity, insert_entry)))); EXPECT_EQ(quiche::QuicheTextUtils::HexDecode( "0200" // prefix @@ -288,23 +288,22 @@ TEST_F(QpackEncoderTest, SmallDynamicTable) { TEST_F(QpackEncoderTest, BlockedStream) { encoder_.SetMaximumBlockedStreams(1); encoder_.SetMaximumDynamicTableCapacity(4096); - - // Set Dynamic Table Capacity instruction. - EXPECT_CALL( - encoder_stream_sender_delegate_, - WriteStreamData(Eq(quiche::QuicheTextUtils::HexDecode("3fe11f")))); encoder_.SetDynamicTableCapacity(4096); spdy::SpdyHeaderBlock header_list1; header_list1["foo"] = "bar"; + // Set Dynamic Table Capacity instruction. + std::string set_dyanamic_table_capacity = + quiche::QuicheTextUtils::HexDecode("3fe11f"); // Insert one entry into the dynamic table. std::string insert_entry1 = quiche::QuicheTextUtils::HexDecode( "62" // insert without name reference "94e7" // Huffman-encoded name "foo" "03626172"); // value "bar" EXPECT_CALL(encoder_stream_sender_delegate_, - WriteStreamData(Eq(insert_entry1))); + WriteStreamData(Eq(quiche::QuicheStrCat( + set_dyanamic_table_capacity, insert_entry1)))); EXPECT_EQ(quiche::QuicheTextUtils::HexDecode("0200" // prefix "80"), // dynamic entry 0 @@ -420,12 +419,10 @@ TEST_F(QpackEncoderTest, Draining) { } maximum_dynamic_table_capacity += QpackEntry::Size("one", "foo"); encoder_.SetMaximumDynamicTableCapacity(maximum_dynamic_table_capacity); - - // Set Dynamic Table Capacity instruction. - EXPECT_CALL(encoder_stream_sender_delegate_, WriteStreamData(_)); encoder_.SetDynamicTableCapacity(maximum_dynamic_table_capacity); - // Insert ten entries into the dynamic table. + // Set Dynamic Table Capacity instruction and insert ten entries into the + // dynamic table. EXPECT_CALL(encoder_stream_sender_delegate_, WriteStreamData(_)); EXPECT_EQ(quiche::QuicheTextUtils::HexDecode( @@ -466,10 +463,6 @@ TEST_F(QpackEncoderTest, Draining) { TEST_F(QpackEncoderTest, DynamicTableCapacityLessThanMaximum) { encoder_.SetMaximumDynamicTableCapacity(1024); - - // Set Dynamic Table Capacity instruction. - EXPECT_CALL(encoder_stream_sender_delegate_, - WriteStreamData(Eq(quiche::QuicheTextUtils::HexDecode("3e")))); encoder_.SetDynamicTableCapacity(30); QpackHeaderTable* header_table = QpackEncoderPeer::header_table(&encoder_); diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table_test.cc index 5cf392023af..a96159be486 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table_test.cc @@ -25,8 +25,8 @@ class MockObserver : public QpackHeaderTable::Observer { public: ~MockObserver() override = default; - MOCK_METHOD0(OnInsertCountReachedThreshold, void()); - MOCK_METHOD0(Cancel, void()); + MOCK_METHOD(void, OnInsertCountReachedThreshold, (), (override)); + MOCK_METHOD(void, Cancel, (), (override)); }; class QpackHeaderTableTest : public QuicTest { diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder_test.cc index 99cda08dd28..a4bbc91aaf5 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder_test.cc @@ -61,8 +61,14 @@ class MockDelegate : public QpackInstructionDecoder::Delegate { MockDelegate& operator=(const MockDelegate&) = delete; ~MockDelegate() override = default; - MOCK_METHOD1(OnInstructionDecoded, bool(const QpackInstruction* instruction)); - MOCK_METHOD1(OnError, void(quiche::QuicheStringPiece error_message)); + MOCK_METHOD(bool, + OnInstructionDecoded, + (const QpackInstruction*), + (override)); + MOCK_METHOD(void, + OnError, + (quiche::QuicheStringPiece error_message), + (override)); }; class QpackInstructionDecoderTest : public QuicTestWithParam<FragmentMode> { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_alarm_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_alarm_test.cc index b2f4690f9a5..87cbd699dff 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_alarm_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_alarm_test.cc @@ -14,7 +14,7 @@ namespace { class MockDelegate : public QuicAlarm::Delegate { public: - MOCK_METHOD0(OnAlarm, void()); + MOCK_METHOD(void, OnAlarm, (), (override)); }; class DestructiveDelegate : public QuicAlarm::Delegate { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_arena_scoped_ptr_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_arena_scoped_ptr_test.cc index cd0780fe508..5b7548a5c53 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_arena_scoped_ptr_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_arena_scoped_ptr_test.cc @@ -13,7 +13,7 @@ namespace { enum class TestParam { kFromHeap, kFromArena }; struct TestObject { - explicit TestObject(uintptr_t value) : value(value) { buffer.resize(1200); } + explicit TestObject(uintptr_t value) : value(value) { buffer.resize(1024); } uintptr_t value; // Ensure that we have a non-trivial destructor that will leak memory if it's @@ -51,7 +51,7 @@ class QuicArenaScopedPtrParamTest : public QuicTestWithParam<TestParam> { } private: - QuicOneBlockArena<1200> arena_; + QuicOneBlockArena<1024> arena_; }; INSTANTIATE_TEST_SUITE_P(QuicArenaScopedPtrParamTest, @@ -69,7 +69,7 @@ TEST_P(QuicArenaScopedPtrParamTest, NullObjects) { } TEST_P(QuicArenaScopedPtrParamTest, FromArena) { - QuicOneBlockArena<1200> arena_; + QuicOneBlockArena<1024> arena_; EXPECT_TRUE(arena_.New<TestObject>(0).is_from_arena()); EXPECT_FALSE( QuicArenaScopedPtr<TestObject>(new TestObject(0)).is_from_arena()); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store.cc b/chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store.cc index e363461cf8c..cafe871f38b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store.cc @@ -86,23 +86,25 @@ EnqueuePacketResult QuicBufferedPacketStore::EnqueuePacket( QuicSocketAddress self_address, QuicSocketAddress peer_address, bool is_chlo, - const std::string& alpn, + const std::vector<std::string>& alpns, const ParsedQuicVersion& version) { QUIC_BUG_IF(!GetQuicFlag(FLAGS_quic_allow_chlo_buffering)) << "Shouldn't buffer packets if disabled via flag."; QUIC_BUG_IF(is_chlo && QuicContainsKey(connections_with_chlo_, connection_id)) << "Shouldn't buffer duplicated CHLO on connection " << connection_id; - QUIC_BUG_IF(!is_chlo && !alpn.empty()) + QUIC_BUG_IF(!is_chlo && !alpns.empty()) << "Shouldn't have an ALPN defined for a non-CHLO packet."; QUIC_BUG_IF(is_chlo && version.transport_version == QUIC_VERSION_UNSUPPORTED) << "Should have version for CHLO packet."; - if (!QuicContainsKey(undecryptable_packets_, connection_id) && - ShouldBufferPacket(is_chlo)) { - // Drop the packet if the upper limit of undecryptable packets has been - // reached or the whole capacity of the store has been reached. - return TOO_MANY_CONNECTIONS; - } else if (!QuicContainsKey(undecryptable_packets_, connection_id)) { + const bool is_first_packet = + !QuicContainsKey(undecryptable_packets_, connection_id); + if (is_first_packet) { + if (ShouldBufferPacket(is_chlo)) { + // Drop the packet if the upper limit of undecryptable packets has been + // reached or the whole capacity of the store has been reached. + return TOO_MANY_CONNECTIONS; + } undecryptable_packets_.emplace( std::make_pair(connection_id, BufferedPacketList())); undecryptable_packets_.back().second.ietf_quic = ietf_quic; @@ -138,14 +140,25 @@ EnqueuePacketResult QuicBufferedPacketStore::EnqueuePacket( // Add CHLO to the beginning of buffered packets so that it can be delivered // first later. queue.buffered_packets.push_front(std::move(new_entry)); - queue.alpn = alpn; + queue.alpns = alpns; connections_with_chlo_[connection_id] = false; // Dummy value. // Set the version of buffered packets of this connection on CHLO. queue.version = version; } else { // Buffer non-CHLO packets in arrival order. queue.buffered_packets.push_back(std::move(new_entry)); + + // Attempt to parse multi-packet TLS CHLOs. + if (is_first_packet) { + queue.tls_chlo_extractor.IngestPacket(version, packet); + // Since this is the first packet and it's not a CHLO, the + // TlsChloExtractor should not have the entire CHLO. + QUIC_BUG_IF(queue.tls_chlo_extractor.HasParsedFullChlo()) + << "First packet in list should not contain full CHLO"; + } + // TODO(b/154857081) Reorder CHLO packets ahead of other ones. } + MaybeSetExpirationAlarm(); return SUCCESS; } @@ -240,4 +253,25 @@ bool QuicBufferedPacketStore::HasChloForConnection( return QuicContainsKey(connections_with_chlo_, connection_id); } +bool QuicBufferedPacketStore::IngestPacketForTlsChloExtraction( + const QuicConnectionId& connection_id, + const ParsedQuicVersion& version, + const QuicReceivedPacket& packet, + std::vector<std::string>* out_alpns) { + DCHECK_NE(out_alpns, nullptr); + DCHECK_EQ(version.handshake_protocol, PROTOCOL_TLS1_3); + auto it = undecryptable_packets_.find(connection_id); + if (it == undecryptable_packets_.end()) { + QUIC_BUG << "Cannot ingest packet for unknown connection ID " + << connection_id; + return false; + } + it->second.tls_chlo_extractor.IngestPacket(version, packet); + if (!it->second.tls_chlo_extractor.HasParsedFullChlo()) { + return false; + } + *out_alpns = it->second.tls_chlo_extractor.alpns(); + return true; +} + } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store.h b/chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store.h index 52d957e1a43..b862b42ee4f 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store.h @@ -13,6 +13,7 @@ #include "net/third_party/quiche/src/quic/core/quic_clock.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/core/quic_time.h" +#include "net/third_party/quiche/src/quic/core/tls_chlo_extractor.h" #include "net/third_party/quiche/src/quic/platform/api/quic_containers.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" @@ -32,7 +33,7 @@ class QuicBufferedPacketStorePeer; // of connections: connections with CHLO buffered and those without CHLO. The // latter has its own upper limit along with the max number of connections this // store can hold. The former pool can grow till this store is full. -class QUIC_EXPORT_PRIVATE QuicBufferedPacketStore { +class QUIC_NO_EXPORT QuicBufferedPacketStore { public: enum EnqueuePacketResult { SUCCESS = 0, @@ -40,7 +41,7 @@ class QUIC_EXPORT_PRIVATE QuicBufferedPacketStore { TOO_MANY_CONNECTIONS // Too many connections stored up in the store. }; - struct QUIC_EXPORT_PRIVATE BufferedPacket { + struct QUIC_NO_EXPORT BufferedPacket { BufferedPacket(std::unique_ptr<QuicReceivedPacket> packet, QuicSocketAddress self_address, QuicSocketAddress peer_address); @@ -56,7 +57,7 @@ class QUIC_EXPORT_PRIVATE QuicBufferedPacketStore { }; // A queue of BufferedPackets for a connection. - struct QUIC_EXPORT_PRIVATE BufferedPacketList { + struct QUIC_NO_EXPORT BufferedPacketList { BufferedPacketList(); BufferedPacketList(BufferedPacketList&& other); @@ -66,13 +67,14 @@ class QUIC_EXPORT_PRIVATE QuicBufferedPacketStore { std::list<BufferedPacket> buffered_packets; QuicTime creation_time; - // The alpn from the CHLO, if one was found. - std::string alpn; + // The ALPNs from the CHLO, if found. + std::vector<std::string> alpns; // Indicating whether this is an IETF QUIC connection. bool ietf_quic; // If buffered_packets contains the CHLO, it is the version of the CHLO. // Otherwise, it is the version of the first packet in |buffered_packets|. ParsedQuicVersion version; + TlsChloExtractor tls_chlo_extractor; }; typedef QuicLinkedHashMap<QuicConnectionId, @@ -80,7 +82,7 @@ class QUIC_EXPORT_PRIVATE QuicBufferedPacketStore { QuicConnectionIdHash> BufferedPacketMap; - class QUIC_EXPORT_PRIVATE VisitorInterface { + class QUIC_NO_EXPORT VisitorInterface { public: virtual ~VisitorInterface() {} @@ -108,12 +110,22 @@ class QUIC_EXPORT_PRIVATE QuicBufferedPacketStore { QuicSocketAddress self_address, QuicSocketAddress peer_address, bool is_chlo, - const std::string& alpn, + const std::vector<std::string>& alpns, const ParsedQuicVersion& version); // Returns true if there are any packets buffered for |connection_id|. bool HasBufferedPackets(QuicConnectionId connection_id) const; + // Ingests this packet into the corresponding TlsChloExtractor. This should + // only be called when HasBufferedPackets(connection_id) is true. + // Returns whether we've now parsed a full multi-packet TLS CHLO. + // When this returns true, |out_alpns| is populated with the list of ALPNs + // extracted from the CHLO. + bool IngestPacketForTlsChloExtraction(const QuicConnectionId& connection_id, + const ParsedQuicVersion& version, + const QuicReceivedPacket& packet, + std::vector<std::string>* out_alpns); + // Returns the list of buffered packets for |connection_id| and removes them // from the store. Returns an empty list if no early arrived packets for this // connection are present. diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store_test.cc index dbf6c16e627..d99f4e0586e 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_buffered_packet_store_test.cc @@ -74,13 +74,13 @@ class QuicBufferedPacketStoreTest : public QuicTest { TEST_F(QuicBufferedPacketStoreTest, SimpleEnqueueAndDeliverPacket) { QuicConnectionId connection_id = TestConnectionId(1); store_.EnqueuePacket(connection_id, false, packet_, self_address_, - peer_address_, false, "", invalid_version_); + peer_address_, false, {}, invalid_version_); EXPECT_TRUE(store_.HasBufferedPackets(connection_id)); auto packets = store_.DeliverPackets(connection_id); const std::list<BufferedPacket>& queue = packets.buffered_packets; ASSERT_EQ(1u, queue.size()); // The alpn should be ignored for non-chlo packets. - ASSERT_EQ("", packets.alpn); + ASSERT_TRUE(packets.alpns.empty()); // There is no valid version because CHLO has not arrived. EXPECT_EQ(invalid_version_, packets.version); // Check content of the only packet in the queue. @@ -97,9 +97,9 @@ TEST_F(QuicBufferedPacketStoreTest, DifferentPacketAddressOnOneConnection) { QuicSocketAddress addr_with_new_port(QuicIpAddress::Any4(), 256); QuicConnectionId connection_id = TestConnectionId(1); store_.EnqueuePacket(connection_id, false, packet_, self_address_, - peer_address_, false, "", invalid_version_); + peer_address_, false, {}, invalid_version_); store_.EnqueuePacket(connection_id, false, packet_, self_address_, - addr_with_new_port, false, "", invalid_version_); + addr_with_new_port, false, {}, invalid_version_); std::list<BufferedPacket> queue = store_.DeliverPackets(connection_id).buffered_packets; ASSERT_EQ(2u, queue.size()); @@ -114,9 +114,9 @@ TEST_F(QuicBufferedPacketStoreTest, for (uint64_t conn_id = 1; conn_id <= num_connections; ++conn_id) { QuicConnectionId connection_id = TestConnectionId(conn_id); store_.EnqueuePacket(connection_id, false, packet_, self_address_, - peer_address_, false, "", invalid_version_); + peer_address_, false, {}, invalid_version_); store_.EnqueuePacket(connection_id, false, packet_, self_address_, - peer_address_, false, "", invalid_version_); + peer_address_, false, {}, invalid_version_); } // Deliver packets in reversed order. @@ -138,12 +138,12 @@ TEST_F(QuicBufferedPacketStoreTest, // keep. EXPECT_EQ(QuicBufferedPacketStore::SUCCESS, store_.EnqueuePacket(connection_id, false, packet_, self_address_, - peer_address_, true, "", valid_version_)); + peer_address_, true, {}, valid_version_)); for (size_t i = 1; i <= num_packets; ++i) { // Only first |kDefaultMaxUndecryptablePackets packets| will be buffered. EnqueuePacketResult result = store_.EnqueuePacket(connection_id, false, packet_, self_address_, - peer_address_, false, "", invalid_version_); + peer_address_, false, {}, invalid_version_); if (i <= kDefaultMaxUndecryptablePackets) { EXPECT_EQ(EnqueuePacketResult::SUCCESS, result); } else { @@ -165,7 +165,7 @@ TEST_F(QuicBufferedPacketStoreTest, ReachNonChloConnectionUpperLimit) { QuicConnectionId connection_id = TestConnectionId(conn_id); EnqueuePacketResult result = store_.EnqueuePacket(connection_id, false, packet_, self_address_, - peer_address_, false, "", invalid_version_); + peer_address_, false, {}, invalid_version_); if (conn_id <= kMaxConnectionsWithoutCHLO) { EXPECT_EQ(EnqueuePacketResult::SUCCESS, result); } else { @@ -194,7 +194,7 @@ TEST_F(QuicBufferedPacketStoreTest, for (uint64_t conn_id = 1; conn_id <= num_chlos; ++conn_id) { EXPECT_EQ(EnqueuePacketResult::SUCCESS, store_.EnqueuePacket(TestConnectionId(conn_id), false, packet_, - self_address_, peer_address_, true, "", + self_address_, peer_address_, true, {}, valid_version_)); } @@ -205,7 +205,7 @@ TEST_F(QuicBufferedPacketStoreTest, QuicConnectionId connection_id = TestConnectionId(conn_id); EnqueuePacketResult result = store_.EnqueuePacket(connection_id, false, packet_, self_address_, - peer_address_, true, "", valid_version_); + peer_address_, true, {}, valid_version_); if (conn_id <= kDefaultMaxConnectionsInStore) { EXPECT_EQ(EnqueuePacketResult::SUCCESS, result); } else { @@ -220,7 +220,7 @@ TEST_F(QuicBufferedPacketStoreTest, EnqueueChloOnTooManyDifferentConnections) { QuicConnectionId connection_id = TestConnectionId(conn_id); EXPECT_EQ(EnqueuePacketResult::SUCCESS, store_.EnqueuePacket(connection_id, false, packet_, self_address_, - peer_address_, false, "", invalid_version_)); + peer_address_, false, {}, invalid_version_)); } // Buffer CHLOs on other connections till store is full. @@ -229,7 +229,7 @@ TEST_F(QuicBufferedPacketStoreTest, EnqueueChloOnTooManyDifferentConnections) { QuicConnectionId connection_id = TestConnectionId(i); EnqueuePacketResult rs = store_.EnqueuePacket(connection_id, false, packet_, self_address_, - peer_address_, true, "", valid_version_); + peer_address_, true, {}, valid_version_); if (i <= kDefaultMaxConnectionsInStore) { EXPECT_EQ(EnqueuePacketResult::SUCCESS, rs); EXPECT_TRUE(store_.HasChloForConnection(connection_id)); @@ -246,7 +246,7 @@ TEST_F(QuicBufferedPacketStoreTest, EnqueueChloOnTooManyDifferentConnections) { EXPECT_EQ(EnqueuePacketResult::SUCCESS, store_.EnqueuePacket( /*connection_id=*/TestConnectionId(1), false, packet_, - self_address_, peer_address_, true, "", valid_version_)); + self_address_, peer_address_, true, {}, valid_version_)); EXPECT_TRUE(store_.HasChloForConnection( /*connection_id=*/TestConnectionId(1))); @@ -274,14 +274,14 @@ TEST_F(QuicBufferedPacketStoreTest, EnqueueChloOnTooManyDifferentConnections) { TEST_F(QuicBufferedPacketStoreTest, PacketQueueExpiredBeforeDelivery) { QuicConnectionId connection_id = TestConnectionId(1); store_.EnqueuePacket(connection_id, false, packet_, self_address_, - peer_address_, false, "", invalid_version_); + peer_address_, false, {}, invalid_version_); EXPECT_EQ(EnqueuePacketResult::SUCCESS, store_.EnqueuePacket(connection_id, false, packet_, self_address_, - peer_address_, true, "", valid_version_)); + peer_address_, true, {}, valid_version_)); QuicConnectionId connection_id2 = TestConnectionId(2); EXPECT_EQ(EnqueuePacketResult::SUCCESS, store_.EnqueuePacket(connection_id2, false, packet_, self_address_, - peer_address_, false, "", invalid_version_)); + peer_address_, false, {}, invalid_version_)); // CHLO on connection 3 arrives 1ms later. clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); @@ -290,7 +290,7 @@ TEST_F(QuicBufferedPacketStoreTest, PacketQueueExpiredBeforeDelivery) { // connections. QuicSocketAddress another_client_address(QuicIpAddress::Any4(), 255); store_.EnqueuePacket(connection_id3, false, packet_, self_address_, - another_client_address, true, "", valid_version_); + another_client_address, true, {}, valid_version_); // Advance clock to the time when connection 1 and 2 expires. clock_.AdvanceTime( @@ -322,9 +322,9 @@ TEST_F(QuicBufferedPacketStoreTest, PacketQueueExpiredBeforeDelivery) { // for them to expire. QuicConnectionId connection_id4 = TestConnectionId(4); store_.EnqueuePacket(connection_id4, false, packet_, self_address_, - peer_address_, false, "", invalid_version_); + peer_address_, false, {}, invalid_version_); store_.EnqueuePacket(connection_id4, false, packet_, self_address_, - peer_address_, false, "", invalid_version_); + peer_address_, false, {}, invalid_version_); clock_.AdvanceTime( QuicBufferedPacketStorePeer::expiration_alarm(&store_)->deadline() - clock_.ApproximateNow()); @@ -339,9 +339,9 @@ TEST_F(QuicBufferedPacketStoreTest, SimpleDiscardPackets) { // Enqueue some packets store_.EnqueuePacket(connection_id, false, packet_, self_address_, - peer_address_, false, "", invalid_version_); + peer_address_, false, {}, invalid_version_); store_.EnqueuePacket(connection_id, false, packet_, self_address_, - peer_address_, false, "", invalid_version_); + peer_address_, false, {}, invalid_version_); EXPECT_TRUE(store_.HasBufferedPackets(connection_id)); EXPECT_FALSE(store_.HasChlosBuffered()); @@ -365,11 +365,11 @@ TEST_F(QuicBufferedPacketStoreTest, DiscardWithCHLOs) { // Enqueue some packets, which include a CHLO store_.EnqueuePacket(connection_id, false, packet_, self_address_, - peer_address_, false, "", invalid_version_); + peer_address_, false, {}, invalid_version_); store_.EnqueuePacket(connection_id, false, packet_, self_address_, - peer_address_, true, "", valid_version_); + peer_address_, true, {}, valid_version_); store_.EnqueuePacket(connection_id, false, packet_, self_address_, - peer_address_, false, "", invalid_version_); + peer_address_, false, {}, invalid_version_); EXPECT_TRUE(store_.HasBufferedPackets(connection_id)); EXPECT_TRUE(store_.HasChlosBuffered()); @@ -394,11 +394,11 @@ TEST_F(QuicBufferedPacketStoreTest, MultipleDiscardPackets) { // Enqueue some packets for two connection IDs store_.EnqueuePacket(connection_id_1, false, packet_, self_address_, - peer_address_, false, "", invalid_version_); + peer_address_, false, {}, invalid_version_); store_.EnqueuePacket(connection_id_1, false, packet_, self_address_, - peer_address_, false, "", invalid_version_); + peer_address_, false, {}, invalid_version_); store_.EnqueuePacket(connection_id_2, false, packet_, self_address_, - peer_address_, true, "h3", valid_version_); + peer_address_, true, {"h3"}, valid_version_); EXPECT_TRUE(store_.HasBufferedPackets(connection_id_1)); EXPECT_TRUE(store_.HasBufferedPackets(connection_id_2)); EXPECT_TRUE(store_.HasChlosBuffered()); @@ -415,7 +415,8 @@ TEST_F(QuicBufferedPacketStoreTest, MultipleDiscardPackets) { EXPECT_TRUE(store_.HasBufferedPackets(connection_id_2)); auto packets = store_.DeliverPackets(connection_id_2); EXPECT_EQ(1u, packets.buffered_packets.size()); - EXPECT_EQ("h3", packets.alpn); + ASSERT_EQ(1u, packets.alpns.size()); + EXPECT_EQ("h3", packets.alpns[0]); // Since connection_id_2's chlo arrives, verify version is set. EXPECT_EQ(valid_version_, packets.version); EXPECT_TRUE(store_.HasChlosBuffered()); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_circular_deque.h b/chromium/net/third_party/quiche/src/quic/core/quic_circular_deque.h index 997740bf300..1949d85f79e 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_circular_deque.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_circular_deque.h @@ -7,6 +7,7 @@ #include <algorithm> #include <cstddef> +#include <cstring> #include <iterator> #include <memory> #include <ostream> @@ -62,6 +63,16 @@ class QUIC_NO_EXPORT QuicCircularDeque { const basic_iterator<value_type>& it) // NOLINT(runtime/explicit) : deque_(it.deque_), index_(it.index_) {} + // A copy assignment if Pointee is T. + // A assignment from iterator to const_iterator if Pointee is const T. + basic_iterator& operator=(const basic_iterator<value_type>& it) { + if (this != &it) { + deque_ = it.deque_; + index_ = it.index_; + } + return *this; + } + reference operator*() const { return *deque_->index_to_address(index_); } pointer operator->() const { return deque_->index_to_address(index_); } reference operator[](difference_type i) { return *(*this + i); } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet.cc b/chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet.cc index 6393f5d6c8a..c18369eac9b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet.cc @@ -90,9 +90,6 @@ void QuicCoalescedPacket::Clear() { for (auto& packet : encrypted_buffers_) { packet.clear(); } - if (initial_packet_ != nullptr) { - ClearSerializedPacket(initial_packet_.get()); - } initial_packet_ = nullptr; } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet.h b/chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet.h index 1974f77c56b..447ab95bf68 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet.h @@ -36,6 +36,9 @@ class QUIC_EXPORT_PRIVATE QuicCoalescedPacket { std::string ToString(size_t serialized_length) const; + // Returns true if this coalesced packet contains packet of |level|. + bool ContainsPacketOfEncryptionLevel(EncryptionLevel level) const; + const SerializedPacket* initial_packet() const { return initial_packet_.get(); } @@ -49,9 +52,6 @@ class QUIC_EXPORT_PRIVATE QuicCoalescedPacket { QuicPacketLength max_packet_length() const { return max_packet_length_; } private: - // Returns true if this coalesced packet contains packet of |level|. - bool ContainsPacketOfEncryptionLevel(EncryptionLevel level) const; - // self/peer addresses are set when trying to coalesce the first packet. // Packets with different self/peer addresses cannot be coalesced. QuicSocketAddress self_address_; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_config.cc b/chromium/net/third_party/quiche/src/quic/core/quic_config.cc index d0087c46f09..7c781f4def0 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_config.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_config.cc @@ -6,11 +6,13 @@ #include <algorithm> #include <cstring> +#include <limits> #include <string> #include <utility> #include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/core/quic_connection_id.h" #include "net/third_party/quiche/src/quic/core/quic_constants.h" #include "net/third_party/quiche/src/quic/core/quic_socket_address_coder.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" @@ -58,74 +60,6 @@ QuicConfigValue::QuicConfigValue(QuicTag tag, QuicConfigPresence presence) : tag_(tag), presence_(presence) {} QuicConfigValue::~QuicConfigValue() {} -QuicNegotiableValue::QuicNegotiableValue(QuicTag tag, - QuicConfigPresence presence) - : QuicConfigValue(tag, presence), negotiated_(false) {} -QuicNegotiableValue::~QuicNegotiableValue() {} - -QuicNegotiableUint32::QuicNegotiableUint32(QuicTag tag, - QuicConfigPresence presence) - : QuicNegotiableValue(tag, presence), - max_value_(0), - default_value_(0), - negotiated_value_(0) {} -QuicNegotiableUint32::~QuicNegotiableUint32() {} - -void QuicNegotiableUint32::set(uint32_t max, uint32_t default_value) { - DCHECK_LE(default_value, max); - max_value_ = max; - default_value_ = default_value; -} - -uint32_t QuicNegotiableUint32::GetUint32() const { - if (negotiated()) { - return negotiated_value_; - } - return default_value_; -} - -// Returns the maximum value negotiable. -uint32_t QuicNegotiableUint32::GetMax() const { - return max_value_; -} - -void QuicNegotiableUint32::ToHandshakeMessage( - CryptoHandshakeMessage* out) const { - if (negotiated()) { - out->SetValue(tag_, negotiated_value_); - } else { - out->SetValue(tag_, max_value_); - } -} - -QuicErrorCode QuicNegotiableUint32::ProcessPeerHello( - const CryptoHandshakeMessage& peer_hello, - HelloType hello_type, - std::string* error_details) { - DCHECK(!negotiated()); - DCHECK(error_details != nullptr); - uint32_t value; - QuicErrorCode error = ReadUint32(peer_hello, tag_, presence_, default_value_, - &value, error_details); - if (error != QUIC_NO_ERROR) { - return error; - } - return ReceiveValue(value, hello_type, error_details); -} - -QuicErrorCode QuicNegotiableUint32::ReceiveValue(uint32_t value, - HelloType hello_type, - std::string* error_details) { - if (hello_type == SERVER && value > max_value_) { - *error_details = "Invalid value received for " + QuicTagToString(tag_); - return QUIC_INVALID_NEGOTIATED_VALUE; - } - - set_negotiated(true); - negotiated_value_ = std::min(value, max_value_); - return QUIC_NO_ERROR; -} - QuicFixedUint32::QuicFixedUint32(QuicTag tag, QuicConfigPresence presence) : QuicConfigValue(tag, presence), has_send_value_(false), @@ -163,6 +97,11 @@ void QuicFixedUint32::SetReceivedValue(uint32_t value) { } void QuicFixedUint32::ToHandshakeMessage(CryptoHandshakeMessage* out) const { + if (tag_ == 0) { + QUIC_BUG + << "This parameter does not support writing to CryptoHandshakeMessage"; + return; + } if (has_send_value_) { out->SetValue(tag_, send_value_); } @@ -173,6 +112,12 @@ QuicErrorCode QuicFixedUint32::ProcessPeerHello( HelloType /*hello_type*/, std::string* error_details) { DCHECK(error_details != nullptr); + if (tag_ == 0) { + *error_details = + "This parameter does not support reading from CryptoHandshakeMessage"; + QUIC_BUG << *error_details; + return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; + } QuicErrorCode error = peer_hello.GetUint32(tag_, &receive_value_); switch (error) { case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND: @@ -191,6 +136,92 @@ QuicErrorCode QuicFixedUint32::ProcessPeerHello( return error; } +QuicFixedUint62::QuicFixedUint62(QuicTag name, QuicConfigPresence presence) + : QuicConfigValue(name, presence), + has_send_value_(false), + has_receive_value_(false) {} + +QuicFixedUint62::~QuicFixedUint62() {} + +bool QuicFixedUint62::HasSendValue() const { + return has_send_value_; +} + +uint64_t QuicFixedUint62::GetSendValue() const { + if (!has_send_value_) { + QUIC_BUG << "No send value to get for tag:" << QuicTagToString(tag_); + return 0; + } + return send_value_; +} + +void QuicFixedUint62::SetSendValue(uint64_t value) { + if (value > kVarInt62MaxValue) { + QUIC_BUG << "QuicFixedUint62 invalid value " << value; + value = kVarInt62MaxValue; + } + has_send_value_ = true; + send_value_ = value; +} + +bool QuicFixedUint62::HasReceivedValue() const { + return has_receive_value_; +} + +uint64_t QuicFixedUint62::GetReceivedValue() const { + if (!has_receive_value_) { + QUIC_BUG << "No receive value to get for tag:" << QuicTagToString(tag_); + return 0; + } + return receive_value_; +} + +void QuicFixedUint62::SetReceivedValue(uint64_t value) { + has_receive_value_ = true; + receive_value_ = value; +} + +void QuicFixedUint62::ToHandshakeMessage(CryptoHandshakeMessage* out) const { + if (!has_send_value_) { + return; + } + uint32_t send_value32; + if (send_value_ > std::numeric_limits<uint32_t>::max()) { + QUIC_BUG << "Attempting to send " << send_value_ + << " for tag:" << QuicTagToString(tag_); + send_value32 = std::numeric_limits<uint32_t>::max(); + } else { + send_value32 = static_cast<uint32_t>(send_value_); + } + out->SetValue(tag_, send_value32); +} + +QuicErrorCode QuicFixedUint62::ProcessPeerHello( + const CryptoHandshakeMessage& peer_hello, + HelloType /*hello_type*/, + std::string* error_details) { + DCHECK(error_details != nullptr); + uint32_t receive_value32; + QuicErrorCode error = peer_hello.GetUint32(tag_, &receive_value32); + // GetUint32 is guaranteed to always initialize receive_value32. + receive_value_ = receive_value32; + switch (error) { + case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND: + if (presence_ == PRESENCE_OPTIONAL) { + return QUIC_NO_ERROR; + } + *error_details = "Missing " + QuicTagToString(tag_); + break; + case QUIC_NO_ERROR: + has_receive_value_ = true; + break; + default: + *error_details = "Bad " + QuicTagToString(tag_); + break; + } + return error; +} + QuicFixedUint128::QuicFixedUint128(QuicTag tag, QuicConfigPresence presence) : QuicConfigValue(tag, presence), has_send_value_(false), @@ -271,7 +302,7 @@ bool QuicFixedTagVector::HasSendValues() const { return has_send_values_; } -QuicTagVector QuicFixedTagVector::GetSendValues() const { +const QuicTagVector& QuicFixedTagVector::GetSendValues() const { QUIC_BUG_IF(!has_send_values_) << "No send values to get for tag:" << QuicTagToString(tag_); return send_values_; @@ -286,7 +317,7 @@ bool QuicFixedTagVector::HasReceivedValues() const { return has_receive_values_; } -QuicTagVector QuicFixedTagVector::GetReceivedValues() const { +const QuicTagVector& QuicFixedTagVector::GetReceivedValues() const { QUIC_BUG_IF(!has_receive_values_) << "No receive value to get for tag:" << QuicTagToString(tag_); return receive_values_; @@ -397,13 +428,13 @@ QuicErrorCode QuicFixedSocketAddress::ProcessPeerHello( } QuicConfig::QuicConfig() - : max_time_before_crypto_handshake_(QuicTime::Delta::Zero()), + : negotiated_(false), + max_time_before_crypto_handshake_(QuicTime::Delta::Zero()), max_idle_time_before_crypto_handshake_(QuicTime::Delta::Zero()), max_undecryptable_packets_(0), connection_options_(kCOPT, PRESENCE_OPTIONAL), client_connection_options_(kCLOP, PRESENCE_OPTIONAL), - idle_network_timeout_seconds_(kICSL, PRESENCE_REQUIRED), - silent_close_(kSCLS, PRESENCE_OPTIONAL), + idle_timeout_to_send_(QuicTime::Delta::Infinite()), max_bidirectional_streams_(kMIBS, PRESENCE_REQUIRED), max_unidirectional_streams_(kMIUS, PRESENCE_OPTIONAL), bytes_for_connection_id_(kTCID, PRESENCE_OPTIONAL), @@ -416,13 +447,14 @@ QuicConfig::QuicConfig() initial_stream_flow_control_window_bytes_(kSFCW, PRESENCE_OPTIONAL), initial_session_flow_control_window_bytes_(kCFCW, PRESENCE_OPTIONAL), connection_migration_disabled_(kNCMR, PRESENCE_OPTIONAL), - alternate_server_address_(kASAD, PRESENCE_OPTIONAL), - support_max_header_list_size_(kSMHL, PRESENCE_OPTIONAL), + alternate_server_address_ipv6_(kASAD, PRESENCE_OPTIONAL), + alternate_server_address_ipv4_(kASAD, PRESENCE_OPTIONAL), stateless_reset_token_(kSRST, PRESENCE_OPTIONAL), max_ack_delay_ms_(kMAD, PRESENCE_OPTIONAL), ack_delay_exponent_(kADE, PRESENCE_OPTIONAL), max_packet_size_(0, PRESENCE_OPTIONAL), - max_datagram_frame_size_(0, PRESENCE_OPTIONAL) { + max_datagram_frame_size_(0, PRESENCE_OPTIONAL), + active_connection_id_limit_(0, PRESENCE_OPTIONAL) { SetDefaults(); } @@ -450,7 +482,7 @@ bool QuicConfig::HasReceivedConnectionOptions() const { return connection_options_.HasReceivedValues(); } -QuicTagVector QuicConfig::ReceivedConnectionOptions() const { +const QuicTagVector& QuicConfig::ReceivedConnectionOptions() const { return connection_options_.GetReceivedValues(); } @@ -458,7 +490,7 @@ bool QuicConfig::HasSendConnectionOptions() const { return connection_options_.HasSendValues(); } -QuicTagVector QuicConfig::SendConnectionOptions() const { +const QuicTagVector& QuicConfig::SendConnectionOptions() const { return connection_options_.GetSendValues(); } @@ -493,26 +525,35 @@ bool QuicConfig::HasClientRequestedIndependentOption( ContainsQuicTag(client_connection_options_.GetSendValues(), tag)); } -void QuicConfig::SetIdleNetworkTimeout( - QuicTime::Delta max_idle_network_timeout, - QuicTime::Delta default_idle_network_timeout) { - idle_network_timeout_seconds_.set( - static_cast<uint32_t>(max_idle_network_timeout.ToSeconds()), - static_cast<uint32_t>(default_idle_network_timeout.ToSeconds())); -} +const QuicTagVector& QuicConfig::ClientRequestedIndependentOptions( + Perspective perspective) const { + static const QuicTagVector* no_options = new QuicTagVector; + if (perspective == Perspective::IS_SERVER) { + return HasReceivedConnectionOptions() ? ReceivedConnectionOptions() + : *no_options; + } -QuicTime::Delta QuicConfig::IdleNetworkTimeout() const { - return QuicTime::Delta::FromSeconds( - idle_network_timeout_seconds_.GetUint32()); + return client_connection_options_.HasSendValues() + ? client_connection_options_.GetSendValues() + : *no_options; } -// TODO(ianswett) Use this for silent close on mobile, or delete. -QUIC_UNUSED void QuicConfig::SetSilentClose(bool silent_close) { - silent_close_.set(silent_close ? 1 : 0, silent_close ? 1 : 0); +void QuicConfig::SetIdleNetworkTimeout(QuicTime::Delta idle_network_timeout) { + if (idle_network_timeout.ToMicroseconds() <= 0) { + QUIC_BUG << "Invalid idle network timeout " << idle_network_timeout; + return; + } + idle_timeout_to_send_ = idle_network_timeout; } -bool QuicConfig::SilentClose() const { - return silent_close_.GetUint32() > 0; +QuicTime::Delta QuicConfig::IdleNetworkTimeout() const { + // TODO(b/152032210) add a QUIC_BUG to ensure that is not called before we've + // received the peer's values. This is true in production code but not in all + // of our tests that use a fake QuicConfig. + if (!received_idle_timeout_.has_value()) { + return idle_timeout_to_send_; + } + return received_idle_timeout_.value(); } void QuicConfig::SetMaxBidirectionalStreamsToSend(uint32_t max_streams) { @@ -579,11 +620,11 @@ uint32_t QuicConfig::ReceivedAckDelayExponent() const { return ack_delay_exponent_.GetReceivedValue(); } -void QuicConfig::SetMaxPacketSizeToSend(uint32_t max_packet_size) { +void QuicConfig::SetMaxPacketSizeToSend(uint64_t max_packet_size) { max_packet_size_.SetSendValue(max_packet_size); } -uint32_t QuicConfig::GetMaxPacketSizeToSend() const { +uint64_t QuicConfig::GetMaxPacketSizeToSend() const { return max_packet_size_.GetSendValue(); } @@ -591,16 +632,16 @@ bool QuicConfig::HasReceivedMaxPacketSize() const { return max_packet_size_.HasReceivedValue(); } -uint32_t QuicConfig::ReceivedMaxPacketSize() const { +uint64_t QuicConfig::ReceivedMaxPacketSize() const { return max_packet_size_.GetReceivedValue(); } void QuicConfig::SetMaxDatagramFrameSizeToSend( - uint32_t max_datagram_frame_size) { + uint64_t max_datagram_frame_size) { max_datagram_frame_size_.SetSendValue(max_datagram_frame_size); } -uint32_t QuicConfig::GetMaxDatagramFrameSizeToSend() const { +uint64_t QuicConfig::GetMaxDatagramFrameSizeToSend() const { return max_datagram_frame_size_.GetSendValue(); } @@ -608,10 +649,27 @@ bool QuicConfig::HasReceivedMaxDatagramFrameSize() const { return max_datagram_frame_size_.HasReceivedValue(); } -uint32_t QuicConfig::ReceivedMaxDatagramFrameSize() const { +uint64_t QuicConfig::ReceivedMaxDatagramFrameSize() const { return max_datagram_frame_size_.GetReceivedValue(); } +void QuicConfig::SetActiveConnectionIdLimitToSend( + uint64_t active_connection_id_limit) { + active_connection_id_limit_.SetSendValue(active_connection_id_limit); +} + +uint64_t QuicConfig::GetActiveConnectionIdLimitToSend() const { + return active_connection_id_limit_.GetSendValue(); +} + +bool QuicConfig::HasReceivedActiveConnectionIdLimit() const { + return active_connection_id_limit_.HasReceivedValue(); +} + +uint64_t QuicConfig::ReceivedActiveConnectionIdLimit() const { + return active_connection_id_limit_.GetReceivedValue(); +} + bool QuicConfig::HasSetBytesForConnectionIdToSend() const { return bytes_for_connection_id_.HasSendValue(); } @@ -628,7 +686,7 @@ uint32_t QuicConfig::ReceivedBytesForConnectionId() const { return bytes_for_connection_id_.GetReceivedValue(); } -void QuicConfig::SetInitialRoundTripTimeUsToSend(uint32_t rtt) { +void QuicConfig::SetInitialRoundTripTimeUsToSend(uint64_t rtt) { initial_round_trip_time_us_.SetSendValue(rtt); } @@ -636,7 +694,7 @@ bool QuicConfig::HasReceivedInitialRoundTripTimeUs() const { return initial_round_trip_time_us_.HasReceivedValue(); } -uint32_t QuicConfig::ReceivedInitialRoundTripTimeUs() const { +uint64_t QuicConfig::ReceivedInitialRoundTripTimeUs() const { return initial_round_trip_time_us_.GetReceivedValue(); } @@ -644,12 +702,12 @@ bool QuicConfig::HasInitialRoundTripTimeUsToSend() const { return initial_round_trip_time_us_.HasSendValue(); } -uint32_t QuicConfig::GetInitialRoundTripTimeUsToSend() const { +uint64_t QuicConfig::GetInitialRoundTripTimeUsToSend() const { return initial_round_trip_time_us_.GetSendValue(); } void QuicConfig::SetInitialStreamFlowControlWindowToSend( - uint32_t window_bytes) { + uint64_t window_bytes) { if (window_bytes < kMinimumFlowControlSendWindow) { QUIC_BUG << "Initial stream flow control receive window (" << window_bytes << ") cannot be set lower than minimum (" @@ -659,7 +717,7 @@ void QuicConfig::SetInitialStreamFlowControlWindowToSend( initial_stream_flow_control_window_bytes_.SetSendValue(window_bytes); } -uint32_t QuicConfig::GetInitialStreamFlowControlWindowToSend() const { +uint64_t QuicConfig::GetInitialStreamFlowControlWindowToSend() const { return initial_stream_flow_control_window_bytes_.GetSendValue(); } @@ -667,17 +725,17 @@ bool QuicConfig::HasReceivedInitialStreamFlowControlWindowBytes() const { return initial_stream_flow_control_window_bytes_.HasReceivedValue(); } -uint32_t QuicConfig::ReceivedInitialStreamFlowControlWindowBytes() const { +uint64_t QuicConfig::ReceivedInitialStreamFlowControlWindowBytes() const { return initial_stream_flow_control_window_bytes_.GetReceivedValue(); } void QuicConfig::SetInitialMaxStreamDataBytesIncomingBidirectionalToSend( - uint32_t window_bytes) { + uint64_t window_bytes) { initial_max_stream_data_bytes_incoming_bidirectional_.SetSendValue( window_bytes); } -uint32_t QuicConfig::GetInitialMaxStreamDataBytesIncomingBidirectionalToSend() +uint64_t QuicConfig::GetInitialMaxStreamDataBytesIncomingBidirectionalToSend() const { if (initial_max_stream_data_bytes_incoming_bidirectional_.HasSendValue()) { return initial_max_stream_data_bytes_incoming_bidirectional_.GetSendValue(); @@ -691,19 +749,19 @@ bool QuicConfig::HasReceivedInitialMaxStreamDataBytesIncomingBidirectional() .HasReceivedValue(); } -uint32_t QuicConfig::ReceivedInitialMaxStreamDataBytesIncomingBidirectional() +uint64_t QuicConfig::ReceivedInitialMaxStreamDataBytesIncomingBidirectional() const { return initial_max_stream_data_bytes_incoming_bidirectional_ .GetReceivedValue(); } void QuicConfig::SetInitialMaxStreamDataBytesOutgoingBidirectionalToSend( - uint32_t window_bytes) { + uint64_t window_bytes) { initial_max_stream_data_bytes_outgoing_bidirectional_.SetSendValue( window_bytes); } -uint32_t QuicConfig::GetInitialMaxStreamDataBytesOutgoingBidirectionalToSend() +uint64_t QuicConfig::GetInitialMaxStreamDataBytesOutgoingBidirectionalToSend() const { if (initial_max_stream_data_bytes_outgoing_bidirectional_.HasSendValue()) { return initial_max_stream_data_bytes_outgoing_bidirectional_.GetSendValue(); @@ -717,18 +775,18 @@ bool QuicConfig::HasReceivedInitialMaxStreamDataBytesOutgoingBidirectional() .HasReceivedValue(); } -uint32_t QuicConfig::ReceivedInitialMaxStreamDataBytesOutgoingBidirectional() +uint64_t QuicConfig::ReceivedInitialMaxStreamDataBytesOutgoingBidirectional() const { return initial_max_stream_data_bytes_outgoing_bidirectional_ .GetReceivedValue(); } void QuicConfig::SetInitialMaxStreamDataBytesUnidirectionalToSend( - uint32_t window_bytes) { + uint64_t window_bytes) { initial_max_stream_data_bytes_unidirectional_.SetSendValue(window_bytes); } -uint32_t QuicConfig::GetInitialMaxStreamDataBytesUnidirectionalToSend() const { +uint64_t QuicConfig::GetInitialMaxStreamDataBytesUnidirectionalToSend() const { if (initial_max_stream_data_bytes_unidirectional_.HasSendValue()) { return initial_max_stream_data_bytes_unidirectional_.GetSendValue(); } @@ -739,12 +797,12 @@ bool QuicConfig::HasReceivedInitialMaxStreamDataBytesUnidirectional() const { return initial_max_stream_data_bytes_unidirectional_.HasReceivedValue(); } -uint32_t QuicConfig::ReceivedInitialMaxStreamDataBytesUnidirectional() const { +uint64_t QuicConfig::ReceivedInitialMaxStreamDataBytesUnidirectional() const { return initial_max_stream_data_bytes_unidirectional_.GetReceivedValue(); } void QuicConfig::SetInitialSessionFlowControlWindowToSend( - uint32_t window_bytes) { + uint64_t window_bytes) { if (window_bytes < kMinimumFlowControlSendWindow) { QUIC_BUG << "Initial session flow control receive window (" << window_bytes << ") cannot be set lower than default (" @@ -754,7 +812,7 @@ void QuicConfig::SetInitialSessionFlowControlWindowToSend( initial_session_flow_control_window_bytes_.SetSendValue(window_bytes); } -uint32_t QuicConfig::GetInitialSessionFlowControlWindowToSend() const { +uint64_t QuicConfig::GetInitialSessionFlowControlWindowToSend() const { return initial_session_flow_control_window_bytes_.GetSendValue(); } @@ -762,7 +820,7 @@ bool QuicConfig::HasReceivedInitialSessionFlowControlWindowBytes() const { return initial_session_flow_control_window_bytes_.HasReceivedValue(); } -uint32_t QuicConfig::ReceivedInitialSessionFlowControlWindowBytes() const { +uint64_t QuicConfig::ReceivedInitialSessionFlowControlWindowBytes() const { return initial_session_flow_control_window_bytes_.GetReceivedValue(); } @@ -774,25 +832,59 @@ bool QuicConfig::DisableConnectionMigration() const { return connection_migration_disabled_.HasReceivedValue(); } -void QuicConfig::SetAlternateServerAddressToSend( - const QuicSocketAddress& alternate_server_address) { - alternate_server_address_.SetSendValue(alternate_server_address); +void QuicConfig::SetIPv6AlternateServerAddressToSend( + const QuicSocketAddress& alternate_server_address_ipv6) { + if (!alternate_server_address_ipv6.host().IsIPv6()) { + QUIC_BUG << "Cannot use SetIPv6AlternateServerAddressToSend with " + << alternate_server_address_ipv6; + return; + } + alternate_server_address_ipv6_.SetSendValue(alternate_server_address_ipv6); +} + +bool QuicConfig::HasReceivedIPv6AlternateServerAddress() const { + return alternate_server_address_ipv6_.HasReceivedValue(); +} + +const QuicSocketAddress& QuicConfig::ReceivedIPv6AlternateServerAddress() + const { + return alternate_server_address_ipv6_.GetReceivedValue(); +} + +void QuicConfig::SetIPv4AlternateServerAddressToSend( + const QuicSocketAddress& alternate_server_address_ipv4) { + if (!alternate_server_address_ipv4.host().IsIPv4()) { + QUIC_BUG << "Cannot use SetIPv4AlternateServerAddressToSend with " + << alternate_server_address_ipv4; + return; + } + alternate_server_address_ipv4_.SetSendValue(alternate_server_address_ipv4); } -bool QuicConfig::HasReceivedAlternateServerAddress() const { - return alternate_server_address_.HasReceivedValue(); +bool QuicConfig::HasReceivedIPv4AlternateServerAddress() const { + return alternate_server_address_ipv4_.HasReceivedValue(); } -const QuicSocketAddress& QuicConfig::ReceivedAlternateServerAddress() const { - return alternate_server_address_.GetReceivedValue(); +const QuicSocketAddress& QuicConfig::ReceivedIPv4AlternateServerAddress() + const { + return alternate_server_address_ipv4_.GetReceivedValue(); } -void QuicConfig::SetSupportMaxHeaderListSize() { - support_max_header_list_size_.SetSendValue(1); +void QuicConfig::SetOriginalConnectionIdToSend( + const QuicConnectionId& original_connection_id) { + original_connection_id_to_send_ = original_connection_id; } -bool QuicConfig::SupportMaxHeaderListSize() const { - return support_max_header_list_size_.HasReceivedValue(); +bool QuicConfig::HasReceivedOriginalConnectionId() const { + return received_original_connection_id_.has_value(); +} + +QuicConnectionId QuicConfig::ReceivedOriginalConnectionId() const { + if (!HasReceivedOriginalConnectionId()) { + QUIC_BUG << "No received original connection ID"; + return EmptyQuicConnectionId(); + } + return received_original_connection_id_.value(); } void QuicConfig::SetStatelessResetTokenToSend( @@ -809,9 +901,7 @@ QuicUint128 QuicConfig::ReceivedStatelessResetToken() const { } bool QuicConfig::negotiated() const { - // TODO(ianswett): Add the negotiated parameters once and iterate over all - // of them in negotiated, ToHandshakeMessage, and ProcessPeerHello. - return idle_network_timeout_seconds_.negotiated(); + return negotiated_; } void QuicConfig::SetCreateSessionTagIndicators(QuicTagVector tags) { @@ -823,9 +913,7 @@ const QuicTagVector& QuicConfig::create_session_tag_indicators() const { } void QuicConfig::SetDefaults() { - idle_network_timeout_seconds_.set(kMaximumIdleTimeoutSecs, - kDefaultIdleTimeoutSecs); - silent_close_.set(1, 0); + SetIdleNetworkTimeout(QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs)); SetMaxBidirectionalStreamsToSend(kDefaultMaxStreamsPerConnection); SetMaxUnidirectionalStreamsToSend(kDefaultMaxStreamsPerConnection); max_time_before_crypto_handshake_ = @@ -837,7 +925,6 @@ void QuicConfig::SetDefaults() { SetInitialStreamFlowControlWindowToSend(kMinimumFlowControlSendWindow); SetInitialSessionFlowControlWindowToSend(kMinimumFlowControlSendWindow); SetMaxAckDelayToSendMs(kDefaultDelayedAckTimeMs); - SetSupportMaxHeaderListSize(); SetAckDelayExponentToSend(kDefaultAckDelayExponent); SetMaxPacketSizeToSend(kMaxIncomingPacketSize); SetMaxDatagramFrameSizeToSend(kMaxAcceptedDatagramFrameSize); @@ -846,8 +933,20 @@ void QuicConfig::SetDefaults() { void QuicConfig::ToHandshakeMessage( CryptoHandshakeMessage* out, QuicTransportVersion transport_version) const { - idle_network_timeout_seconds_.ToHandshakeMessage(out); - silent_close_.ToHandshakeMessage(out); + // Idle timeout has custom rules that are different from other values. + // We configure ourselves with the minumum value between the one sent and + // the one received. Additionally, when QUIC_CRYPTO is used, the server + // MUST send an idle timeout no greater than the idle timeout it received + // from the client. We therefore send the received value if it is lower. + QuicFixedUint32 idle_timeout_seconds(kICSL, PRESENCE_REQUIRED); + uint32_t idle_timeout_to_send_seconds = idle_timeout_to_send_.ToSeconds(); + if (received_idle_timeout_.has_value() && + received_idle_timeout_->ToSeconds() < idle_timeout_to_send_seconds) { + idle_timeout_to_send_seconds = received_idle_timeout_->ToSeconds(); + } + idle_timeout_seconds.SetSendValue(idle_timeout_to_send_seconds); + idle_timeout_seconds.ToHandshakeMessage(out); + // Do not need a version check here, max...bi... will encode // as "MIDS" -- the max initial dynamic streams tag -- if // doing some version other than IETF QUIC. @@ -866,8 +965,11 @@ void QuicConfig::ToHandshakeMessage( initial_session_flow_control_window_bytes_.ToHandshakeMessage(out); connection_migration_disabled_.ToHandshakeMessage(out); connection_options_.ToHandshakeMessage(out); - alternate_server_address_.ToHandshakeMessage(out); - support_max_header_list_size_.ToHandshakeMessage(out); + if (alternate_server_address_ipv6_.HasSendValue()) { + alternate_server_address_ipv6_.ToHandshakeMessage(out); + } else { + alternate_server_address_ipv4_.ToHandshakeMessage(out); + } stateless_reset_token_.ToHandshakeMessage(out); } @@ -879,12 +981,29 @@ QuicErrorCode QuicConfig::ProcessPeerHello( QuicErrorCode error = QUIC_NO_ERROR; if (error == QUIC_NO_ERROR) { - error = idle_network_timeout_seconds_.ProcessPeerHello( - peer_hello, hello_type, error_details); - } - if (error == QUIC_NO_ERROR) { - error = - silent_close_.ProcessPeerHello(peer_hello, hello_type, error_details); + // Idle timeout has custom rules that are different from other values. + // We configure ourselves with the minumum value between the one sent and + // the one received. Additionally, when QUIC_CRYPTO is used, the server + // MUST send an idle timeout no greater than the idle timeout it received + // from the client. + QuicFixedUint32 idle_timeout_seconds(kICSL, PRESENCE_REQUIRED); + error = idle_timeout_seconds.ProcessPeerHello(peer_hello, hello_type, + error_details); + if (error == QUIC_NO_ERROR) { + if (idle_timeout_seconds.GetReceivedValue() > + idle_timeout_to_send_.ToSeconds()) { + // The received value is higher than ours, ignore it if from the client + // and raise an error if from the server. + if (hello_type == SERVER) { + error = QUIC_INVALID_NEGOTIATED_VALUE; + *error_details = + "Invalid value received for " + QuicTagToString(kICSL); + } + } else { + received_idle_timeout_ = QuicTime::Delta::FromSeconds( + idle_timeout_seconds.GetReceivedValue()); + } + } } if (error == QUIC_NO_ERROR) { error = max_bidirectional_streams_.ProcessPeerHello(peer_hello, hello_type, @@ -919,12 +1038,18 @@ QuicErrorCode QuicConfig::ProcessPeerHello( error_details); } if (error == QUIC_NO_ERROR) { - error = alternate_server_address_.ProcessPeerHello(peer_hello, hello_type, - error_details); - } - if (error == QUIC_NO_ERROR) { - error = support_max_header_list_size_.ProcessPeerHello( - peer_hello, hello_type, error_details); + QuicFixedSocketAddress alternate_server_address(kASAD, PRESENCE_OPTIONAL); + error = alternate_server_address.ProcessPeerHello(peer_hello, hello_type, + error_details); + if (error == QUIC_NO_ERROR && alternate_server_address.HasReceivedValue()) { + const QuicSocketAddress& received_address = + alternate_server_address.GetReceivedValue(); + if (received_address.host().IsIPv6()) { + alternate_server_address_ipv6_.SetReceivedValue(received_address); + } else if (received_address.host().IsIPv4()) { + alternate_server_address_ipv4_.SetReceivedValue(received_address); + } + } } if (error == QUIC_NO_ERROR) { error = stateless_reset_token_.ProcessPeerHello(peer_hello, hello_type, @@ -941,12 +1066,19 @@ QuicErrorCode QuicConfig::ProcessPeerHello( error = ack_delay_exponent_.ProcessPeerHello(peer_hello, hello_type, error_details); } + if (error == QUIC_NO_ERROR) { + negotiated_ = true; + } return error; } bool QuicConfig::FillTransportParameters(TransportParameters* params) const { + if (original_connection_id_to_send_.has_value()) { + params->original_connection_id = original_connection_id_to_send_.value(); + } + params->idle_timeout_milliseconds.set_value( - idle_network_timeout_seconds_.GetMax() * kNumMillisPerSecond); + idle_timeout_to_send_.ToMilliseconds()); if (stateless_reset_token_.HasSendValue()) { QuicUint128 stateless_reset_token = stateless_reset_token_.GetSendValue(); @@ -985,26 +1117,50 @@ bool QuicConfig::FillTransportParameters(TransportParameters* params) const { connection_migration_disabled_.HasSendValue() && connection_migration_disabled_.GetSendValue() != 0; - if (alternate_server_address_.HasSendValue()) { + if (alternate_server_address_ipv6_.HasSendValue() || + alternate_server_address_ipv4_.HasSendValue()) { TransportParameters::PreferredAddress preferred_address; - QuicSocketAddress socket_address = alternate_server_address_.GetSendValue(); - if (socket_address.host().IsIPv6()) { - preferred_address.ipv6_socket_address = socket_address; - } else { - preferred_address.ipv4_socket_address = socket_address; + if (alternate_server_address_ipv6_.HasSendValue()) { + preferred_address.ipv6_socket_address = + alternate_server_address_ipv6_.GetSendValue(); + } + if (alternate_server_address_ipv4_.HasSendValue()) { + preferred_address.ipv4_socket_address = + alternate_server_address_ipv4_.GetSendValue(); } params->preferred_address = std::make_unique<TransportParameters::PreferredAddress>( preferred_address); } - if (!params->google_quic_params) { - params->google_quic_params = std::make_unique<CryptoHandshakeMessage>(); + if (active_connection_id_limit_.HasSendValue()) { + params->active_connection_id_limit.set_value( + active_connection_id_limit_.GetSendValue()); } - silent_close_.ToHandshakeMessage(params->google_quic_params.get()); - initial_round_trip_time_us_.ToHandshakeMessage( - params->google_quic_params.get()); - connection_options_.ToHandshakeMessage(params->google_quic_params.get()); + + if (GetQuicRestartFlag(quic_google_transport_param_send_new)) { + QUIC_RESTART_FLAG_COUNT_N(quic_google_transport_param_send_new, 1, 3); + if (initial_round_trip_time_us_.HasSendValue()) { + params->initial_round_trip_time_us.set_value( + initial_round_trip_time_us_.GetSendValue()); + } + if (connection_options_.HasSendValues() && + !connection_options_.GetSendValues().empty()) { + params->google_connection_options = connection_options_.GetSendValues(); + } + } + + if (!GetQuicRestartFlag(quic_google_transport_param_omit_old)) { + if (!params->google_quic_params) { + params->google_quic_params = std::make_unique<CryptoHandshakeMessage>(); + } + initial_round_trip_time_us_.ToHandshakeMessage( + params->google_quic_params.get()); + connection_options_.ToHandshakeMessage(params->google_quic_params.get()); + } else { + QUIC_RESTART_FLAG_COUNT_N(quic_google_transport_param_omit_old, 1, 3); + } + params->custom_parameters = custom_transport_parameters_to_send_; return true; @@ -1013,25 +1169,23 @@ bool QuicConfig::FillTransportParameters(TransportParameters* params) const { QuicErrorCode QuicConfig::ProcessTransportParameters( const TransportParameters& params, HelloType hello_type, + bool is_resumption, std::string* error_details) { - // Intentionally round down to probe too often rather than not often enough. - uint64_t idle_timeout_seconds = - params.idle_timeout_milliseconds.value() / kNumMillisPerSecond; - // An idle timeout of zero indicates it is disabled (in other words, it is - // set to infinity). When the idle timeout is very high, we set it to our - // preferred maximum and still probe that often. - if (idle_timeout_seconds > idle_network_timeout_seconds_.GetMax() || - idle_timeout_seconds == 0) { - idle_timeout_seconds = idle_network_timeout_seconds_.GetMax(); - } - QuicErrorCode error = idle_network_timeout_seconds_.ReceiveValue( - idle_timeout_seconds, hello_type, error_details); - if (error != QUIC_NO_ERROR) { - DCHECK(!error_details->empty()); - return error; - } - - if (!params.stateless_reset_token.empty()) { + if (!is_resumption && params.original_connection_id.has_value()) { + received_original_connection_id_ = params.original_connection_id.value(); + } + + if (params.idle_timeout_milliseconds.value() > 0 && + params.idle_timeout_milliseconds.value() < + static_cast<uint64_t>(idle_timeout_to_send_.ToMilliseconds())) { + // An idle timeout of zero indicates it is disabled. + // We also ignore values higher than ours which will cause us to use the + // smallest value between ours and our peer's. + received_idle_timeout_ = QuicTime::Delta::FromMilliseconds( + params.idle_timeout_milliseconds.value()); + } + + if (!is_resumption && !params.stateless_reset_token.empty()) { QuicUint128 stateless_reset_token; if (params.stateless_reset_token.size() != sizeof(stateless_reset_token)) { QUIC_BUG << "Bad stateless reset token length " @@ -1051,12 +1205,13 @@ QuicErrorCode QuicConfig::ProcessTransportParameters( if (params.max_datagram_frame_size.IsValid()) { max_datagram_frame_size_.SetReceivedValue( params.max_datagram_frame_size.value()); - // TODO(dschinazi) act on this. } initial_session_flow_control_window_bytes_.SetReceivedValue( - std::min<uint64_t>(params.initial_max_data.value(), - std::numeric_limits<uint32_t>::max())); + params.initial_max_data.value()); + + // IETF QUIC specifies stream IDs and stream counts as 62-bit integers but + // our implementation uses uint32_t to represent them to save memory. max_bidirectional_streams_.SetReceivedValue( std::min<uint64_t>(params.initial_max_streams_bidi.value(), std::numeric_limits<uint32_t>::max())); @@ -1071,61 +1226,79 @@ QuicErrorCode QuicConfig::ProcessTransportParameters( // received transport parameters, so a local stream is one initiated by our // peer, which means an incoming stream. initial_max_stream_data_bytes_incoming_bidirectional_.SetReceivedValue( - std::min<uint64_t>(params.initial_max_stream_data_bidi_local.value(), - std::numeric_limits<uint32_t>::max())); + params.initial_max_stream_data_bidi_local.value()); initial_max_stream_data_bytes_outgoing_bidirectional_.SetReceivedValue( - std::min<uint64_t>(params.initial_max_stream_data_bidi_remote.value(), - std::numeric_limits<uint32_t>::max())); + params.initial_max_stream_data_bidi_remote.value()); initial_max_stream_data_bytes_unidirectional_.SetReceivedValue( - std::min<uint64_t>(params.initial_max_stream_data_uni.value(), - std::numeric_limits<uint32_t>::max())); + params.initial_max_stream_data_uni.value()); - if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_negotiate_ack_delay_time, 4, 4); - max_ack_delay_ms_.SetReceivedValue(std::min<uint32_t>( - params.max_ack_delay.value(), std::numeric_limits<uint32_t>::max())); - } - if (params.ack_delay_exponent.IsValid()) { - ack_delay_exponent_.SetReceivedValue(params.ack_delay_exponent.value()); + if (!is_resumption) { + if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_negotiate_ack_delay_time, 4, 4); + max_ack_delay_ms_.SetReceivedValue(params.max_ack_delay.value()); + } + if (params.ack_delay_exponent.IsValid()) { + ack_delay_exponent_.SetReceivedValue(params.ack_delay_exponent.value()); + } + if (params.preferred_address != nullptr) { + if (params.preferred_address->ipv6_socket_address.port() != 0) { + alternate_server_address_ipv6_.SetReceivedValue( + params.preferred_address->ipv6_socket_address); + } + if (params.preferred_address->ipv4_socket_address.port() != 0) { + alternate_server_address_ipv4_.SetReceivedValue( + params.preferred_address->ipv4_socket_address); + } + } } + if (params.disable_migration) { connection_migration_disabled_.SetReceivedValue(1u); } - if (params.preferred_address != nullptr) { - if (params.preferred_address->ipv6_socket_address.port() != 0) { - alternate_server_address_.SetReceivedValue( - params.preferred_address->ipv6_socket_address); - } else if (params.preferred_address->ipv4_socket_address.port() != 0) { - alternate_server_address_.SetReceivedValue( - params.preferred_address->ipv4_socket_address); - } - } + active_connection_id_limit_.SetReceivedValue( + params.active_connection_id_limit.value()); - const CryptoHandshakeMessage* peer_params = params.google_quic_params.get(); - if (peer_params != nullptr) { - error = - silent_close_.ProcessPeerHello(*peer_params, hello_type, error_details); - if (error != QUIC_NO_ERROR) { - DCHECK(!error_details->empty()); - return error; + bool google_params_already_parsed = false; + if (GetQuicRestartFlag(quic_google_transport_param_send_new)) { + QUIC_RESTART_FLAG_COUNT_N(quic_google_transport_param_send_new, 2, 3); + if (params.initial_round_trip_time_us.value() > 0) { + google_params_already_parsed = true; + initial_round_trip_time_us_.SetReceivedValue( + params.initial_round_trip_time_us.value()); } - error = initial_round_trip_time_us_.ProcessPeerHello( - *peer_params, hello_type, error_details); - if (error != QUIC_NO_ERROR) { - DCHECK(!error_details->empty()); - return error; + if (params.google_connection_options.has_value()) { + google_params_already_parsed = true; + connection_options_.SetReceivedValues( + params.google_connection_options.value()); } - error = connection_options_.ProcessPeerHello(*peer_params, hello_type, - error_details); - if (error != QUIC_NO_ERROR) { - DCHECK(!error_details->empty()); - return error; + } + + if (!GetQuicRestartFlag(quic_google_transport_param_omit_old)) { + const CryptoHandshakeMessage* peer_params = params.google_quic_params.get(); + if (peer_params != nullptr && !google_params_already_parsed) { + QuicErrorCode error = initial_round_trip_time_us_.ProcessPeerHello( + *peer_params, hello_type, error_details); + if (error != QUIC_NO_ERROR) { + DCHECK(!error_details->empty()); + return error; + } + error = connection_options_.ProcessPeerHello(*peer_params, hello_type, + error_details); + if (error != QUIC_NO_ERROR) { + DCHECK(!error_details->empty()); + return error; + } } + } else { + QUIC_RESTART_FLAG_COUNT_N(quic_google_transport_param_omit_old, 2, 3); } received_custom_transport_parameters_ = params.custom_parameters; + if (!is_resumption) { + negotiated_ = true; + } *error_details = ""; return QUIC_NO_ERROR; } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_config.h b/chromium/net/third_party/quiche/src/quic/core/quic_config.h index 95a26cb0d8f..4d2bacce383 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_config.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_config.h @@ -10,10 +10,12 @@ #include <string> #include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h" +#include "net/third_party/quiche/src/quic/core/quic_connection_id.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/core/quic_time.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" #include "net/third_party/quiche/src/quic/platform/api/quic_uint128.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_optional.h" namespace quic { @@ -62,86 +64,62 @@ class QUIC_EXPORT_PRIVATE QuicConfigValue { const QuicConfigPresence presence_; }; -class QUIC_EXPORT_PRIVATE QuicNegotiableValue : public QuicConfigValue { +// Stores uint32_t from CHLO or SHLO messages that are not negotiated. +class QUIC_EXPORT_PRIVATE QuicFixedUint32 : public QuicConfigValue { public: - QuicNegotiableValue(QuicTag tag, QuicConfigPresence presence); - ~QuicNegotiableValue() override; - - bool negotiated() const { return negotiated_; } + QuicFixedUint32(QuicTag name, QuicConfigPresence presence); + ~QuicFixedUint32() override; - protected: - void set_negotiated(bool negotiated) { negotiated_ = negotiated; } + bool HasSendValue() const; - private: - bool negotiated_; -}; + uint32_t GetSendValue() const; -class QUIC_EXPORT_PRIVATE QuicNegotiableUint32 : public QuicNegotiableValue { - // TODO(fayang): some negotiated values use uint32 as bool (e.g., silent - // close). Consider adding a QuicNegotiableBool type. - public: - // Default and max values default to 0. - QuicNegotiableUint32(QuicTag name, QuicConfigPresence presence); - ~QuicNegotiableUint32() override; + void SetSendValue(uint32_t value); - // Sets the maximum possible value that can be achieved after negotiation and - // also the default values to be assumed if PRESENCE_OPTIONAL and the *HLO msg - // doesn't contain a value corresponding to |name_|. |max| is serialised via - // ToHandshakeMessage call if |negotiated_| is false. - void set(uint32_t max, uint32_t default_value); + bool HasReceivedValue() const; - // Returns the value negotiated if |negotiated_| is true, otherwise returns - // default_value_ (used to set default values before negotiation finishes). - uint32_t GetUint32() const; + uint32_t GetReceivedValue() const; - // Returns the maximum value negotiable. - uint32_t GetMax() const; + void SetReceivedValue(uint32_t value); - // Serialises |name_| and value to |out|. If |negotiated_| is true then - // |negotiated_value_| is serialised, otherwise |max_value_| is serialised. + // If has_send_value is true, serialises |tag_| and |send_value_| to |out|. void ToHandshakeMessage(CryptoHandshakeMessage* out) const override; - // Processes the corresponding value from |peer_hello| and if present calls - // ReceiveValue with it. If the corresponding value is missing and - // PRESENCE_OPTIONAL then |negotiated_value_| is set to |default_value_|. + // Sets |value_| to the corresponding value from |peer_hello_| if it exists. QuicErrorCode ProcessPeerHello(const CryptoHandshakeMessage& peer_hello, HelloType hello_type, std::string* error_details) override; - // Takes a value |value| parsed from a handshake message (whether a TLS - // ClientHello/ServerHello or a CryptoHandshakeMessage) whose sender was - // |hello_type|, and sets |negotiated_value_| to the minimum of |value| and - // |max_value_|. On success this function returns QUIC_NO_ERROR; if there is - // an error, details are put in |*error_details|. - QuicErrorCode ReceiveValue(uint32_t value, - HelloType hello_type, - std::string* error_details); - private: - uint32_t max_value_; - uint32_t default_value_; - uint32_t negotiated_value_; + uint32_t send_value_; + bool has_send_value_; + uint32_t receive_value_; + bool has_receive_value_; }; -// Stores uint32_t from CHLO or SHLO messages that are not negotiated. -class QUIC_EXPORT_PRIVATE QuicFixedUint32 : public QuicConfigValue { +// Stores 62bit numbers from handshake messages that unilaterally shared by each +// endpoint. IMPORTANT: these are serialized as 32-bit unsigned integers when +// using QUIC_CRYPTO versions and CryptoHandshakeMessage. +class QUIC_EXPORT_PRIVATE QuicFixedUint62 : public QuicConfigValue { public: - QuicFixedUint32(QuicTag name, QuicConfigPresence presence); - ~QuicFixedUint32() override; + QuicFixedUint62(QuicTag name, QuicConfigPresence presence); + ~QuicFixedUint62() override; bool HasSendValue() const; - uint32_t GetSendValue() const; + uint64_t GetSendValue() const; - void SetSendValue(uint32_t value); + void SetSendValue(uint64_t value); bool HasReceivedValue() const; - uint32_t GetReceivedValue() const; + uint64_t GetReceivedValue() const; - void SetReceivedValue(uint32_t value); + void SetReceivedValue(uint64_t value); // If has_send_value is true, serialises |tag_| and |send_value_| to |out|. + // IMPORTANT: this method serializes |send_value_| as an unsigned 32bit + // integer. void ToHandshakeMessage(CryptoHandshakeMessage* out) const override; // Sets |value_| to the corresponding value from |peer_hello_| if it exists. @@ -150,9 +128,9 @@ class QUIC_EXPORT_PRIVATE QuicFixedUint32 : public QuicConfigValue { std::string* error_details) override; private: - uint32_t send_value_; + uint64_t send_value_; bool has_send_value_; - uint32_t receive_value_; + uint64_t receive_value_; bool has_receive_value_; }; @@ -198,13 +176,13 @@ class QUIC_EXPORT_PRIVATE QuicFixedTagVector : public QuicConfigValue { bool HasSendValues() const; - QuicTagVector GetSendValues() const; + const QuicTagVector& GetSendValues() const; void SetSendValues(const QuicTagVector& values); bool HasReceivedValues() const; - QuicTagVector GetReceivedValues() const; + const QuicTagVector& GetReceivedValues() const; void SetReceivedValues(const QuicTagVector& values); @@ -275,11 +253,11 @@ class QUIC_EXPORT_PRIVATE QuicConfig { // function does nothing and returns false. bool SetInitialReceivedConnectionOptions(const QuicTagVector& tags); - QuicTagVector ReceivedConnectionOptions() const; + const QuicTagVector& ReceivedConnectionOptions() const; bool HasSendConnectionOptions() const; - QuicTagVector SendConnectionOptions() const; + const QuicTagVector& SendConnectionOptions() const; // Returns true if the client is sending or the server has received a // connection option. @@ -296,14 +274,12 @@ class QUIC_EXPORT_PRIVATE QuicConfig { bool HasClientRequestedIndependentOption(QuicTag tag, Perspective perspective) const; - void SetIdleNetworkTimeout(QuicTime::Delta max_idle_network_timeout, - QuicTime::Delta default_idle_network_timeout); - - QuicTime::Delta IdleNetworkTimeout() const; + const QuicTagVector& ClientRequestedIndependentOptions( + Perspective perspective) const; - void SetSilentClose(bool silent_close); + void SetIdleNetworkTimeout(QuicTime::Delta idle_network_timeout); - bool SilentClose() const; + QuicTime::Delta IdleNetworkTimeout() const; // Sets the max bidirectional stream count that this endpoint supports. void SetMaxBidirectionalStreamsToSend(uint32_t max_streams); @@ -340,10 +316,6 @@ class QUIC_EXPORT_PRIVATE QuicConfig { return max_idle_time_before_crypto_handshake_; } - QuicNegotiableUint32 idle_network_timeout_seconds() const { - return idle_network_timeout_seconds_; - } - void set_max_undecryptable_packets(size_t max_undecryptable_packets) { max_undecryptable_packets_ = max_undecryptable_packets; } @@ -352,89 +324,85 @@ class QUIC_EXPORT_PRIVATE QuicConfig { return max_undecryptable_packets_; } + // Peer's connection id length, in bytes. Only used in Q043 and Q046. bool HasSetBytesForConnectionIdToSend() const; - - // Sets the peer's connection id length, in bytes. void SetBytesForConnectionIdToSend(uint32_t bytes); - bool HasReceivedBytesForConnectionId() const; - uint32_t ReceivedBytesForConnectionId() const; - // Sets an estimated initial round trip time in us. - void SetInitialRoundTripTimeUsToSend(uint32_t rtt_us); - + // Estimated initial round trip time in us. + void SetInitialRoundTripTimeUsToSend(uint64_t rtt_us); bool HasReceivedInitialRoundTripTimeUs() const; - - uint32_t ReceivedInitialRoundTripTimeUs() const; - + uint64_t ReceivedInitialRoundTripTimeUs() const; bool HasInitialRoundTripTimeUsToSend() const; - - uint32_t GetInitialRoundTripTimeUsToSend() const; + uint64_t GetInitialRoundTripTimeUsToSend() const; // Sets an initial stream flow control window size to transmit to the peer. - void SetInitialStreamFlowControlWindowToSend(uint32_t window_bytes); - uint32_t GetInitialStreamFlowControlWindowToSend() const; + void SetInitialStreamFlowControlWindowToSend(uint64_t window_bytes); + uint64_t GetInitialStreamFlowControlWindowToSend() const; bool HasReceivedInitialStreamFlowControlWindowBytes() const; - uint32_t ReceivedInitialStreamFlowControlWindowBytes() const; + uint64_t ReceivedInitialStreamFlowControlWindowBytes() const; // Specifies the initial flow control window (max stream data) for // incoming bidirectional streams. Incoming means streams initiated by our // peer. If not set, GetInitialMaxStreamDataBytesIncomingBidirectionalToSend // returns the value passed to SetInitialStreamFlowControlWindowToSend. void SetInitialMaxStreamDataBytesIncomingBidirectionalToSend( - uint32_t window_bytes); - uint32_t GetInitialMaxStreamDataBytesIncomingBidirectionalToSend() const; + uint64_t window_bytes); + uint64_t GetInitialMaxStreamDataBytesIncomingBidirectionalToSend() const; bool HasReceivedInitialMaxStreamDataBytesIncomingBidirectional() const; - uint32_t ReceivedInitialMaxStreamDataBytesIncomingBidirectional() const; + uint64_t ReceivedInitialMaxStreamDataBytesIncomingBidirectional() const; // Specifies the initial flow control window (max stream data) for // outgoing bidirectional streams. Outgoing means streams initiated by us. // If not set, GetInitialMaxStreamDataBytesOutgoingBidirectionalToSend // returns the value passed to SetInitialStreamFlowControlWindowToSend. void SetInitialMaxStreamDataBytesOutgoingBidirectionalToSend( - uint32_t window_bytes); - uint32_t GetInitialMaxStreamDataBytesOutgoingBidirectionalToSend() const; + uint64_t window_bytes); + uint64_t GetInitialMaxStreamDataBytesOutgoingBidirectionalToSend() const; bool HasReceivedInitialMaxStreamDataBytesOutgoingBidirectional() const; - uint32_t ReceivedInitialMaxStreamDataBytesOutgoingBidirectional() const; + uint64_t ReceivedInitialMaxStreamDataBytesOutgoingBidirectional() const; // Specifies the initial flow control window (max stream data) for // unidirectional streams. If not set, // GetInitialMaxStreamDataBytesUnidirectionalToSend returns the value passed // to SetInitialStreamFlowControlWindowToSend. - void SetInitialMaxStreamDataBytesUnidirectionalToSend(uint32_t window_bytes); - uint32_t GetInitialMaxStreamDataBytesUnidirectionalToSend() const; + void SetInitialMaxStreamDataBytesUnidirectionalToSend(uint64_t window_bytes); + uint64_t GetInitialMaxStreamDataBytesUnidirectionalToSend() const; bool HasReceivedInitialMaxStreamDataBytesUnidirectional() const; - uint32_t ReceivedInitialMaxStreamDataBytesUnidirectional() const; + uint64_t ReceivedInitialMaxStreamDataBytesUnidirectional() const; // Sets an initial session flow control window size to transmit to the peer. - void SetInitialSessionFlowControlWindowToSend(uint32_t window_bytes); - - uint32_t GetInitialSessionFlowControlWindowToSend() const; - + void SetInitialSessionFlowControlWindowToSend(uint64_t window_bytes); + uint64_t GetInitialSessionFlowControlWindowToSend() const; bool HasReceivedInitialSessionFlowControlWindowBytes() const; + uint64_t ReceivedInitialSessionFlowControlWindowBytes() const; - uint32_t ReceivedInitialSessionFlowControlWindowBytes() const; - + // Disable connection migration. void SetDisableConnectionMigration(); - bool DisableConnectionMigration() const; - void SetAlternateServerAddressToSend( - const QuicSocketAddress& alternate_server_address); - - bool HasReceivedAlternateServerAddress() const; - - const QuicSocketAddress& ReceivedAlternateServerAddress() const; - - void SetSupportMaxHeaderListSize(); - - bool SupportMaxHeaderListSize() const; - + // IPv6 alternate server address. + void SetIPv6AlternateServerAddressToSend( + const QuicSocketAddress& alternate_server_address_ipv6); + bool HasReceivedIPv6AlternateServerAddress() const; + const QuicSocketAddress& ReceivedIPv6AlternateServerAddress() const; + + // IPv4 alternate server address. + void SetIPv4AlternateServerAddressToSend( + const QuicSocketAddress& alternate_server_address_ipv4); + bool HasReceivedIPv4AlternateServerAddress() const; + const QuicSocketAddress& ReceivedIPv4AlternateServerAddress() const; + + // Original connection ID. + void SetOriginalConnectionIdToSend( + const QuicConnectionId& original_connection_id); + bool HasReceivedOriginalConnectionId() const; + QuicConnectionId ReceivedOriginalConnectionId() const; + + // Stateless reset token. void SetStatelessResetTokenToSend(QuicUint128 stateless_reset_token); - bool HasReceivedStatelessResetToken() const; - QuicUint128 ReceivedStatelessResetToken() const; // Manage the IETF QUIC Max ACK Delay transport parameter. @@ -453,16 +421,22 @@ class QUIC_EXPORT_PRIVATE QuicConfig { uint32_t ReceivedAckDelayExponent() const; // IETF QUIC max_packet_size transport parameter. - void SetMaxPacketSizeToSend(uint32_t max_packet_size); - uint32_t GetMaxPacketSizeToSend() const; + void SetMaxPacketSizeToSend(uint64_t max_packet_size); + uint64_t GetMaxPacketSizeToSend() const; bool HasReceivedMaxPacketSize() const; - uint32_t ReceivedMaxPacketSize() const; + uint64_t ReceivedMaxPacketSize() const; // IETF QUIC max_datagram_frame_size transport parameter. - void SetMaxDatagramFrameSizeToSend(uint32_t max_datagram_frame_size); - uint32_t GetMaxDatagramFrameSizeToSend() const; + void SetMaxDatagramFrameSizeToSend(uint64_t max_datagram_frame_size); + uint64_t GetMaxDatagramFrameSizeToSend() const; bool HasReceivedMaxDatagramFrameSize() const; - uint32_t ReceivedMaxDatagramFrameSize() const; + uint64_t ReceivedMaxDatagramFrameSize() const; + + // IETF QUIC active_connection_id_limit transport parameter. + void SetActiveConnectionIdLimitToSend(uint64_t active_connection_id_limit); + uint64_t GetActiveConnectionIdLimitToSend() const; + bool HasReceivedActiveConnectionIdLimit() const; + uint64_t ReceivedActiveConnectionIdLimit() const; bool negotiated() const; @@ -488,10 +462,13 @@ class QUIC_EXPORT_PRIVATE QuicConfig { // ProcessTransportParameters reads from |params| which was received from a // peer operating as a |hello_type|. It processes values for ICSL, MIDS, CFCW, - // and SFCW and sets the corresponding members of this QuicConfig. On failure, - // it returns a QuicErrorCode and puts a detailed error in |*error_details|. + // and SFCW and sets the corresponding members of this QuicConfig. + // If |is_resumption|, some configs will not be processed. + // On failure, it returns a QuicErrorCode and puts a detailed error in + // |*error_details|. QuicErrorCode ProcessTransportParameters(const TransportParameters& params, HelloType hello_type, + bool is_resumption, std::string* error_details); TransportParameters::ParameterMap& custom_transport_parameters_to_send() { @@ -508,6 +485,9 @@ class QUIC_EXPORT_PRIVATE QuicConfig { // SetDefaults sets the members to sensible, default values. void SetDefaults(); + // Whether we've received the peer's config. + bool negotiated_; + // Configurations options that are not negotiated. // Maximum time the session can be alive before crypto handshake is finished. QuicTime::Delta max_time_before_crypto_handshake_; @@ -521,10 +501,12 @@ class QUIC_EXPORT_PRIVATE QuicConfig { QuicFixedTagVector connection_options_; // Connection options which only affect the client side. QuicFixedTagVector client_connection_options_; - // Idle network timeout in seconds. - QuicNegotiableUint32 idle_network_timeout_seconds_; - // Whether to use silent close. Defaults to 0 (false) and is otherwise true. - QuicNegotiableUint32 silent_close_; + // Idle network timeout. + // Uses the max_idle_timeout transport parameter in IETF QUIC. + // Note that received_idle_timeout_ is only populated if we receive the + // peer's value, which isn't guaranteed in IETF QUIC as sending is optional. + QuicTime::Delta idle_timeout_to_send_; + quiche::QuicheOptional<QuicTime::Delta> received_idle_timeout_; // Maximum number of dynamic streams that a Google QUIC connection // can support or the maximum number of bidirectional streams that // an IETF QUIC connection can support. @@ -532,6 +514,7 @@ class QUIC_EXPORT_PRIVATE QuicConfig { // advertising. // The ReceivedValue is the limit on locally-created streams that // the peer advertised. + // Uses the initial_max_streams_bidi transport parameter in IETF QUIC. QuicFixedUint32 max_bidirectional_streams_; // Maximum number of unidirectional streams that the connection can // support. @@ -539,36 +522,46 @@ class QUIC_EXPORT_PRIVATE QuicConfig { // advertising. // The ReceivedValue is the limit on locally-created streams that the peer // advertised. + // Uses the initial_max_streams_uni transport parameter in IETF QUIC. QuicFixedUint32 max_unidirectional_streams_; - // The number of bytes required for the connection ID. + // The number of bytes required for the connection ID. This is only used in + // the legacy header format used only by Q043 at this point. QuicFixedUint32 bytes_for_connection_id_; // Initial round trip time estimate in microseconds. - QuicFixedUint32 initial_round_trip_time_us_; + QuicFixedUint62 initial_round_trip_time_us_; // Initial IETF QUIC stream flow control receive windows in bytes. // Incoming bidirectional streams. - QuicFixedUint32 initial_max_stream_data_bytes_incoming_bidirectional_; + // Uses the initial_max_stream_data_bidi_{local,remote} transport parameter + // in IETF QUIC, depending on whether we're sending or receiving. + QuicFixedUint62 initial_max_stream_data_bytes_incoming_bidirectional_; // Outgoing bidirectional streams. - QuicFixedUint32 initial_max_stream_data_bytes_outgoing_bidirectional_; + // Uses the initial_max_stream_data_bidi_{local,remote} transport parameter + // in IETF QUIC, depending on whether we're sending or receiving. + QuicFixedUint62 initial_max_stream_data_bytes_outgoing_bidirectional_; // Unidirectional streams. - QuicFixedUint32 initial_max_stream_data_bytes_unidirectional_; + // Uses the initial_max_stream_data_uni transport parameter in IETF QUIC. + QuicFixedUint62 initial_max_stream_data_bytes_unidirectional_; // Initial Google QUIC stream flow control receive window in bytes. - QuicFixedUint32 initial_stream_flow_control_window_bytes_; + QuicFixedUint62 initial_stream_flow_control_window_bytes_; // Initial session flow control receive window in bytes. - QuicFixedUint32 initial_session_flow_control_window_bytes_; + // Uses the initial_max_data transport parameter in IETF QUIC. + QuicFixedUint62 initial_session_flow_control_window_bytes_; - // Whether tell peer not to attempt connection migration. + // Whether active connection migration is allowed. + // Uses the disable_active_migration transport parameter in IETF QUIC. QuicFixedUint32 connection_migration_disabled_; - // An alternate server address the client could connect to. - QuicFixedSocketAddress alternate_server_address_; - - // Whether support HTTP/2 SETTINGS_MAX_HEADER_LIST_SIZE SETTINGS frame. - QuicFixedUint32 support_max_header_list_size_; + // Alternate server addresses the client could connect to. + // Uses the preferred_address transport parameter in IETF QUIC. + // Note that when QUIC_CRYPTO is in use, only one of the addresses is sent. + QuicFixedSocketAddress alternate_server_address_ipv6_; + QuicFixedSocketAddress alternate_server_address_ipv4_; // Stateless reset token used in IETF public reset packet. + // Uses the stateless_reset_token transport parameter in IETF QUIC. QuicFixedUint128 stateless_reset_token_; // List of QuicTags whose presence immediately causes the session to @@ -579,20 +572,32 @@ class QUIC_EXPORT_PRIVATE QuicConfig { // Maximum ack delay. The sent value is the value used on this node. // The received value is the value received from the peer and used by // the peer. + // Uses the max_ack_delay transport parameter in IETF QUIC. QuicFixedUint32 max_ack_delay_ms_; - // ack_delay_exponent parameter negotiated in IETF QUIC transport - // parameter negotiation. The sent exponent is the exponent that this - // node uses when serializing an ACK frame (and the peer should use when - // deserializing the frame); the received exponent is the value the peer uses - // to serialize frames and this node uses to deserialize them. + // The sent exponent is the exponent that this node uses when serializing an + // ACK frame (and the peer should use when deserializing the frame); + // the received exponent is the value the peer uses to serialize frames and + // this node uses to deserialize them. + // Uses the ack_delay_exponent transport parameter in IETF QUIC. QuicFixedUint32 ack_delay_exponent_; - // max_packet_size IETF QUIC transport parameter. - QuicFixedUint32 max_packet_size_; + // Maximum packet size in bytes. + // Uses the max_packet_size transport parameter in IETF QUIC. + QuicFixedUint62 max_packet_size_; + + // Maximum DATAGRAM/MESSAGE frame size in bytes. + // Uses the max_datagram_frame_size transport parameter in IETF QUIC. + QuicFixedUint62 max_datagram_frame_size_; + + // Maximum number of connection IDs from the peer. + // Uses the active_connection_id_limit transport parameter in IETF QUIC. + QuicFixedUint62 active_connection_id_limit_; - // max_datagram_frame_size IETF QUIC transport parameter. - QuicFixedUint32 max_datagram_frame_size_; + // Sent by the server when it has previously sent a RETRY packet. + // Uses the original_connection_id transport parameter in IETF QUIC. + quiche::QuicheOptional<QuicConnectionId> original_connection_id_to_send_; + quiche::QuicheOptional<QuicConnectionId> received_original_connection_id_; // Custom transport parameters that can be sent and received in the TLS // handshake. diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_config_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_config_test.cc index 69ce78de0fd..4aa10ef40b0 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_config_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_config_test.cc @@ -12,6 +12,7 @@ #include "net/third_party/quiche/src/quic/core/quic_time.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/platform/api/quic_uint128.h" #include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h" @@ -21,18 +22,36 @@ namespace quic { namespace test { namespace { -const uint32_t kMaxPacketSizeForTest = 1234; -const uint32_t kMaxDatagramFrameSizeForTest = 1333; +constexpr uint32_t kMaxPacketSizeForTest = 1234; +constexpr uint32_t kMaxDatagramFrameSizeForTest = 1333; +constexpr uint8_t kFakeStatelessResetTokenData[16] = { + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F}; +constexpr uint64_t kFakeAckDelayExponent = 10; +constexpr uint64_t kFakeMaxAckDelay = 51; +constexpr uint64_t kFakeActiveConnectionIdLimit = 52; + +// TODO(b/153726130): Consider merging this with methods in +// transport_parameters_test.cc. +std::vector<uint8_t> CreateFakeStatelessResetToken() { + return std::vector<uint8_t>( + kFakeStatelessResetTokenData, + kFakeStatelessResetTokenData + sizeof(kFakeStatelessResetTokenData)); +} + +class QuicConfigTest : public QuicTestWithParam<ParsedQuicVersion> { + public: + QuicConfigTest() : version_(GetParam()) {} -class QuicConfigTest : public QuicTestWithParam<QuicTransportVersion> { protected: + ParsedQuicVersion version_; QuicConfig config_; }; // Run all tests with all versions of QUIC. INSTANTIATE_TEST_SUITE_P(QuicConfigTests, QuicConfigTest, - ::testing::ValuesIn(AllSupportedTransportVersions()), + ::testing::ValuesIn(AllSupportedVersions()), ::testing::PrintToStringParamName()); TEST_P(QuicConfigTest, SetDefaults) { @@ -85,14 +104,17 @@ TEST_P(QuicConfigTest, AutoSetIetfFlowControl) { } TEST_P(QuicConfigTest, ToHandshakeMessage) { + if (version_.UsesTls()) { + // CryptoHandshakeMessage is only used for QUIC_CRYPTO. + return; + } config_.SetInitialStreamFlowControlWindowToSend( kInitialStreamFlowControlWindowForTest); config_.SetInitialSessionFlowControlWindowToSend( kInitialSessionFlowControlWindowForTest); - config_.SetIdleNetworkTimeout(QuicTime::Delta::FromSeconds(5), - QuicTime::Delta::FromSeconds(2)); + config_.SetIdleNetworkTimeout(QuicTime::Delta::FromSeconds(5)); CryptoHandshakeMessage msg; - config_.ToHandshakeMessage(&msg, GetParam()); + config_.ToHandshakeMessage(&msg, version_.transport_version); uint32_t value; QuicErrorCode error = msg.GetUint32(kICSL, &value); @@ -109,14 +131,17 @@ TEST_P(QuicConfigTest, ToHandshakeMessage) { } TEST_P(QuicConfigTest, ProcessClientHello) { + if (version_.UsesTls()) { + // CryptoHandshakeMessage is only used for QUIC_CRYPTO. + return; + } const uint32_t kTestMaxAckDelayMs = static_cast<uint32_t>(kDefaultDelayedAckTimeMs + 1); QuicConfig client_config; QuicTagVector cgst; cgst.push_back(kQBIC); client_config.SetIdleNetworkTimeout( - QuicTime::Delta::FromSeconds(2 * kMaximumIdleTimeoutSecs), - QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs)); + QuicTime::Delta::FromSeconds(2 * kMaximumIdleTimeoutSecs)); client_config.SetInitialRoundTripTimeUsToSend(10 * kNumMicrosPerMilli); client_config.SetInitialStreamFlowControlWindowToSend( 2 * kInitialStreamFlowControlWindowForTest); @@ -127,7 +152,7 @@ TEST_P(QuicConfigTest, ProcessClientHello) { client_config.SetConnectionOptionsToSend(copt); client_config.SetMaxAckDelayToSendMs(kTestMaxAckDelayMs); CryptoHandshakeMessage msg; - client_config.ToHandshakeMessage(&msg, GetParam()); + client_config.ToHandshakeMessage(&msg, version_.transport_version); std::string error_details; QuicTagVector initial_received_options; @@ -171,6 +196,10 @@ TEST_P(QuicConfigTest, ProcessClientHello) { } TEST_P(QuicConfigTest, ProcessServerHello) { + if (version_.UsesTls()) { + // CryptoHandshakeMessage is only used for QUIC_CRYPTO. + return; + } QuicIpAddress host; host.FromString("127.0.3.1"); const QuicSocketAddress kTestServerAddress = QuicSocketAddress(host, 1234); @@ -181,18 +210,17 @@ TEST_P(QuicConfigTest, ProcessServerHello) { QuicTagVector cgst; cgst.push_back(kQBIC); server_config.SetIdleNetworkTimeout( - QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs / 2), QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs / 2)); server_config.SetInitialRoundTripTimeUsToSend(10 * kNumMicrosPerMilli); server_config.SetInitialStreamFlowControlWindowToSend( 2 * kInitialStreamFlowControlWindowForTest); server_config.SetInitialSessionFlowControlWindowToSend( 2 * kInitialSessionFlowControlWindowForTest); - server_config.SetAlternateServerAddressToSend(kTestServerAddress); + server_config.SetIPv4AlternateServerAddressToSend(kTestServerAddress); server_config.SetStatelessResetTokenToSend(kTestResetToken); server_config.SetMaxAckDelayToSendMs(kTestMaxAckDelayMs); CryptoHandshakeMessage msg; - server_config.ToHandshakeMessage(&msg, GetParam()); + server_config.ToHandshakeMessage(&msg, version_.transport_version); std::string error_details; const QuicErrorCode error = config_.ProcessPeerHello(msg, SERVER, &error_details); @@ -205,8 +233,9 @@ TEST_P(QuicConfigTest, ProcessServerHello) { 2 * kInitialStreamFlowControlWindowForTest); EXPECT_EQ(config_.ReceivedInitialSessionFlowControlWindowBytes(), 2 * kInitialSessionFlowControlWindowForTest); - EXPECT_TRUE(config_.HasReceivedAlternateServerAddress()); - EXPECT_EQ(kTestServerAddress, config_.ReceivedAlternateServerAddress()); + EXPECT_TRUE(config_.HasReceivedIPv4AlternateServerAddress()); + EXPECT_EQ(kTestServerAddress, config_.ReceivedIPv4AlternateServerAddress()); + EXPECT_FALSE(config_.HasReceivedIPv6AlternateServerAddress()); EXPECT_TRUE(config_.HasReceivedStatelessResetToken()); EXPECT_EQ(kTestResetToken, config_.ReceivedStatelessResetToken()); if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) { @@ -225,6 +254,10 @@ TEST_P(QuicConfigTest, ProcessServerHello) { } TEST_P(QuicConfigTest, MissingOptionalValuesInCHLO) { + if (version_.UsesTls()) { + // CryptoHandshakeMessage is only used for QUIC_CRYPTO. + return; + } CryptoHandshakeMessage msg; msg.SetValue(kICSL, 1); @@ -241,6 +274,10 @@ TEST_P(QuicConfigTest, MissingOptionalValuesInCHLO) { } TEST_P(QuicConfigTest, MissingOptionalValuesInSHLO) { + if (version_.UsesTls()) { + // CryptoHandshakeMessage is only used for QUIC_CRYPTO. + return; + } CryptoHandshakeMessage msg; // Set all REQUIRED tags. @@ -256,6 +293,10 @@ TEST_P(QuicConfigTest, MissingOptionalValuesInSHLO) { } TEST_P(QuicConfigTest, MissingValueInCHLO) { + if (version_.UsesTls()) { + // CryptoHandshakeMessage is only used for QUIC_CRYPTO. + return; + } // Server receives CHLO with missing kICSL. CryptoHandshakeMessage msg; std::string error_details; @@ -265,6 +306,10 @@ TEST_P(QuicConfigTest, MissingValueInCHLO) { } TEST_P(QuicConfigTest, MissingValueInSHLO) { + if (version_.UsesTls()) { + // CryptoHandshakeMessage is only used for QUIC_CRYPTO. + return; + } // Client receives SHLO with missing kICSL. CryptoHandshakeMessage msg; std::string error_details; @@ -274,13 +319,16 @@ TEST_P(QuicConfigTest, MissingValueInSHLO) { } TEST_P(QuicConfigTest, OutOfBoundSHLO) { + if (version_.UsesTls()) { + // CryptoHandshakeMessage is only used for QUIC_CRYPTO. + return; + } QuicConfig server_config; server_config.SetIdleNetworkTimeout( - QuicTime::Delta::FromSeconds(2 * kMaximumIdleTimeoutSecs), QuicTime::Delta::FromSeconds(2 * kMaximumIdleTimeoutSecs)); CryptoHandshakeMessage msg; - server_config.ToHandshakeMessage(&msg, GetParam()); + server_config.ToHandshakeMessage(&msg, version_.transport_version); std::string error_details; const QuicErrorCode error = config_.ProcessPeerHello(msg, SERVER, &error_details); @@ -301,6 +349,10 @@ TEST_P(QuicConfigTest, InvalidFlowControlWindow) { } TEST_P(QuicConfigTest, HasClientSentConnectionOption) { + if (version_.UsesTls()) { + // CryptoHandshakeMessage is only used for QUIC_CRYPTO. + return; + } QuicConfig client_config; QuicTagVector copt; copt.push_back(kTBBR); @@ -309,7 +361,7 @@ TEST_P(QuicConfigTest, HasClientSentConnectionOption) { kTBBR, Perspective::IS_CLIENT)); CryptoHandshakeMessage msg; - client_config.ToHandshakeMessage(&msg, GetParam()); + client_config.ToHandshakeMessage(&msg, version_.transport_version); std::string error_details; const QuicErrorCode error = @@ -324,13 +376,17 @@ TEST_P(QuicConfigTest, HasClientSentConnectionOption) { } TEST_P(QuicConfigTest, DontSendClientConnectionOptions) { + if (version_.UsesTls()) { + // CryptoHandshakeMessage is only used for QUIC_CRYPTO. + return; + } QuicConfig client_config; QuicTagVector copt; copt.push_back(kTBBR); client_config.SetClientConnectionOptions(copt); CryptoHandshakeMessage msg; - client_config.ToHandshakeMessage(&msg, GetParam()); + client_config.ToHandshakeMessage(&msg, version_.transport_version); std::string error_details; const QuicErrorCode error = @@ -342,6 +398,10 @@ TEST_P(QuicConfigTest, DontSendClientConnectionOptions) { } TEST_P(QuicConfigTest, HasClientRequestedIndependentOption) { + if (version_.UsesTls()) { + // CryptoHandshakeMessage is only used for QUIC_CRYPTO. + return; + } QuicConfig client_config; QuicTagVector client_opt; client_opt.push_back(kRENO); @@ -357,7 +417,7 @@ TEST_P(QuicConfigTest, HasClientRequestedIndependentOption) { kTBBR, Perspective::IS_CLIENT)); CryptoHandshakeMessage msg; - client_config.ToHandshakeMessage(&msg, GetParam()); + client_config.ToHandshakeMessage(&msg, version_.transport_version); std::string error_details; const QuicErrorCode error = @@ -374,23 +434,30 @@ TEST_P(QuicConfigTest, HasClientRequestedIndependentOption) { } TEST_P(QuicConfigTest, IncomingLargeIdleTimeoutTransportParameter) { - // Configure our default to 30s and max to 60s, then receive 120s from peer. - // Since the received value is above the max, we should then use the max. - config_.SetIdleNetworkTimeout(quic::QuicTime::Delta::FromSeconds(60), - quic::QuicTime::Delta::FromSeconds(30)); + if (!version_.UsesTls()) { + // TransportParameters are only used for QUIC+TLS. + return; + } + // Configure our idle timeout to 60s, then receive 120s from peer. + // Since the received value is above ours, we should then use ours. + config_.SetIdleNetworkTimeout(quic::QuicTime::Delta::FromSeconds(60)); TransportParameters params; params.idle_timeout_milliseconds.set_value(120000); std::string error_details = "foobar"; - EXPECT_THAT( - config_.ProcessTransportParameters(params, SERVER, &error_details), - IsQuicNoError()); + EXPECT_THAT(config_.ProcessTransportParameters( + params, SERVER, /* is_resumption = */ false, &error_details), + IsQuicNoError()); EXPECT_EQ("", error_details); EXPECT_EQ(quic::QuicTime::Delta::FromSeconds(60), config_.IdleNetworkTimeout()); } TEST_P(QuicConfigTest, FillTransportParams) { + if (!version_.UsesTls()) { + // TransportParameters are only used for QUIC+TLS. + return; + } config_.SetInitialMaxStreamDataBytesIncomingBidirectionalToSend( 2 * kMinimumFlowControlSendWindow); config_.SetInitialMaxStreamDataBytesOutgoingBidirectionalToSend( @@ -399,6 +466,7 @@ TEST_P(QuicConfigTest, FillTransportParams) { 4 * kMinimumFlowControlSendWindow); config_.SetMaxPacketSizeToSend(kMaxPacketSizeForTest); config_.SetMaxDatagramFrameSizeToSend(kMaxDatagramFrameSizeForTest); + config_.SetActiveConnectionIdLimitToSend(kFakeActiveConnectionIdLimit); TransportParameters params; config_.FillTransportParameters(¶ms); @@ -416,9 +484,16 @@ TEST_P(QuicConfigTest, FillTransportParams) { EXPECT_EQ(kMaxPacketSizeForTest, params.max_packet_size.value()); EXPECT_EQ(kMaxDatagramFrameSizeForTest, params.max_datagram_frame_size.value()); + EXPECT_EQ(kFakeActiveConnectionIdLimit, + params.active_connection_id_limit.value()); } TEST_P(QuicConfigTest, ProcessTransportParametersServer) { + if (!version_.UsesTls()) { + // TransportParameters are only used for QUIC+TLS. + return; + } + SetQuicReloadableFlag(quic_negotiate_ack_delay_time, true); TransportParameters params; params.initial_max_stream_data_bidi_local.set_value( @@ -429,11 +504,19 @@ TEST_P(QuicConfigTest, ProcessTransportParametersServer) { kMinimumFlowControlSendWindow); params.max_packet_size.set_value(kMaxPacketSizeForTest); params.max_datagram_frame_size.set_value(kMaxDatagramFrameSizeForTest); + params.initial_max_streams_bidi.set_value(kDefaultMaxStreamsPerConnection); + params.stateless_reset_token = CreateFakeStatelessResetToken(); + params.max_ack_delay.set_value(kFakeMaxAckDelay); + params.ack_delay_exponent.set_value(kFakeAckDelayExponent); + params.active_connection_id_limit.set_value(kFakeActiveConnectionIdLimit); std::string error_details; - EXPECT_THAT( - config_.ProcessTransportParameters(params, SERVER, &error_details), - IsQuicNoError()); + EXPECT_THAT(config_.ProcessTransportParameters( + params, SERVER, /* is_resumption = */ true, &error_details), + IsQuicNoError()) + << error_details; + + EXPECT_FALSE(config_.negotiated()); ASSERT_TRUE( config_.HasReceivedInitialMaxStreamDataBytesIncomingBidirectional()); @@ -456,16 +539,89 @@ TEST_P(QuicConfigTest, ProcessTransportParametersServer) { EXPECT_EQ(kMaxDatagramFrameSizeForTest, config_.ReceivedMaxDatagramFrameSize()); + ASSERT_TRUE(config_.HasReceivedMaxBidirectionalStreams()); + EXPECT_EQ(kDefaultMaxStreamsPerConnection, + config_.ReceivedMaxBidirectionalStreams()); + EXPECT_FALSE(config_.DisableConnectionMigration()); + + // The following config shouldn't be processed because of resumption. + EXPECT_FALSE(config_.HasReceivedStatelessResetToken()); + EXPECT_FALSE(config_.HasReceivedMaxAckDelayMs()); + EXPECT_FALSE(config_.HasReceivedAckDelayExponent()); + + // Let the config process another slightly tweaked transport paramters. + // Note that the values for flow control and stream limit cannot be smaller + // than before. This rule is enforced in QuicSession::OnConfigNegotiated(). + params.initial_max_stream_data_bidi_local.set_value( + 2 * kMinimumFlowControlSendWindow + 1); + params.initial_max_stream_data_bidi_remote.set_value( + 4 * kMinimumFlowControlSendWindow); + params.initial_max_stream_data_uni.set_value(5 * + kMinimumFlowControlSendWindow); + params.max_packet_size.set_value(2 * kMaxPacketSizeForTest); + params.max_datagram_frame_size.set_value(2 * kMaxDatagramFrameSizeForTest); + params.initial_max_streams_bidi.set_value(2 * + kDefaultMaxStreamsPerConnection); + params.disable_migration = true; + + EXPECT_THAT(config_.ProcessTransportParameters( + params, SERVER, /* is_resumption = */ false, &error_details), + IsQuicNoError()) + << error_details; + + EXPECT_TRUE(config_.negotiated()); + + ASSERT_TRUE( + config_.HasReceivedInitialMaxStreamDataBytesIncomingBidirectional()); + EXPECT_EQ(2 * kMinimumFlowControlSendWindow + 1, + config_.ReceivedInitialMaxStreamDataBytesIncomingBidirectional()); + + ASSERT_TRUE( + config_.HasReceivedInitialMaxStreamDataBytesOutgoingBidirectional()); + EXPECT_EQ(4 * kMinimumFlowControlSendWindow, + config_.ReceivedInitialMaxStreamDataBytesOutgoingBidirectional()); + + ASSERT_TRUE(config_.HasReceivedInitialMaxStreamDataBytesUnidirectional()); + EXPECT_EQ(5 * kMinimumFlowControlSendWindow, + config_.ReceivedInitialMaxStreamDataBytesUnidirectional()); + + ASSERT_TRUE(config_.HasReceivedMaxPacketSize()); + EXPECT_EQ(2 * kMaxPacketSizeForTest, config_.ReceivedMaxPacketSize()); + + ASSERT_TRUE(config_.HasReceivedMaxDatagramFrameSize()); + EXPECT_EQ(2 * kMaxDatagramFrameSizeForTest, + config_.ReceivedMaxDatagramFrameSize()); + + ASSERT_TRUE(config_.HasReceivedMaxBidirectionalStreams()); + EXPECT_EQ(2 * kDefaultMaxStreamsPerConnection, + config_.ReceivedMaxBidirectionalStreams()); + + EXPECT_TRUE(config_.DisableConnectionMigration()); + + ASSERT_TRUE(config_.HasReceivedStatelessResetToken()); + ASSERT_TRUE(config_.HasReceivedMaxAckDelayMs()); + EXPECT_EQ(config_.ReceivedMaxAckDelayMs(), kFakeMaxAckDelay); + + ASSERT_TRUE(config_.HasReceivedAckDelayExponent()); + EXPECT_EQ(config_.ReceivedAckDelayExponent(), kFakeAckDelayExponent); + + ASSERT_TRUE(config_.HasReceivedActiveConnectionIdLimit()); + EXPECT_EQ(config_.ReceivedActiveConnectionIdLimit(), + kFakeActiveConnectionIdLimit); } TEST_P(QuicConfigTest, DisableMigrationTransportParameter) { + if (!version_.UsesTls()) { + // TransportParameters are only used for QUIC+TLS. + return; + } TransportParameters params; params.disable_migration = true; std::string error_details; - EXPECT_THAT( - config_.ProcessTransportParameters(params, SERVER, &error_details), - IsQuicNoError()); + EXPECT_THAT(config_.ProcessTransportParameters( + params, SERVER, /* is_resumption = */ false, &error_details), + IsQuicNoError()); EXPECT_TRUE(config_.DisableConnectionMigration()); } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection.cc b/chromium/net/third_party/quiche/src/quic/core/quic_connection.cc index f83dbdd8950..4f089a44fe9 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_connection.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection.cc @@ -286,9 +286,6 @@ QuicConnection::QuicConnection( mtu_discovery_alarm_(alarm_factory_->CreateAlarm( arena_.New<MtuDiscoveryAlarmDelegate>(this), &arena_)), - path_degrading_alarm_(alarm_factory_->CreateAlarm( - arena_.New<PathDegradingAlarmDelegate>(this), - &arena_)), process_undecryptable_packets_alarm_(alarm_factory_->CreateAlarm( arena_.New<ProcessUndecryptablePacketsAlarmDelegate>(this), &arena_)), @@ -299,6 +296,7 @@ QuicConnection::QuicConnection( handshake_timeout_(QuicTime::Delta::Infinite()), time_of_first_packet_sent_after_receiving_(QuicTime::Zero()), time_of_last_received_packet_(clock_->ApproximateNow()), + time_of_last_decryptable_packet_(time_of_last_received_packet_), sent_packet_manager_(perspective, clock_, random_generator_, @@ -347,7 +345,9 @@ QuicConnection::QuicConnection( << "QuicConnection: attempted to use server connection ID " << server_connection_id << " which is invalid with version " << QuicVersionToString(transport_version()); - + if (advance_ack_timeout_update_) { + QUIC_RELOADABLE_FLAG_COUNT(quic_advance_ack_timeout_update); + } framer_.set_visitor(this); stats_.connection_creation_time = clock_->ApproximateNow(); // TODO(ianswett): Supply the NetworkChangeVisitor as a constructor argument @@ -407,9 +407,40 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) { // Handshake complete, set handshake timeout to Infinite. SetNetworkTimeouts(QuicTime::Delta::Infinite(), config.IdleNetworkTimeout()); - if (config.SilentClose()) { - idle_timeout_connection_close_behavior_ = - ConnectionCloseBehavior::SILENT_CLOSE; + idle_timeout_connection_close_behavior_ = + ConnectionCloseBehavior::SILENT_CLOSE; + if (original_connection_id_.has_value()) { + DCHECK_EQ(perspective_, Perspective::IS_CLIENT); + // We received a RETRY packet, validate that the |original_connection_id| + // from the config matches the one from the RETRY. + if (!config.HasReceivedOriginalConnectionId() || + config.ReceivedOriginalConnectionId() != + original_connection_id_.value()) { + std::string received_value; + if (config.HasReceivedOriginalConnectionId()) { + received_value = config.ReceivedOriginalConnectionId().ToString(); + } else { + received_value = "none"; + } + std::string error_details = quiche::QuicheStrCat( + "Bad original_connection_id: expected ", + original_connection_id_.value().ToString(), ", received ", + received_value, ", RETRY used ", server_connection_id_.ToString()); + CloseConnection(IETF_QUIC_PROTOCOL_VIOLATION, error_details, + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return; + } + } else { + // We did not receive a RETRY packet, make sure we did not receive the + // original_connection_id transport parameter. + if (config.HasReceivedOriginalConnectionId()) { + std::string error_details = quiche::QuicheStrCat( + "Bad original_connection_id: did not receive RETRY but received ", + config.ReceivedOriginalConnectionId().ToString()); + CloseConnection(IETF_QUIC_PROTOCOL_VIOLATION, error_details, + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return; + } } } else { SetNetworkTimeouts(config.max_time_before_crypto_handshake(), @@ -466,8 +497,7 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) { framer_.set_process_timestamps(true); uber_received_packet_manager_.set_save_timestamps(true); } - if (GetQuicReloadableFlag(quic_bundle_retransmittable_with_pto_ack) && - config.HasClientSentConnectionOption(kEACK, perspective_)) { + if (config.HasClientSentConnectionOption(kEACK, perspective_)) { bundle_retransmittable_with_pto_ack_ = true; } if (config.HasReceivedMaxPacketSize()) { @@ -475,6 +505,10 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) { packet_creator_.SetMaxPacketLength( GetLimitedMaxPacketSize(packet_creator_.max_packet_length())); } + if (config.HasReceivedMaxDatagramFrameSize()) { + packet_creator_.SetMaxDatagramFrameSize( + config.ReceivedMaxDatagramFrameSize()); + } supports_release_time_ = writer_ != nullptr && writer_->SupportsReleaseTime() && @@ -485,6 +519,11 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) { } } +void QuicConnection::ApplyConnectionOptions( + const QuicTagVector& connection_options) { + sent_packet_manager_.ApplyConnectionOptions(connection_options); +} + void QuicConnection::OnSendConnectionState( const CachedNetworkParameters& cached_network_params) { if (debug_visitor_ != nullptr) { @@ -679,6 +718,8 @@ void QuicConnection::OnRetryPacket( << server_connection_id_ << " with " << new_connection_id << ", received token " << quiche::QuicheTextUtils::HexEncode(retry_token); + DCHECK(!original_connection_id_.has_value()); + original_connection_id_ = server_connection_id_; server_connection_id_ = new_connection_id; packet_creator_.SetServerConnectionId(server_connection_id_); packet_creator_.SetRetryToken(retry_token); @@ -808,6 +849,14 @@ void QuicConnection::OnDecryptedPacket(EncryptionLevel level) { // Address is validated by successfully processing a HANDSHAKE packet. address_validated_ = true; } + if (extend_idle_time_on_decryptable_packets_) { + QUIC_RELOADABLE_FLAG_COUNT(quic_extend_idle_time_on_decryptable_packets); + if (use_idle_network_detector_) { + idle_network_detector_.OnPacketReceived(time_of_last_received_packet_); + } else { + time_of_last_decryptable_packet_ = time_of_last_received_packet_; + } + } visitor_->OnPacketDecrypted(level); } @@ -913,9 +962,14 @@ bool QuicConnection::OnStreamFrame(const QuicStreamFrame& frame) { ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); return false; } + if (advance_ack_timeout_update_) { + MaybeUpdateAckTimeout(); + } visitor_->OnStreamFrame(frame); stats_.stream_bytes_received += frame.data_length; - should_last_packet_instigate_acks_ = true; + if (!advance_ack_timeout_update_) { + should_last_packet_instigate_acks_ = true; + } consecutive_retransmittable_on_wire_ping_count_ = 0; return connected_; } @@ -930,8 +984,13 @@ bool QuicConnection::OnCryptoFrame(const QuicCryptoFrame& frame) { if (debug_visitor_ != nullptr) { debug_visitor_->OnCryptoFrame(frame); } + if (advance_ack_timeout_update_) { + MaybeUpdateAckTimeout(); + } visitor_->OnCryptoFrame(frame); - should_last_packet_instigate_acks_ = true; + if (!advance_ack_timeout_update_) { + should_last_packet_instigate_acks_ = true; + } return connected_; } @@ -1118,7 +1177,11 @@ bool QuicConnection::OnPingFrame(const QuicPingFrame& frame) { if (debug_visitor_ != nullptr) { debug_visitor_->OnPingFrame(frame); } - should_last_packet_instigate_acks_ = true; + if (advance_ack_timeout_update_) { + MaybeUpdateAckTimeout(); + } else { + should_last_packet_instigate_acks_ = true; + } return true; } @@ -1160,8 +1223,13 @@ bool QuicConnection::OnRstStreamFrame(const QuicRstStreamFrame& frame) { << "RST_STREAM_FRAME received for stream: " << frame.stream_id << " with error: " << QuicRstStreamErrorCodeToString(frame.error_code); + if (advance_ack_timeout_update_) { + MaybeUpdateAckTimeout(); + } visitor_->OnRstStream(frame); - should_last_packet_instigate_acks_ = true; + if (!advance_ack_timeout_update_) { + should_last_packet_instigate_acks_ = true; + } return connected_; } @@ -1192,7 +1260,11 @@ bool QuicConnection::OnPathChallengeFrame(const QuicPathChallengeFrame& frame) { // response. received_path_challenge_payloads_.push_back(frame.data_buffer); - should_last_packet_instigate_acks_ = true; + if (advance_ack_timeout_update_) { + MaybeUpdateAckTimeout(); + } else { + should_last_packet_instigate_acks_ = true; + } return true; } @@ -1200,7 +1272,11 @@ bool QuicConnection::OnPathResponseFrame(const QuicPathResponseFrame& frame) { if (debug_visitor_ != nullptr) { debug_visitor_->OnPathResponseFrame(frame); } - should_last_packet_instigate_acks_ = true; + if (advance_ack_timeout_update_) { + MaybeUpdateAckTimeout(); + } else { + should_last_packet_instigate_acks_ = true; + } if (!transmitted_connectivity_probe_payload_ || *transmitted_connectivity_probe_payload_ != frame.data_buffer) { // Is not for the probe we sent, ignore it. @@ -1226,31 +1302,30 @@ bool QuicConnection::OnConnectionCloseFrame( case GOOGLE_QUIC_CONNECTION_CLOSE: QUIC_DLOG(INFO) << ENDPOINT << "Received ConnectionClose for connection: " << connection_id() << ", with error: " - << QuicErrorCodeToString(frame.extracted_error_code) - << " (" << frame.error_details << ")"; + << QuicErrorCodeToString(frame.quic_error_code) << " (" + << frame.error_details << ")"; break; case IETF_QUIC_TRANSPORT_CONNECTION_CLOSE: QUIC_DLOG(INFO) << ENDPOINT << "Received Transport ConnectionClose for connection: " << connection_id() << ", with error: " - << QuicErrorCodeToString(frame.extracted_error_code) - << " (" << frame.error_details << ")" - << ", transport error code: " - << frame.transport_error_code << ", error frame type: " + << QuicErrorCodeToString(frame.quic_error_code) << " (" + << frame.error_details << ")" + << ", transport error code: " << frame.wire_error_code + << ", error frame type: " << frame.transport_close_frame_type; break; case IETF_QUIC_APPLICATION_CONNECTION_CLOSE: QUIC_DLOG(INFO) << ENDPOINT << "Received Application ConnectionClose for connection: " << connection_id() << ", with error: " - << QuicErrorCodeToString(frame.extracted_error_code) - << " (" << frame.error_details << ")" - << ", application error code: " - << frame.application_error_code; + << QuicErrorCodeToString(frame.quic_error_code) << " (" + << frame.error_details << ")" + << ", application error code: " << frame.wire_error_code; break; } - if (frame.extracted_error_code == QUIC_BAD_MULTIPATH_FLAG) { + if (frame.quic_error_code == QUIC_BAD_MULTIPATH_FLAG) { QUIC_LOG_FIRST_N(ERROR, 10) << "Unexpected QUIC_BAD_MULTIPATH_FLAG error." << " last_received_header: " << last_header_ << " encryption_level: " << encryption_level_; @@ -1288,9 +1363,13 @@ bool QuicConnection::OnGoAwayFrame(const QuicGoAwayFrame& frame) { << frame.last_good_stream_id << " and error: " << QuicErrorCodeToString(frame.error_code) << " and reason: " << frame.reason_phrase; - + if (advance_ack_timeout_update_) { + MaybeUpdateAckTimeout(); + } visitor_->OnGoAway(frame); - should_last_packet_instigate_acks_ = true; + if (!advance_ack_timeout_update_) { + should_last_packet_instigate_acks_ = true; + } return connected_; } @@ -1305,8 +1384,13 @@ bool QuicConnection::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) { debug_visitor_->OnWindowUpdateFrame(frame, GetTimeOfLastReceivedPacket()); } QUIC_DVLOG(1) << ENDPOINT << "WINDOW_UPDATE_FRAME received " << frame; + if (advance_ack_timeout_update_) { + MaybeUpdateAckTimeout(); + } visitor_->OnWindowUpdateFrame(frame); - should_last_packet_instigate_acks_ = true; + if (!advance_ack_timeout_update_) { + should_last_packet_instigate_acks_ = true; + } return connected_; } @@ -1343,9 +1427,14 @@ bool QuicConnection::OnMessageFrame(const QuicMessageFrame& frame) { if (debug_visitor_ != nullptr) { debug_visitor_->OnMessageFrame(frame); } + if (advance_ack_timeout_update_) { + MaybeUpdateAckTimeout(); + } visitor_->OnMessageReceived( quiche::QuicheStringPiece(frame.data, frame.message_length)); - should_last_packet_instigate_acks_ = true; + if (!advance_ack_timeout_update_) { + should_last_packet_instigate_acks_ = true; + } return connected_; } @@ -1366,8 +1455,13 @@ bool QuicConnection::OnHandshakeDoneFrame(const QuicHandshakeDoneFrame& frame) { if (debug_visitor_ != nullptr) { debug_visitor_->OnHandshakeDoneFrame(frame); } + if (advance_ack_timeout_update_) { + MaybeUpdateAckTimeout(); + } visitor_->OnHandshakeDoneReceived(); - should_last_packet_instigate_acks_ = true; + if (!advance_ack_timeout_update_) { + should_last_packet_instigate_acks_ = true; + } return connected_; } @@ -1383,9 +1477,14 @@ bool QuicConnection::OnBlockedFrame(const QuicBlockedFrame& frame) { } QUIC_DLOG(INFO) << ENDPOINT << "BLOCKED_FRAME received for stream: " << frame.stream_id; + if (advance_ack_timeout_update_) { + MaybeUpdateAckTimeout(); + } visitor_->OnBlockedFrame(frame); stats_.blocked_frames_received++; - should_last_packet_instigate_acks_ = true; + if (!advance_ack_timeout_update_) { + should_last_packet_instigate_acks_ = true; + } return connected_; } @@ -1457,10 +1556,12 @@ void QuicConnection::OnPacketComplete() { // For IETF QUIC, it is guaranteed that TLS will give connection the // corresponding write key before read key. In other words, connection should // never process a packet while an ACK for it cannot be encrypted. - uber_received_packet_manager_.MaybeUpdateAckTimeout( - should_last_packet_instigate_acks_, last_decrypted_packet_level_, - last_header_.packet_number, GetTimeOfLastReceivedPacket(), - clock_->ApproximateNow(), sent_packet_manager_.GetRttStats()); + if (!advance_ack_timeout_update_ || !should_last_packet_instigate_acks_) { + uber_received_packet_manager_.MaybeUpdateAckTimeout( + should_last_packet_instigate_acks_, last_decrypted_packet_level_, + last_header_.packet_number, GetTimeOfLastReceivedPacket(), + clock_->ApproximateNow(), sent_packet_manager_.GetRttStats()); + } ClearLastFrames(); CloseIfTooManyOutstandingSentPackets(); @@ -1735,9 +1836,12 @@ void QuicConnection::OnUndecryptablePacket(const QuicEncryptedPacket& packet, } if (should_enqueue) { - QueueUndecryptablePacket(packet); - } else if (debug_visitor_ != nullptr) { - debug_visitor_->OnUndecryptablePacket(); + QueueUndecryptablePacket(packet, decryption_level); + } + + if (debug_visitor_ != nullptr) { + debug_visitor_->OnUndecryptablePacket(decryption_level, + /*dropped=*/!should_enqueue); } } @@ -1795,7 +1899,7 @@ void QuicConnection::ProcessUdpPacket(const QuicSocketAddress& self_address, << " too far from current time:" << clock_->ApproximateNow().ToDebuggingValue(); } - if (use_idle_network_detector_) { + if (!extend_idle_time_on_decryptable_packets_ && use_idle_network_detector_) { QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_idle_network_detector, 1, 6); idle_network_detector_.OnPacketReceived(packet.receipt_time()); } else { @@ -2018,6 +2122,12 @@ void QuicConnection::WriteQueuedPackets() { // TODO(wub): Reduce max packet size to a safe default, or the actual MTU. mtu_discoverer_.Disable(); mtu_discovery_alarm_->Cancel(); + if (GetQuicReloadableFlag( + quic_ignore_msg_too_big_from_buffered_packets)) { + QUIC_RELOADABLE_FLAG_COUNT( + quic_ignore_msg_too_big_from_buffered_packets); + buffered_packets_.pop_front(); + } continue; } if (IsWriteError(result.status)) { @@ -2157,6 +2267,23 @@ bool QuicConnection::CanWrite(HasRetransmittableData retransmittable) { return true; } +QuicTime QuicConnection::CalculatePacketSentTime() { + const QuicTime now = clock_->Now(); + if (!supports_release_time_ || per_packet_options_ == nullptr) { + // Don't change the release delay. + return now; + } + + auto next_release_time_result = sent_packet_manager_.GetNextReleaseTime(); + + // Release before |now| is impossible. + QuicTime next_release_time = + std::max(now, next_release_time_result.release_time); + per_packet_options_->release_time_delay = next_release_time - now; + per_packet_options_->allow_burst = next_release_time_result.allow_burst; + return next_release_time; +} + bool QuicConnection::WritePacket(SerializedPacket* packet) { if (ShouldDiscardPacket(*packet)) { ++stats_.packets_discarded; @@ -2166,8 +2293,6 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { packet->packet_number < sent_packet_manager_.GetLargestSentPacket()) { QUIC_BUG << "Attempt to write packet:" << packet->packet_number << " after:" << sent_packet_manager_.GetLargestSentPacket(); - QUIC_CLIENT_HISTOGRAM_COUNTS("QuicSession.NumQueuedPacketsAtOutOfOrder", - buffered_packets_.size(), 1, 1000, 50, ""); CloseConnection(QUIC_INTERNAL_ERROR, "Packet written out of order.", ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); return true; @@ -2180,7 +2305,7 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { // Termination packets are encrypted and saved, so don't exit early. const bool is_termination_packet = IsTerminationPacket(*packet); QuicPacketNumber packet_number = packet->packet_number; - QuicPacketLength encrypted_length = packet->encrypted_length; + const QuicPacketLength encrypted_length = packet->encrypted_length; // Termination packets are eventually owned by TimeWaitListManager. // Others are deleted at the end of this call. if (is_termination_packet) { @@ -2213,18 +2338,7 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { // Measure the RTT from before the write begins to avoid underestimating the // min_rtt_, especially in cases where the thread blocks or gets swapped out // during the WritePacket below. - QuicTime packet_send_time = clock_->Now(); - if (supports_release_time_ && per_packet_options_ != nullptr) { - QuicTime next_release_time = sent_packet_manager_.GetNextReleaseTime(); - QuicTime::Delta release_time_delay = QuicTime::Delta::Zero(); - QuicTime now = packet_send_time; - if (next_release_time > now) { - release_time_delay = next_release_time - now; - // Set packet_send_time to the future to make the RTT estimation accurate. - packet_send_time = next_release_time; - } - per_packet_options_->release_time_delay = release_time_delay; - } + QuicTime packet_send_time = CalculatePacketSentTime(); WriteResult result(WRITE_STATUS_OK, encrypted_length); switch (fate) { case COALESCE: @@ -2314,8 +2428,8 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { // When MSG_TOO_BIG is returned, the system typically knows what the // actual MTU is, so there is no need to probe further. // TODO(wub): Reduce max packet size to a safe default, or the actual MTU. - QUIC_DVLOG(1) << ENDPOINT << " MTU probe packet too big, size:" - << packet->encrypted_length + QUIC_DVLOG(1) << ENDPOINT + << " MTU probe packet too big, size:" << encrypted_length << ", long_term_mtu_:" << long_term_mtu_; mtu_discoverer_.Disable(); mtu_discovery_alarm_->Cancel(); @@ -2349,29 +2463,22 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { !is_termination_packet) { // Start blackhole/path degrading detections if the sent packet is not // termination packet and contains retransmittable data. - if (use_blackhole_detector_) { - // Do not restart detection if detection is in progress indicating no - // forward progress has been made since last event (i.e., packet was sent - // or new packets were acknowledged). - if (!blackhole_detector_.IsDetectionInProgress()) { - // Try to start detections if no detection in progress. This could - // because either both detections are inactive when sending last packet - // or this connection just gets out of quiescence. - QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_blackhole_detector, 1, 4); - blackhole_detector_.RestartDetection(GetPathDegradingDeadline(), - GetNetworkBlackholeDeadline()); - } - } else if (!is_path_degrading_ && !path_degrading_alarm_->IsSet()) { - // This is the first retransmittable packet on the working path. - // Start the path degrading alarm to detect new path degrading. - SetPathDegradingAlarm(); + // Do not restart detection if detection is in progress indicating no + // forward progress has been made since last event (i.e., packet was sent + // or new packets were acknowledged). + if (!blackhole_detector_.IsDetectionInProgress()) { + // Try to start detections if no detection in progress. This could + // because either both detections are inactive when sending last packet + // or this connection just gets out of quiescence. + blackhole_detector_.RestartDetection(GetPathDegradingDeadline(), + GetNetworkBlackholeDeadline()); } if (use_idle_network_detector_) { idle_network_detector_.OnPacketSent(packet_send_time); QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_idle_network_detector, 2, 6); } else if (time_of_first_packet_sent_after_receiving_ < - time_of_last_received_packet_) { + GetTimeOfLastReceivedPacket()) { // Update |time_of_first_packet_sent_after_receiving_| if this is the // first packet sent after the last packet was received. If it were // updated on every sent packet, then sending into a black hole might @@ -2386,7 +2493,7 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { if (EnforceAntiAmplificationLimit()) { // Include bytes sent even if they are not in flight. - bytes_sent_before_address_validation_ += packet->encrypted_length; + bytes_sent_before_address_validation_ += encrypted_length; } const bool in_flight = sent_packet_manager_.OnPacketSent( @@ -2474,12 +2581,10 @@ bool QuicConnection::ShouldDiscardPacket(const SerializedPacket& packet) { } bool QuicConnection::ShouldIgnoreWriteError() { - if (!GetQuicReloadableFlag(quic_ignore_one_write_error_after_mtu_probe) || - previous_validated_mtu_ == 0) { + if (previous_validated_mtu_ == 0) { return false; } - QUIC_CODE_COUNT(quic_ignore_one_write_error_after_mtu_probe); SetMaxPacketLength(previous_validated_mtu_); mtu_discoverer_.Disable(); mtu_discovery_alarm_->Cancel(); @@ -2524,8 +2629,8 @@ char* QuicConnection::GetPacketBuffer() { return writer_->GetNextWriteLocation(self_address().host(), peer_address()); } -void QuicConnection::OnSerializedPacket(SerializedPacket* serialized_packet) { - if (serialized_packet->encrypted_buffer == nullptr) { +void QuicConnection::OnSerializedPacket(SerializedPacket serialized_packet) { + if (serialized_packet.encrypted_buffer == nullptr) { // We failed to serialize the packet, so close the connection. // Specify that the close is silent, that no packet be sent, so no infinite // loop here. @@ -2544,14 +2649,14 @@ void QuicConnection::OnSerializedPacket(SerializedPacket* serialized_packet) { return; } - if (serialized_packet->retransmittable_frames.empty()) { + if (serialized_packet.retransmittable_frames.empty()) { // Increment consecutive_num_packets_with_no_retransmittable_frames_ if // this packet is a new transmission with no retransmittable frames. ++consecutive_num_packets_with_no_retransmittable_frames_; } else { consecutive_num_packets_with_no_retransmittable_frames_ = 0; } - SendOrQueuePacket(serialized_packet); + SendOrQueuePacket(std::move(serialized_packet)); } void QuicConnection::OnUnrecoverableError(QuicErrorCode error, @@ -2610,14 +2715,9 @@ void QuicConnection::OnHandshakeComplete() { kAlarmGranularity); } -void QuicConnection::SendOrQueuePacket(SerializedPacket* packet) { +void QuicConnection::SendOrQueuePacket(SerializedPacket packet) { // The caller of this function is responsible for checking CanWrite(). - if (packet->encrypted_buffer == nullptr) { - QUIC_BUG << "packet.encrypted_buffer == nullptr in to SendOrQueuePacket"; - return; - } - WritePacket(packet); - ClearSerializedPacket(packet); + WritePacket(&packet); } void QuicConnection::OnPingTimeout() { @@ -2668,28 +2768,6 @@ void QuicConnection::OnRetransmissionTimeout() { QuicPacketNumber previous_created_packet_number = packet_creator_.packet_number(); - if (!use_blackhole_detector_) { - if (close_connection_after_five_rtos_ && - sent_packet_manager_.GetConsecutiveRtoCount() >= 4) { - // Close on the 5th consecutive RTO, so after 4 previous RTOs have - // occurred. - CloseConnection(QUIC_TOO_MANY_RTOS, - "5 consecutive retransmission timeouts", - ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); - return; - } - if (sent_packet_manager_.pto_enabled() && max_consecutive_ptos_ > 0 && - sent_packet_manager_.GetConsecutivePtoCount() >= - max_consecutive_ptos_) { - CloseConnection( - QUIC_TOO_MANY_RTOS, - quiche::QuicheStrCat(max_consecutive_ptos_ + 1, - "consecutive retransmission timeouts"), - ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); - return; - } - } - const auto retransmission_mode = sent_packet_manager_.OnRetransmissionTimeout(); if (sent_packet_manager_.skip_packet_number_for_pto() && @@ -2701,10 +2779,7 @@ void QuicConnection::OnRetransmissionTimeout() { packet_creator_.SkipNPacketNumbers( num_packet_numbers_to_skip, sent_packet_manager_.GetLeastUnacked(), sent_packet_manager_.EstimateMaxPacketsInFlight(max_packet_length())); - if (GetQuicReloadableFlag(quic_send_ping_when_pto_skips_packet_number)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_send_ping_when_pto_skips_packet_number); - previous_created_packet_number += num_packet_numbers_to_skip; - } + previous_created_packet_number += num_packet_numbers_to_skip; if (debug_visitor_ != nullptr) { debug_visitor_->OnNPacketNumbersSkipped(num_packet_numbers_to_skip); } @@ -2840,16 +2915,17 @@ const QuicDecrypter* QuicConnection::alternative_decrypter() const { } void QuicConnection::QueueUndecryptablePacket( - const QuicEncryptedPacket& packet) { + const QuicEncryptedPacket& packet, + EncryptionLevel decryption_level) { for (const auto& saved_packet : undecryptable_packets_) { - if (packet.data() == saved_packet->data() && - packet.length() == saved_packet->length()) { + if (packet.data() == saved_packet.packet->data() && + packet.length() == saved_packet.packet->length()) { QUIC_DVLOG(1) << ENDPOINT << "Not queueing known undecryptable packet"; return; } } QUIC_DVLOG(1) << ENDPOINT << "Queueing undecryptable packet."; - undecryptable_packets_.push_back(packet.Clone()); + undecryptable_packets_.emplace_back(packet, decryption_level); } void QuicConnection::MaybeProcessUndecryptablePackets() { @@ -2868,8 +2944,12 @@ void QuicConnection::MaybeProcessUndecryptablePackets() { return; } QUIC_DVLOG(1) << ENDPOINT << "Attempting to process undecryptable packet"; - QuicEncryptedPacket* packet = undecryptable_packets_.front().get(); - if (!framer_.ProcessPacket(*packet) && + const auto& undecryptable_packet = undecryptable_packets_.front(); + if (debug_visitor_ != nullptr) { + debug_visitor_->OnAttemptingToProcessUndecryptablePacket( + undecryptable_packet.encryption_level); + } + if (!framer_.ProcessPacket(*undecryptable_packet.packet) && framer_.error() == QUIC_DECRYPTION_FAILURE) { QUIC_DVLOG(1) << ENDPOINT << "Unable to process undecryptable packet..."; break; @@ -2884,11 +2964,9 @@ void QuicConnection::MaybeProcessUndecryptablePackets() { // never be able to be decrypted. if (encryption_level_ == ENCRYPTION_FORWARD_SECURE) { if (debug_visitor_ != nullptr) { - // TODO(rtenneti): perhaps more efficient to pass the number of - // undecryptable packets as the argument to OnUndecryptablePacket so that - // we just need to call OnUndecryptablePacket once? - for (size_t i = 0; i < undecryptable_packets_.size(); ++i) { - debug_visitor_->OnUndecryptablePacket(); + for (const auto& undecryptable_packet : undecryptable_packets_) { + debug_visitor_->OnUndecryptablePacket( + undecryptable_packet.encryption_level, /*dropped=*/true); } } undecryptable_packets_.clear(); @@ -3064,12 +3142,8 @@ void QuicConnection::CancelAllAlarms() { send_alarm_->Cancel(); timeout_alarm_->Cancel(); mtu_discovery_alarm_->Cancel(); - path_degrading_alarm_->Cancel(); process_undecryptable_packets_alarm_->Cancel(); - if (use_blackhole_detector_) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_blackhole_detector, 4, 4); - blackhole_detector_.StopDetection(); - } + blackhole_detector_.StopDetection(); if (use_idle_network_detector_) { QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_idle_network_detector, 3, 6); idle_network_detector_.StopDetection(); @@ -3151,7 +3225,7 @@ void QuicConnection::CheckForTimeout() { } QuicTime time_of_last_packet = - std::max(time_of_last_received_packet_, + std::max(GetTimeOfLastReceivedPacket(), time_of_first_packet_sent_after_receiving_); // |delta| can be < 0 as |now| is approximate time but |time_of_last_packet| @@ -3187,7 +3261,7 @@ void QuicConnection::CheckForTimeout() { void QuicConnection::SetTimeoutAlarm() { DCHECK(!use_idle_network_detector_); QuicTime time_of_last_packet = - std::max(time_of_last_received_packet_, + std::max(GetTimeOfLastReceivedPacket(), time_of_first_packet_sent_after_receiving_); QuicTime deadline = time_of_last_packet + idle_network_timeout_; @@ -3270,16 +3344,6 @@ void QuicConnection::SetRetransmissionAlarm() { kAlarmGranularity); } -void QuicConnection::SetPathDegradingAlarm() { - DCHECK(!use_blackhole_detector_); - if (perspective_ == Perspective::IS_SERVER) { - return; - } - const QuicTime::Delta delay = sent_packet_manager_.GetPathDegradingDelay(); - path_degrading_alarm_->Update(clock_->ApproximateNow() + delay, - kAlarmGranularity); -} - void QuicConnection::MaybeSetMtuAlarm(QuicPacketNumber sent_packet_number) { if (mtu_discovery_alarm_->IsSet() || !mtu_discoverer_.ShouldProbeMtu(sent_packet_number)) { @@ -3505,7 +3569,7 @@ bool QuicConnection::SendGenericPathProbePacket( << "Sending path probe packet for connection_id = " << server_connection_id_; - OwningSerializedPacketPointer probing_packet; + std::unique_ptr<SerializedPacket> probing_packet; if (!version().HasIetfQuicFrames()) { // Non-IETF QUIC, generate a padded ping regardless of whether this is a // request or a response. @@ -3788,32 +3852,31 @@ void QuicConnection::UpdatePacketContent(PacketContent type) { void QuicConnection::PostProcessAfterAckFrame(bool send_stop_waiting, bool acked_new_packet) { if (no_stop_waiting_frames_) { - uber_received_packet_manager_.DontWaitForPacketsBefore( - last_decrypted_packet_level_, - SupportsMultiplePacketNumberSpaces() - ? sent_packet_manager_.GetLargestPacketPeerKnowsIsAcked( - last_decrypted_packet_level_) - : sent_packet_manager_.largest_packet_peer_knows_is_acked()); + if (GetQuicReloadableFlag(quic_donot_change_queued_ack) && + packet_creator_.has_ack()) { + QUIC_RELOADABLE_FLAG_COUNT(quic_donot_change_queued_ack); + } else { + uber_received_packet_manager_.DontWaitForPacketsBefore( + last_decrypted_packet_level_, + SupportsMultiplePacketNumberSpaces() + ? sent_packet_manager_.GetLargestPacketPeerKnowsIsAcked( + last_decrypted_packet_level_) + : sent_packet_manager_.largest_packet_peer_knows_is_acked()); + } } // Always reset the retransmission alarm when an ack comes in, since we now // have a better estimate of the current rtt than when it was set. SetRetransmissionAlarm(); - if (use_blackhole_detector_) { - if (acked_new_packet) { - is_path_degrading_ = false; - if (sent_packet_manager_.HasInFlightPackets()) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_blackhole_detector, 2, 4); - // Restart detections if forward progress has been made. - blackhole_detector_.RestartDetection(GetPathDegradingDeadline(), - GetNetworkBlackholeDeadline()); - } else { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_blackhole_detector, 3, 4); - // Stop detections in quiecense. - blackhole_detector_.StopDetection(); - } + if (acked_new_packet) { + is_path_degrading_ = false; + if (sent_packet_manager_.HasInFlightPackets()) { + // Restart detections if forward progress has been made. + blackhole_detector_.RestartDetection(GetPathDegradingDeadline(), + GetNetworkBlackholeDeadline()); + } else { + // Stop detections in quiecense. + blackhole_detector_.StopDetection(); } - } else { - MaybeSetPathDegradingAlarm(acked_new_packet); } if (send_stop_waiting) { @@ -3823,21 +3886,6 @@ void QuicConnection::PostProcessAfterAckFrame(bool send_stop_waiting, } } -void QuicConnection::MaybeSetPathDegradingAlarm(bool acked_new_packet) { - DCHECK(!use_blackhole_detector_); - if (!sent_packet_manager_.HasInFlightPackets()) { - // There are no retransmittable packets on the wire, so it's impossible to - // say if the connection has degraded. - path_degrading_alarm_->Cancel(); - } else if (acked_new_packet) { - // A previously-unacked packet has been acked, which means forward progress - // has been made. Unset |is_path_degrading| if the path was considered as - // degrading previously. Set/update the path degrading alarm. - is_path_degrading_ = false; - SetPathDegradingAlarm(); - } -} - void QuicConnection::SetSessionNotifier( SessionNotifierInterface* session_notifier) { sent_packet_manager_.SetSessionNotifier(session_notifier); @@ -3855,6 +3903,7 @@ void QuicConnection::SetTransmissionType(TransmissionType type) { void QuicConnection::UpdateReleaseTimeIntoFuture() { DCHECK(supports_release_time_); + const QuicTime::Delta prior_max_release_time = release_time_into_future_; release_time_into_future_ = std::max( QuicTime::Delta::FromMilliseconds(kMinReleaseTimeIntoFutureMs), std::min( @@ -3862,6 +3911,9 @@ void QuicConnection::UpdateReleaseTimeIntoFuture() { GetQuicFlag(FLAGS_quic_max_pace_time_into_future_ms)), sent_packet_manager_.GetRttStats()->SmoothedOrInitialRtt() * GetQuicFlag(FLAGS_quic_pace_time_into_future_srtt_fraction))); + QUIC_DVLOG(3) << "Updated max release time delay from " + << prior_max_release_time << " to " + << release_time_into_future_; } void QuicConnection::ResetAckStates() { @@ -3998,7 +4050,6 @@ bool QuicConnection::ShouldBundleRetransmittableFrameWithAck() const { if (bundle_retransmittable_with_pto_ack_ && (sent_packet_manager_.GetConsecutiveRtoCount() > 0 || sent_packet_manager_.GetConsecutivePtoCount() > 0)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_bundle_retransmittable_with_pto_ack); // Bundle a retransmittable frame with an ACK if the PTO or RTO has fired // in order to recover more quickly in cases of temporary network outage. return true; @@ -4032,6 +4083,12 @@ bool QuicConnection::FlushCoalescedPacket() { if (debug_visitor_ != nullptr) { debug_visitor_->OnCoalescedPacketSent(coalesced_packet_, length); } + if (coalesced_packet_.ContainsPacketOfEncryptionLevel( + ENCRYPTION_HANDSHAKE)) { + // This is only called in coalescer because all ENCRYPTION_HANDSHAKE + // packets go through the coalescer. + visitor_->OnHandshakePacketSent(); + } return true; } @@ -4055,6 +4112,11 @@ bool QuicConnection::FlushCoalescedPacket() { if (debug_visitor_ != nullptr) { debug_visitor_->OnCoalescedPacketSent(coalesced_packet_, length); } + if (coalesced_packet_.ContainsPacketOfEncryptionLevel(ENCRYPTION_HANDSHAKE)) { + // This is only called in coalescer because all ENCRYPTION_HANDSHAKE + // packets go through the coalescer. + visitor_->OnHandshakePacketSent(); + } // Account for added padding. if (length > coalesced_packet_.length()) { size_t padding_size = length - coalesced_packet_.length(); @@ -4202,13 +4264,11 @@ void QuicConnection::set_client_connection_id( } void QuicConnection::OnPathDegradingDetected() { - DCHECK(use_blackhole_detector_); is_path_degrading_ = true; visitor_->OnPathDegrading(); } void QuicConnection::OnBlackholeDetected() { - DCHECK(use_blackhole_detector_); CloseConnection(QUIC_TOO_MANY_RTOS, "Network blackhole detected.", ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); } @@ -4250,8 +4310,19 @@ void QuicConnection::OnIdleNetworkDetected() { idle_timeout_connection_close_behavior_); } +void QuicConnection::MaybeUpdateAckTimeout() { + DCHECK(advance_ack_timeout_update_); + if (should_last_packet_instigate_acks_) { + return; + } + should_last_packet_instigate_acks_ = true; + uber_received_packet_manager_.MaybeUpdateAckTimeout( + /*should_last_packet_instigate_acks=*/true, last_decrypted_packet_level_, + last_header_.packet_number, GetTimeOfLastReceivedPacket(), + clock_->ApproximateNow(), sent_packet_manager_.GetRttStats()); +} + QuicTime QuicConnection::GetPathDegradingDeadline() const { - DCHECK(use_blackhole_detector_); if (!ShouldDetectPathDegrading()) { return QuicTime::Zero(); } @@ -4260,7 +4331,6 @@ QuicTime QuicConnection::GetPathDegradingDeadline() const { } bool QuicConnection::ShouldDetectPathDegrading() const { - DCHECK(use_blackhole_detector_); if (!connected_) { return false; } @@ -4272,7 +4342,6 @@ bool QuicConnection::ShouldDetectPathDegrading() const { } QuicTime QuicConnection::GetNetworkBlackholeDeadline() const { - DCHECK(use_blackhole_detector_); if (!ShouldDetectBlackhole()) { return QuicTime::Zero(); } @@ -4281,7 +4350,6 @@ QuicTime QuicConnection::GetNetworkBlackholeDeadline() const { } bool QuicConnection::ShouldDetectBlackhole() const { - DCHECK(use_blackhole_detector_); if (!connected_) { return false; } @@ -4304,6 +4372,11 @@ QuicTime QuicConnection::GetTimeOfLastReceivedPacket() const { if (use_idle_network_detector_) { return idle_network_detector_.time_of_last_received_packet(); } + if (extend_idle_time_on_decryptable_packets_) { + DCHECK(time_of_last_decryptable_packet_ == time_of_last_received_packet_ || + !last_packet_decrypted_); + return time_of_last_decryptable_packet_; + } return time_of_last_received_packet_; } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection.h b/chromium/net/third_party/quiche/src/quic/core/quic_connection.h index a6be992badd..6586fb2870a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_connection.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection.h @@ -49,6 +49,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_containers.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_optional.h" #include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" @@ -181,6 +182,9 @@ class QUIC_EXPORT_PRIVATE QuicConnectionVisitorInterface { // Called when a 1RTT packet has been acknowledged. virtual void OnOneRttPacketAcknowledged() = 0; + + // Called when a packet of ENCRYPTION_HANDSHAKE gets sent. + virtual void OnHandshakePacketSent() = 0; }; // Interface which gets callbacks from the QuicConnection at interesting @@ -217,8 +221,15 @@ class QUIC_EXPORT_PRIVATE QuicConnectionDebugVisitor // match the ID of this connection. virtual void OnIncorrectConnectionId(QuicConnectionId /*connection_id*/) {} - // Called when an undecryptable packet has been received. - virtual void OnUndecryptablePacket() {} + // Called when an undecryptable packet has been received. If |dropped| is + // true, the packet has been dropped. Otherwise, the packet will be queued and + // connection will attempt to process it later. + virtual void OnUndecryptablePacket(EncryptionLevel /*decryption_level*/, + bool /*dropped*/) {} + + // Called when attempting to process a previously undecryptable packet. + virtual void OnAttemptingToProcessUndecryptablePacket( + EncryptionLevel /*decryption_level*/) {} // Called when a duplicate packet has been received. virtual void OnDuplicatePacket(QuicPacketNumber /*packet_number*/) {} @@ -373,6 +384,12 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Sets connection parameters from the supplied |config|. void SetFromConfig(const QuicConfig& config); + // Apply |connection_options| for this connection. Unlike SetFromConfig, this + // can happen at anytime in the life of a connection. + // Note there is no guarantee that all options can be applied. Components will + // only apply cherrypicked options that make sense at the time of the call. + void ApplyConnectionOptions(const QuicTagVector& connection_options); + // Called by the session when sending connection state to the client. virtual void OnSendConnectionState( const CachedNetworkParameters& cached_network_params); @@ -571,7 +588,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection IsHandshake handshake) override; const QuicFrames MaybeBundleAckOpportunistically() override; char* GetPacketBuffer() override; - void OnSerializedPacket(SerializedPacket* packet) override; + void OnSerializedPacket(SerializedPacket packet) override; void OnUnrecoverableError(QuicErrorCode error, const std::string& error_details) override; @@ -954,7 +971,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Send a packet to the peer, and takes ownership of the packet if the packet // cannot be written immediately. - virtual void SendOrQueuePacket(SerializedPacket* packet); + virtual void SendOrQueuePacket(SerializedPacket packet); // Called after a packet is received from a new effective peer address and is // decrypted. Starts validation of effective peer's address change. Calls @@ -1053,6 +1070,19 @@ class QUIC_EXPORT_PRIVATE QuicConnection const QuicSocketAddress peer_address; }; + // UndecrytablePacket comprises a undecryptable packet and the its encryption + // level. + struct QUIC_EXPORT_PRIVATE UndecryptablePacket { + UndecryptablePacket(const QuicEncryptedPacket& packet, + EncryptionLevel encryption_level) + : packet(packet.Clone()), encryption_level(encryption_level) {} + + std::unique_ptr<QuicEncryptedPacket> packet; + // Currently, |encryption_level| is only used for logging and does not + // affect processing of the packet. + EncryptionLevel encryption_level; + }; + // Notifies the visitor of the close and marks the connection as disconnected. // Does not send a connection close frame to the peer. It should only be // called by CloseConnection or OnConnectionCloseFrame, OnPublicResetPacket, @@ -1102,7 +1132,8 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Queues |packet| in the hopes that it can be decrypted in the // future, when a new key is installed. - void QueueUndecryptablePacket(const QuicEncryptedPacket& packet); + void QueueUndecryptablePacket(const QuicEncryptedPacket& packet, + EncryptionLevel decryption_level); // Sends any packets which are a response to the last packet, including both // acks and pending writes if an ack opened the congestion window. @@ -1121,9 +1152,6 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Sets the retransmission alarm based on SentPacketManager. void SetRetransmissionAlarm(); - // Sets the path degrading alarm. - void SetPathDegradingAlarm(); - // Sets the MTU discovery alarm if necessary. // |sent_packet_number| is the recently sent packet number. void MaybeSetMtuAlarm(QuicPacketNumber sent_packet_number); @@ -1166,10 +1194,6 @@ class QUIC_EXPORT_PRIVATE QuicConnection // |acked_new_packet| is true if a previously-unacked packet was acked. void PostProcessAfterAckFrame(bool send_stop_waiting, bool acked_new_packet); - // Called when an ACK is received to set the path degrading alarm or - // retransmittable on wire alarm. - void MaybeSetPathDegradingAlarm(bool acked_new_packet); - // Updates the release time into the future. void UpdateReleaseTimeIntoFuture(); @@ -1195,6 +1219,9 @@ class QUIC_EXPORT_PRIVATE QuicConnection // and flags. void MaybeEnableMultiplePacketNumberSpacesSupport(); + // Called to update ACK timeout when an retransmittable frame has been parsed. + void MaybeUpdateAckTimeout(); + // Returns packet fate when trying to write a packet via WritePacket(). SerializedPacketFate DeterminePacketFate(bool is_mtu_discovery); @@ -1228,6 +1255,13 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Whether connection is limited by amplification factor. bool LimitedByAmplificationFactor() const; + // Called before sending a packet to get packet send time and to set the + // release time delay in |per_packet_options_|. Return the time when the + // packet is scheduled to be released(a.k.a send time), which is NOW + delay. + // Returns Now() and does not update release time delay if + // |supports_release_time_| is false. + QuicTime CalculatePacketSentTime(); + // We've got a packet write error, should we ignore it? // NOTE: This is not a const function - if return true, the max packet size is // reverted to a previous(smaller) value to avoid write errors in the future. @@ -1331,8 +1365,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection // established, but which could not be decrypted. We buffer these on // the assumption that they could not be processed because they were // sent with the INITIAL encryption and the CHLO message was lost. - QuicCircularDeque<std::unique_ptr<QuicEncryptedPacket>> - undecryptable_packets_; + QuicCircularDeque<UndecryptablePacket> undecryptable_packets_; // Collection of coalesced packets which were received while processing // the current packet. @@ -1357,9 +1390,8 @@ class QUIC_EXPORT_PRIVATE QuicConnection termination_packets_; // Determines whether or not a connection close packet is sent to the peer - // after idle timeout due to lack of network activity. - // This is particularly important on mobile, where waking up the radio is - // undesirable. + // after idle timeout due to lack of network activity. During the handshake, + // a connection close packet is sent, but not after. ConnectionCloseBehavior idle_timeout_connection_close_behavior_; // When true, close the QUIC connection after 5 RTOs. Due to the min rto of @@ -1409,10 +1441,6 @@ class QUIC_EXPORT_PRIVATE QuicConnection QuicArenaScopedPtr<QuicAlarm> ping_alarm_; // An alarm that fires when an MTU probe should be sent. QuicArenaScopedPtr<QuicAlarm> mtu_discovery_alarm_; - // An alarm that fires when this connection is considered degrading. - // TODO(fayang): Remove this when deprecating quic_use_blackhole_detector - // flag. - QuicArenaScopedPtr<QuicAlarm> path_degrading_alarm_; // An alarm that fires to process undecryptable packets when new decyrption // keys are available. QuicArenaScopedPtr<QuicAlarm> process_undecryptable_packets_alarm_; @@ -1435,13 +1463,20 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Timestamps used for timeouts. // The time of the first retransmittable packet that was sent after the most // recently received packet. - // TODO(fayang): Remove these two when deprecating - // quic_use_idle_network_detector. + // TODO(fayang): Remove time_of_first_packet_sent_after_receiving_ when + // deprecating quic_use_idle_network_detector. QuicTime time_of_first_packet_sent_after_receiving_; // The time that a packet is received for this connection. Initialized to // connection creation time. - // This is used for timeouts, and does not indicate the packet was processed. + // This does not indicate the packet was processed. QuicTime time_of_last_received_packet_; + // This gets set to time_of_last_received_packet_ when a packet gets + // decrypted. Please note, this is not necessarily the original receive time + // of this decrypt packet because connection can decryptable packet out of + // order. + // TODO(fayang): Remove time_of_last_decryptable_packet_ when + // deprecating quic_use_idle_network_detector. + QuicTime time_of_last_decryptable_packet_; // Sent packet manager which tracks the status of packets sent by this // connection and contains the send and receive algorithms to determine when @@ -1566,6 +1601,11 @@ class QUIC_EXPORT_PRIVATE QuicConnection // vector to improve performance since it is expected to be very small. std::vector<QuicConnectionId> incoming_connection_ids_; + // When we receive a RETRY packet, we replace |server_connection_id_| with the + // value from the RETRY packet and save off the original value of + // |server_connection_id_| into |original_connection_id_| for validation. + quiche::QuicheOptional<QuicConnectionId> original_connection_id_; + // Indicates whether received RETRY packets should be dropped. bool drop_incoming_retry_packets_; @@ -1604,12 +1644,14 @@ class QUIC_EXPORT_PRIVATE QuicConnection QuicIdleNetworkDetector idle_network_detector_; - const bool use_blackhole_detector_ = - GetQuicReloadableFlag(quic_use_blackhole_detector); - const bool use_idle_network_detector_ = - use_blackhole_detector_ && GetQuicReloadableFlag(quic_use_idle_network_detector); + + const bool extend_idle_time_on_decryptable_packets_ = + GetQuicReloadableFlag(quic_extend_idle_time_on_decryptable_packets); + + const bool advance_ack_timeout_update_ = + GetQuicReloadableFlag(quic_advance_ack_timeout_update); }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h b/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h index 911ea6dac75..3b0c85d2228 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h @@ -102,6 +102,9 @@ struct QUIC_EXPORT_PRIVATE QuicConnectionStats { // Maximum reordering observed in microseconds int64_t max_time_reordering_us = 0; + // Maximum sequence reordering observed from acked packets. + QuicPacketCount sent_packets_max_sequence_reordering = 0; + // The following stats are used only in TcpCubicSender. // The number of loss events from TCP's perspective. Each loss event includes // one or more lost packets. diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_connection_test.cc index e5faa3586da..24f233ef233 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_test.cc @@ -382,7 +382,8 @@ class TestPacketWriter : public QuicPacketWriter { ENCRYPTION_FORWARD_SECURE, std::make_unique<NullDecrypter>(Perspective::IS_SERVER)); } - EXPECT_TRUE(framer_.ProcessPacket(packet)); + EXPECT_TRUE(framer_.ProcessPacket(packet)) + << framer_.framer()->detailed_error(); if (block_on_next_write_) { write_blocked_ = true; block_on_next_write_ = false; @@ -673,7 +674,7 @@ class TestConnection : public QuicConnection { serialized_packet.retransmittable_frames.push_back( QuicFrame(QuicPingFrame())); } - OnSerializedPacket(&serialized_packet); + OnSerializedPacket(std::move(serialized_packet)); } QuicConsumedData SaveAndSendStreamData(QuicStreamId id, @@ -844,8 +845,7 @@ class TestConnection : public QuicConnection { } TestAlarmFactory::TestAlarm* GetTimeoutAlarm() { - if (GetQuicReloadableFlag(quic_use_blackhole_detector) && - GetQuicReloadableFlag(quic_use_idle_network_detector)) { + if (GetQuicReloadableFlag(quic_use_idle_network_detector)) { return reinterpret_cast<TestAlarmFactory::TestAlarm*>( QuicConnectionPeer::GetIdleNetworkDetectorAlarm(this)); } @@ -858,40 +858,26 @@ class TestConnection : public QuicConnection { QuicConnectionPeer::GetMtuDiscoveryAlarm(this)); } - TestAlarmFactory::TestAlarm* GetPathDegradingAlarm() { - return reinterpret_cast<TestAlarmFactory::TestAlarm*>( - QuicConnectionPeer::GetPathDegradingAlarm(this)); - } - TestAlarmFactory::TestAlarm* GetProcessUndecryptablePacketsAlarm() { return reinterpret_cast<TestAlarmFactory::TestAlarm*>( QuicConnectionPeer::GetProcessUndecryptablePacketsAlarm(this)); } TestAlarmFactory::TestAlarm* GetBlackholeDetectorAlarm() { - DCHECK(GetQuicReloadableFlag(quic_use_blackhole_detector)); return reinterpret_cast<TestAlarmFactory::TestAlarm*>( QuicConnectionPeer::GetBlackholeDetectorAlarm(this)); } void PathDegradingTimeout() { DCHECK(PathDegradingDetectionInProgress()); - if (GetQuicReloadableFlag(quic_use_blackhole_detector)) { - GetBlackholeDetectorAlarm()->Fire(); - } else { - GetPathDegradingAlarm()->Fire(); - } + GetBlackholeDetectorAlarm()->Fire(); } bool PathDegradingDetectionInProgress() { - if (GetQuicReloadableFlag(quic_use_blackhole_detector)) { - return QuicConnectionPeer::GetPathDegradingDeadline(this).IsInitialized(); - } - return GetPathDegradingAlarm()->IsSet(); + return QuicConnectionPeer::GetPathDegradingDeadline(this).IsInitialized(); } bool BlackholeDetectionInProgress() { - DCHECK(GetQuicReloadableFlag(quic_use_blackhole_detector)); return QuicConnectionPeer::GetBlackholeDetectionDeadline(this) .IsInitialized(); } @@ -915,7 +901,8 @@ class TestConnection : public QuicConnection { if (QuicConnectionPeer::GetSentPacketManager(this)->pto_enabled()) { // PTO mode is default enabled for T099. And TLP/RTO related tests are // stale. - DCHECK_EQ(PROTOCOL_TLS1_3, version().handshake_protocol); + DCHECK(PROTOCOL_TLS1_3 == version().handshake_protocol || + GetQuicReloadableFlag(quic_default_on_pto)); return true; } return false; @@ -1094,8 +1081,6 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { .WillRepeatedly(Return(kDefaultTCPMSS)); EXPECT_CALL(*send_algorithm_, PacingRate(_)) .WillRepeatedly(Return(QuicBandwidth::Zero())); - EXPECT_CALL(*send_algorithm_, HasReliableBandwidthEstimate()) - .Times(AnyNumber()); EXPECT_CALL(*send_algorithm_, BandwidthEstimate()) .Times(AnyNumber()) .WillRepeatedly(Return(QuicBandwidth::Zero())); @@ -1176,6 +1161,15 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { } } + QuicFrame MakeCryptoFrame() const { + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + return QuicFrame(new QuicCryptoFrame(crypto_frame_)); + } + return QuicFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, + 0u, quiche::QuicheStringPiece())); + } + void ProcessFramePacket(QuicFrame frame) { ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); } @@ -1522,7 +1516,7 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { return ConstructPacket(header, frames); } - OwningSerializedPacketPointer ConstructProbingPacket() { + std::unique_ptr<SerializedPacket> ConstructProbingPacket() { if (VersionHasIetfQuicFrames(version().transport_version)) { QuicPathFrameBuffer payload = { {0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xfe}}; @@ -1670,8 +1664,13 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { const std::vector<QuicConnectionCloseFrame>& connection_close_frames = writer_->connection_close_frames(); ASSERT_EQ(1u, connection_close_frames.size()); + + EXPECT_THAT(connection_close_frames[0].quic_error_code, + IsError(expected_code)); + if (!VersionHasIetfQuicFrames(version().transport_version)) { - EXPECT_EQ(expected_code, connection_close_frames[0].quic_error_code); + EXPECT_THAT(connection_close_frames[0].wire_error_code, + IsError(expected_code)); EXPECT_EQ(GOOGLE_QUIC_CONNECTION_CLOSE, connection_close_frames[0].close_type); return; @@ -1680,22 +1679,16 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { QuicErrorCodeToIetfMapping mapping = QuicErrorCodeToTransportErrorCode(expected_code); - if (mapping.is_transport_close_) { + if (mapping.is_transport_close) { // This Google QUIC Error Code maps to a transport close, EXPECT_EQ(IETF_QUIC_TRANSPORT_CONNECTION_CLOSE, connection_close_frames[0].close_type); - EXPECT_EQ(mapping.transport_error_code_, - connection_close_frames[0].transport_error_code); - // TODO(fkastenholz): when the extracted error code CL lands, - // need to test that extracted==expected. } else { // This maps to an application close. - EXPECT_EQ(expected_code, connection_close_frames[0].quic_error_code); EXPECT_EQ(IETF_QUIC_APPLICATION_CONNECTION_CLOSE, connection_close_frames[0].close_type); - // TODO(fkastenholz): when the extracted error code CL lands, - // need to test that extracted==expected. } + EXPECT_EQ(mapping.error_code, connection_close_frames[0].wire_error_code); } void MtuDiscoveryTestInit() { @@ -1719,6 +1712,10 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { EXPECT_TRUE(connection_.connected()); } + void TestClientRetryHandling(bool invalid_retry_tag, + bool missing_id_in_config, + bool wrong_id_in_config); + QuicConnectionId connection_id_; QuicFramer framer_; @@ -1752,7 +1749,7 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { }; // Run all end to end tests with all supported versions. -INSTANTIATE_TEST_SUITE_P(SupportedVersion, +INSTANTIATE_TEST_SUITE_P(QuicConnectionTests, QuicConnectionTest, ::testing::ValuesIn(GetTestParams()), ::testing::PrintToStringParamName()); @@ -1763,7 +1760,7 @@ INSTANTIATE_TEST_SUITE_P(SupportedVersion, // close, the second an application connection close. // The connection close codes for the two tests are manually chosen; // they are expected to always map to transport- and application- -// closes, respectively. If that changes, mew codes should be chosen. +// closes, respectively. If that changes, new codes should be chosen. TEST_P(QuicConnectionTest, CloseErrorCodeTestTransport) { EXPECT_TRUE(connection_.connected()); EXPECT_CALL(visitor_, OnConnectionClosed(_, _)); @@ -1793,17 +1790,13 @@ TEST_P(QuicConnectionTest, SelfAddressChangeAtClient) { EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective()); EXPECT_TRUE(connection_.connected()); - QuicFrame frame; if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { - frame = QuicFrame(&crypto_frame_); EXPECT_CALL(visitor_, OnCryptoFrame(_)); } else { - frame = QuicFrame(QuicStreamFrame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, - 0u, quiche::QuicheStringPiece())); EXPECT_CALL(visitor_, OnStreamFrame(_)); } - ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, + kPeerAddress); // Cause change in self_address. QuicIpAddress host; host.FromString("1.1.1.1"); @@ -1813,7 +1806,8 @@ TEST_P(QuicConnectionTest, SelfAddressChangeAtClient) { } else { EXPECT_CALL(visitor_, OnStreamFrame(_)); } - ProcessFramePacketWithAddresses(frame, self_address, kPeerAddress); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), self_address, + kPeerAddress); EXPECT_TRUE(connection_.connected()); } @@ -1824,24 +1818,21 @@ TEST_P(QuicConnectionTest, SelfAddressChangeAtServer) { EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective()); EXPECT_TRUE(connection_.connected()); - QuicFrame frame; if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { - frame = QuicFrame(&crypto_frame_); EXPECT_CALL(visitor_, OnCryptoFrame(_)); } else { - frame = QuicFrame(QuicStreamFrame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, - 0u, quiche::QuicheStringPiece())); EXPECT_CALL(visitor_, OnStreamFrame(_)); } - ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, + kPeerAddress); // Cause change in self_address. QuicIpAddress host; host.FromString("1.1.1.1"); QuicSocketAddress self_address(host, 123); EXPECT_CALL(visitor_, AllowSelfAddressChange()).WillOnce(Return(false)); EXPECT_CALL(visitor_, OnConnectionClosed(_, _)); - ProcessFramePacketWithAddresses(frame, self_address, kPeerAddress); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), self_address, + kPeerAddress); EXPECT_FALSE(connection_.connected()); TestConnectionCloseQuicErrorCode(QUIC_ERROR_MIGRATING_ADDRESS); } @@ -1853,29 +1844,27 @@ TEST_P(QuicConnectionTest, AllowSelfAddressChangeToMappedIpv4AddressAtServer) { EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective()); EXPECT_TRUE(connection_.connected()); - QuicFrame frame; if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { - frame = QuicFrame(&crypto_frame_); EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(3); } else { - frame = QuicFrame(QuicStreamFrame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, - 0u, quiche::QuicheStringPiece())); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(3); } QuicIpAddress host; host.FromString("1.1.1.1"); QuicSocketAddress self_address1(host, 443); - ProcessFramePacketWithAddresses(frame, self_address1, kPeerAddress); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), self_address1, + kPeerAddress); // Cause self_address change to mapped Ipv4 address. QuicIpAddress host2; host2.FromString(quiche::QuicheStrCat( "::ffff:", connection_.self_address().host().ToString())); QuicSocketAddress self_address2(host2, connection_.self_address().port()); - ProcessFramePacketWithAddresses(frame, self_address2, kPeerAddress); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), self_address2, + kPeerAddress); EXPECT_TRUE(connection_.connected()); // self_address change back to Ipv4 address. - ProcessFramePacketWithAddresses(frame, self_address1, kPeerAddress); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), self_address1, + kPeerAddress); EXPECT_TRUE(connection_.connected()); } @@ -1890,21 +1879,17 @@ TEST_P(QuicConnectionTest, ClientAddressChangeAndPacketReordered) { QuicConnectionPeer::SetEffectivePeerAddress(&connection_, QuicSocketAddress()); - QuicFrame frame; if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { - frame = QuicFrame(&crypto_frame_); EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); } else { - frame = QuicFrame(QuicStreamFrame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, - 0u, quiche::QuicheStringPiece())); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); } QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 5); const QuicSocketAddress kNewPeerAddress = QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456); - ProcessFramePacketWithAddresses(frame, kSelfAddress, kNewPeerAddress); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, + kNewPeerAddress); EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address()); @@ -1912,7 +1897,8 @@ TEST_P(QuicConnectionTest, ClientAddressChangeAndPacketReordered) { QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 4); // This is an old packet, do not migrate. EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0); - ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, + kPeerAddress); EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address()); } @@ -1930,17 +1916,13 @@ TEST_P(QuicConnectionTest, PeerAddressChangeAtServer) { QuicSocketAddress()); EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); - QuicFrame frame; if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { - frame = QuicFrame(&crypto_frame_); EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); } else { - frame = QuicFrame(QuicStreamFrame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, - 0u, quiche::QuicheStringPiece())); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); } - ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, + kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); @@ -1949,7 +1931,8 @@ TEST_P(QuicConnectionTest, PeerAddressChangeAtServer) { const QuicSocketAddress kNewPeerAddress = QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456); EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(1); - ProcessFramePacketWithAddresses(frame, kSelfAddress, kNewPeerAddress); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, + kNewPeerAddress); EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address()); } @@ -1969,17 +1952,13 @@ TEST_P(QuicConnectionTest, EffectivePeerAddressChangeAtServer) { QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/43210); connection_.ReturnEffectivePeerAddressForNextPacket(kEffectivePeerAddress); - QuicFrame frame; if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { - frame = QuicFrame(&crypto_frame_); EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); } else { - frame = QuicFrame(QuicStreamFrame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, - 0u, quiche::QuicheStringPiece())); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); } - ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, + kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kEffectivePeerAddress, connection_.effective_peer_address()); @@ -1989,7 +1968,8 @@ TEST_P(QuicConnectionTest, EffectivePeerAddressChangeAtServer) { QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/54321); connection_.ReturnEffectivePeerAddressForNextPacket(kNewEffectivePeerAddress); EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(1); - ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, + kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kNewEffectivePeerAddress, connection_.effective_peer_address()); @@ -2018,7 +1998,8 @@ TEST_P(QuicConnectionTest, EffectivePeerAddressChangeAtServer) { connection_.ReturnEffectivePeerAddressForNextPacket( kNewerEffectivePeerAddress); EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(1); - ProcessFramePacketWithAddresses(frame, kSelfAddress, kFinalPeerAddress); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, + kFinalPeerAddress); EXPECT_EQ(kFinalPeerAddress, connection_.peer_address()); EXPECT_EQ(kNewerEffectivePeerAddress, connection_.effective_peer_address()); EXPECT_EQ(PORT_CHANGE, connection_.active_effective_peer_migration_type()); @@ -2032,7 +2013,8 @@ TEST_P(QuicConnectionTest, EffectivePeerAddressChangeAtServer) { kNewestEffectivePeerAddress); EXPECT_CALL(visitor_, OnConnectionMigration(IPV6_TO_IPV4_CHANGE)).Times(1); EXPECT_CALL(*send_algorithm_, OnConnectionMigration()).Times(1); - ProcessFramePacketWithAddresses(frame, kSelfAddress, kFinalPeerAddress); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, + kFinalPeerAddress); EXPECT_EQ(kFinalPeerAddress, connection_.peer_address()); EXPECT_EQ(kNewestEffectivePeerAddress, connection_.effective_peer_address()); EXPECT_EQ(IPV6_TO_IPV4_CHANGE, @@ -2052,17 +2034,13 @@ TEST_P(QuicConnectionTest, ReceivePathProbeWithNoAddressChangeAtServer) { QuicSocketAddress()); EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); - QuicFrame frame; if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { - frame = QuicFrame(&crypto_frame_); EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); } else { - frame = QuicFrame(QuicStreamFrame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, - 0u, quiche::QuicheStringPiece())); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); } - ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, + kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); @@ -2071,7 +2049,7 @@ TEST_P(QuicConnectionTest, ReceivePathProbeWithNoAddressChangeAtServer) { // Process a padded PING or PATH CHALLENGE packet with no peer address change // on server side will be ignored. - OwningSerializedPacketPointer probing_packet = ConstructProbingPacket(); + std::unique_ptr<SerializedPacket> probing_packet = ConstructProbingPacket(); std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket( QuicEncryptedPacket(probing_packet->encrypted_buffer, @@ -2088,6 +2066,24 @@ TEST_P(QuicConnectionTest, ReceivePathProbeWithNoAddressChangeAtServer) { EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); } +// Regression test for b/150161358. +TEST_P(QuicConnectionTest, BufferedMtuPacketTooBig) { + if (!GetQuicReloadableFlag(quic_ignore_msg_too_big_from_buffered_packets)) { + return; + } + EXPECT_CALL(visitor_, OnWriteBlocked()).Times(1); + writer_->SetWriteBlocked(); + + // Send a MTU packet while blocked. It should be buffered. + connection_.SendMtuDiscoveryPacket(kMaxOutgoingPacketSize); + EXPECT_EQ(1u, connection_.NumQueuedPackets()); + EXPECT_TRUE(writer_->IsWriteBlocked()); + + writer_->AlwaysGetPacketTooLarge(); + writer_->SetWritable(); + connection_.OnCanWrite(); +} + TEST_P(QuicConnectionTest, WriteOutOfOrderQueuedPackets) { // EXPECT_QUIC_BUG tests are expensive so only run one instance of them. if (!IsDefaultTestConfiguration()) { @@ -2154,17 +2150,13 @@ TEST_P(QuicConnectionTest, ReceivePathProbingAtServer) { QuicSocketAddress()); EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); - QuicFrame frame; if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { - frame = QuicFrame(&crypto_frame_); EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); } else { - frame = QuicFrame(QuicStreamFrame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, - 0u, quiche::QuicheStringPiece())); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); } - ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, + kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); @@ -2181,7 +2173,7 @@ TEST_P(QuicConnectionTest, ReceivePathProbingAtServer) { const QuicSocketAddress kNewPeerAddress = QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456); - OwningSerializedPacketPointer probing_packet = ConstructProbingPacket(); + std::unique_ptr<SerializedPacket> probing_packet = ConstructProbingPacket(); std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket( QuicEncryptedPacket(probing_packet->encrypted_buffer, probing_packet->encrypted_length), @@ -2199,7 +2191,8 @@ TEST_P(QuicConnectionTest, ReceivePathProbingAtServer) { // Process another packet with the old peer address on server side will not // start peer migration. EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0); - ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, + kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); } @@ -2218,17 +2211,13 @@ TEST_P(QuicConnectionTest, ReceivePaddedPingWithPortChangeAtServer) { QuicSocketAddress()); EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); - QuicFrame frame; if (GetParam().version.UsesCryptoFrames()) { - frame = QuicFrame(&crypto_frame_); EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); } else { - frame = QuicFrame(QuicStreamFrame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, - 0u, quiche::QuicheStringPiece())); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); } - ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, + kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); @@ -2282,7 +2271,8 @@ TEST_P(QuicConnectionTest, ReceivePaddedPingWithPortChangeAtServer) { } else { EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0); } - ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, + kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); } @@ -2300,18 +2290,14 @@ TEST_P(QuicConnectionTest, ReceiveReorderedPathProbingAtServer) { QuicSocketAddress()); EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); - QuicFrame frame; if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { - frame = QuicFrame(&crypto_frame_); EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); } else { - frame = QuicFrame(QuicStreamFrame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, - 0u, quiche::QuicheStringPiece())); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); } QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 5); - ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, + kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); @@ -2333,7 +2319,7 @@ TEST_P(QuicConnectionTest, ReceiveReorderedPathProbingAtServer) { const QuicSocketAddress kNewPeerAddress = QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456); - OwningSerializedPacketPointer probing_packet = ConstructProbingPacket(); + std::unique_ptr<SerializedPacket> probing_packet = ConstructProbingPacket(); std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket( QuicEncryptedPacket(probing_packet->encrypted_buffer, probing_packet->encrypted_length), @@ -2362,17 +2348,13 @@ TEST_P(QuicConnectionTest, MigrateAfterProbingAtServer) { QuicSocketAddress()); EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); - QuicFrame frame; if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { - frame = QuicFrame(&crypto_frame_); EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); } else { - frame = QuicFrame(QuicStreamFrame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, - 0u, quiche::QuicheStringPiece())); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); } - ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, + kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); @@ -2390,7 +2372,7 @@ TEST_P(QuicConnectionTest, MigrateAfterProbingAtServer) { const QuicSocketAddress kNewPeerAddress = QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456); - OwningSerializedPacketPointer probing_packet = ConstructProbingPacket(); + std::unique_ptr<SerializedPacket> probing_packet = ConstructProbingPacket(); std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket( QuicEncryptedPacket(probing_packet->encrypted_buffer, probing_packet->encrypted_length), @@ -2403,7 +2385,8 @@ TEST_P(QuicConnectionTest, MigrateAfterProbingAtServer) { // side will start peer migration. EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(1); - ProcessFramePacketWithAddresses(frame, kSelfAddress, kNewPeerAddress); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, + kNewPeerAddress); EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address()); } @@ -2421,17 +2404,13 @@ TEST_P(QuicConnectionTest, ReceivePaddedPingAtClient) { QuicSocketAddress()); EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); - QuicFrame frame; if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { - frame = QuicFrame(&crypto_frame_); EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); } else { - frame = QuicFrame(QuicStreamFrame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, - 0u, quiche::QuicheStringPiece())); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); } - ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, + kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); @@ -2440,7 +2419,7 @@ TEST_P(QuicConnectionTest, ReceivePaddedPingAtClient) { EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0); EXPECT_CALL(visitor_, OnPacketReceived(_, _, false)).Times(1); - OwningSerializedPacketPointer probing_packet = ConstructProbingPacket(); + std::unique_ptr<SerializedPacket> probing_packet = ConstructProbingPacket(); std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket( QuicEncryptedPacket(probing_packet->encrypted_buffer, probing_packet->encrypted_length), @@ -2474,17 +2453,13 @@ TEST_P(QuicConnectionTest, ReceiveConnectivityProbingResponseAtClient) { QuicSocketAddress()); EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); - QuicFrame frame; if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { - frame = QuicFrame(&crypto_frame_); EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); } else { - frame = QuicFrame(QuicStreamFrame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, - 0u, quiche::QuicheStringPiece())); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); } - ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, + kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); @@ -2502,7 +2477,7 @@ TEST_P(QuicConnectionTest, ReceiveConnectivityProbingResponseAtClient) { const QuicSocketAddress kNewSelfAddress = QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456); - OwningSerializedPacketPointer probing_packet = ConstructProbingPacket(); + std::unique_ptr<SerializedPacket> probing_packet = ConstructProbingPacket(); std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket( QuicEncryptedPacket(probing_packet->encrypted_buffer, probing_packet->encrypted_length), @@ -2530,17 +2505,13 @@ TEST_P(QuicConnectionTest, PeerAddressChangeAtClient) { QuicSocketAddress()); EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); - QuicFrame frame; if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { - frame = QuicFrame(&crypto_frame_); EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); } else { - frame = QuicFrame(QuicStreamFrame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, - 0u, quiche::QuicheStringPiece())); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); } - ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, + kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); @@ -2549,7 +2520,8 @@ TEST_P(QuicConnectionTest, PeerAddressChangeAtClient) { const QuicSocketAddress kNewPeerAddress = QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456); EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0); - ProcessFramePacketWithAddresses(frame, kSelfAddress, kNewPeerAddress); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, + kNewPeerAddress); EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address()); } @@ -2866,7 +2838,8 @@ TEST_P(QuicConnectionTest, AckReceiptCausesAckSend) { LostPacketVector lost_packets; lost_packets.push_back(LostPacket(original, kMaxOutgoingPacketSize)); EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _)) - .WillOnce(SetArgPointee<5>(lost_packets)); + .WillOnce(DoAll(SetArgPointee<5>(lost_packets), + Return(LossDetectionInterface::DetectionStats()))); EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); QuicPacketNumber retransmission; // Packet 1 is short header for IETF QUIC because the encryption level @@ -3019,7 +2992,6 @@ TEST_P(QuicConnectionTest, AckNeedsRetransmittableFrames) { } TEST_P(QuicConnectionTest, AckNeedsRetransmittableFramesAfterPto) { - SetQuicReloadableFlag(quic_bundle_retransmittable_with_pto_ack, true); // Disable TLP so the RTO fires immediately. connection_.SetMaxTailLossProbes(0); EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); @@ -3587,7 +3559,8 @@ TEST_P(QuicConnectionTest, RetransmitOnNack) { lost_packets.push_back( LostPacket(QuicPacketNumber(2), kMaxOutgoingPacketSize)); EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _)) - .WillOnce(SetArgPointee<5>(lost_packets)); + .WillOnce(DoAll(SetArgPointee<5>(lost_packets), + Return(LossDetectionInterface::DetectionStats()))); EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); EXPECT_FALSE(QuicPacketCreatorPeer::SendVersionInPacket(creator_)); @@ -3669,7 +3642,8 @@ TEST_P(QuicConnectionTest, RetransmitForQuicRstStreamNoErrorOnNack) { LostPacketVector lost_packets; lost_packets.push_back(LostPacket(last_packet - 1, kMaxOutgoingPacketSize)); EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _)) - .WillOnce(SetArgPointee<5>(lost_packets)); + .WillOnce(DoAll(SetArgPointee<5>(lost_packets), + Return(LossDetectionInterface::DetectionStats()))); EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1)); ProcessAckPacket(&nack_two); @@ -3789,7 +3763,8 @@ TEST_P(QuicConnectionTest, SendPendingRetransmissionForQuicRstStreamNoError) { LostPacketVector lost_packets; lost_packets.push_back(LostPacket(last_packet - 1, kMaxOutgoingPacketSize)); EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _)) - .WillOnce(SetArgPointee<5>(lost_packets)); + .WillOnce(DoAll(SetArgPointee<5>(lost_packets), + Return(LossDetectionInterface::DetectionStats()))); EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); ProcessAckPacket(&ack); @@ -3828,7 +3803,8 @@ TEST_P(QuicConnectionTest, RetransmitAckedPacket) { lost_packets.push_back( LostPacket(QuicPacketNumber(2), kMaxOutgoingPacketSize)); EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _)) - .WillOnce(SetArgPointee<5>(lost_packets)); + .WillOnce(DoAll(SetArgPointee<5>(lost_packets), + Return(LossDetectionInterface::DetectionStats()))); EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(4), _, _)) .Times(1); @@ -3865,7 +3841,8 @@ TEST_P(QuicConnectionTest, RetransmitNackedLargestObserved) { LostPacketVector lost_packets; lost_packets.push_back(LostPacket(original, kMaxOutgoingPacketSize)); EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _)) - .WillOnce(SetArgPointee<5>(lost_packets)); + .WillOnce(DoAll(SetArgPointee<5>(lost_packets), + Return(LossDetectionInterface::DetectionStats()))); EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); // Packet 1 is short header for IETF QUIC because the encryption level // switched to ENCRYPTION_FORWARD_SECURE in SendStreamDataToPeer. @@ -3960,8 +3937,10 @@ TEST_P(QuicConnectionTest, RetransmitWriteBlockedAckedOriginalThenSent) { writer_->SetWritable(); connection_.OnCanWrite(); EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet()); - const uint64_t retransmission = - connection_.SupportsMultiplePacketNumberSpaces() ? 3 : 2; + uint64_t retransmission = connection_.SupportsMultiplePacketNumberSpaces() && + !GetQuicReloadableFlag(quic_default_on_pto) + ? 3 + : 2; EXPECT_FALSE(QuicConnectionPeer::HasRetransmittableFrames(&connection_, retransmission)); } @@ -4082,7 +4061,8 @@ TEST_P(QuicConnectionTest, NoLimitPacketsPerNack) { LostPacket(QuicPacketNumber(i), kMaxOutgoingPacketSize)); } EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _)) - .WillOnce(SetArgPointee<5>(lost_packets)); + .WillOnce(DoAll(SetArgPointee<5>(lost_packets), + Return(LossDetectionInterface::DetectionStats()))); EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); ProcessAckPacket(&nack); @@ -4190,6 +4170,9 @@ TEST_P(QuicConnectionTest, DontLatchUnackedPacket) { } TEST_P(QuicConnectionTest, TLP) { + if (connection_.PtoEnabled()) { + return; + } connection_.SetMaxTailLossProbes(1); SendStreamDataToPeer(3, "foo", 0, NO_FIN, nullptr); @@ -4257,8 +4240,7 @@ TEST_P(QuicConnectionTest, TailLossProbeDelayForNonStreamDataInTLPR) { QuicTagVector options; options.push_back(kTLPR); config.SetConnectionOptionsToSend(options); - QuicConfigPeer::ReceiveIdleNetworkTimeout(&config, SERVER, - kDefaultIdleTimeoutSecs); + QuicConfigPeer::SetNegotiated(&config, true); connection_.SetFromConfig(config); connection_.SetMaxTailLossProbes(1); @@ -4795,8 +4777,7 @@ TEST_P(QuicConnectionTest, IdleTimeoutAfterFirstSentPacket) { EXPECT_CALL(visitor_, OnConnectionClosed(_, _)).Times(0); QuicTime::Delta delay = initial_ddl - clock_.ApproximateNow(); clock_.AdvanceTime(delay); - if (!GetQuicReloadableFlag(quic_use_blackhole_detector) || - !GetQuicReloadableFlag(quic_use_idle_network_detector)) { + if (!GetQuicReloadableFlag(quic_use_idle_network_detector)) { connection_.GetTimeoutAlarm()->Fire(); } // Verify the timeout alarm deadline is updated. @@ -4887,8 +4868,7 @@ TEST_P(QuicConnectionTest, HandshakeTimeout) { EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); ProcessAckPacket(&frame); - if (!GetQuicReloadableFlag(quic_use_blackhole_detector) || - !GetQuicReloadableFlag(quic_use_idle_network_detector)) { + if (!GetQuicReloadableFlag(quic_use_idle_network_detector)) { // Fire early to verify it wouldn't timeout yet. connection_.GetTimeoutAlarm()->Fire(); } @@ -5167,23 +5147,21 @@ TEST_P(QuicConnectionTest, MtuDiscoveryEnabled) { // The last probe size should be equal to the target. EXPECT_EQ(probe_size, kMtuDiscoveryTargetPacketSizeHigh); - if (GetQuicReloadableFlag(quic_ignore_one_write_error_after_mtu_probe)) { - writer_->SetShouldWriteFail(); + writer_->SetShouldWriteFail(); - // Ignore PACKET_WRITE_ERROR once. - SendStreamDataToPeer(3, "(", stream_offset++, NO_FIN, nullptr); - EXPECT_EQ(last_probe_size, connection_.max_packet_length()); - EXPECT_TRUE(connection_.connected()); + // Ignore PACKET_WRITE_ERROR once. + SendStreamDataToPeer(3, "(", stream_offset++, NO_FIN, nullptr); + EXPECT_EQ(last_probe_size, connection_.max_packet_length()); + EXPECT_TRUE(connection_.connected()); - // Close connection on another PACKET_WRITE_ERROR. - EXPECT_CALL(visitor_, OnConnectionClosed(_, _)) - .WillOnce(Invoke(this, &QuicConnectionTest::SaveConnectionCloseFrame)); - SendStreamDataToPeer(3, ")", stream_offset++, NO_FIN, nullptr); - EXPECT_EQ(last_probe_size, connection_.max_packet_length()); - EXPECT_FALSE(connection_.connected()); - EXPECT_THAT(saved_connection_close_frame_.quic_error_code, - IsError(QUIC_PACKET_WRITE_ERROR)); - } + // Close connection on another PACKET_WRITE_ERROR. + EXPECT_CALL(visitor_, OnConnectionClosed(_, _)) + .WillOnce(Invoke(this, &QuicConnectionTest::SaveConnectionCloseFrame)); + SendStreamDataToPeer(3, ")", stream_offset++, NO_FIN, nullptr); + EXPECT_EQ(last_probe_size, connection_.max_packet_length()); + EXPECT_FALSE(connection_.connected()); + EXPECT_THAT(saved_connection_close_frame_.quic_error_code, + IsError(QUIC_PACKET_WRITE_ERROR)); } // After a successful MTU probe, one and only one write error should be ignored @@ -5232,31 +5210,29 @@ TEST_P(QuicConnectionTest, EXPECT_EQ(1u, connection_.mtu_probe_count()); - if (GetQuicReloadableFlag(quic_ignore_one_write_error_after_mtu_probe)) { - writer_->SetShouldWriteFail(); + writer_->SetShouldWriteFail(); - // Ignore PACKET_WRITE_ERROR once. - { - QuicConnection::ScopedPacketFlusher flusher(&connection_); - // flusher's destructor will call connection_.FlushPackets, which should - // get a WRITE_STATUS_ERROR from the writer and ignore it. - } - EXPECT_EQ(original_max_packet_length, connection_.max_packet_length()); - EXPECT_TRUE(connection_.connected()); + // Ignore PACKET_WRITE_ERROR once. + { + QuicConnection::ScopedPacketFlusher flusher(&connection_); + // flusher's destructor will call connection_.FlushPackets, which should + // get a WRITE_STATUS_ERROR from the writer and ignore it. + } + EXPECT_EQ(original_max_packet_length, connection_.max_packet_length()); + EXPECT_TRUE(connection_.connected()); - // Close connection on another PACKET_WRITE_ERROR. - EXPECT_CALL(visitor_, OnConnectionClosed(_, _)) - .WillOnce(Invoke(this, &QuicConnectionTest::SaveConnectionCloseFrame)); - { - QuicConnection::ScopedPacketFlusher flusher(&connection_); - // flusher's destructor will call connection_.FlushPackets, which should - // get a WRITE_STATUS_ERROR from the writer and ignore it. - } - EXPECT_EQ(original_max_packet_length, connection_.max_packet_length()); - EXPECT_FALSE(connection_.connected()); - EXPECT_THAT(saved_connection_close_frame_.quic_error_code, - IsError(QUIC_PACKET_WRITE_ERROR)); + // Close connection on another PACKET_WRITE_ERROR. + EXPECT_CALL(visitor_, OnConnectionClosed(_, _)) + .WillOnce(Invoke(this, &QuicConnectionTest::SaveConnectionCloseFrame)); + { + QuicConnection::ScopedPacketFlusher flusher(&connection_); + // flusher's destructor will call connection_.FlushPackets, which should + // get a WRITE_STATUS_ERROR from the writer and ignore it. } + EXPECT_EQ(original_max_packet_length, connection_.max_packet_length()); + EXPECT_FALSE(connection_.connected()); + EXPECT_THAT(saved_connection_close_frame_.quic_error_code, + IsError(QUIC_PACKET_WRITE_ERROR)); } // Simulate the case where the first attempt to send a probe is write blocked, @@ -5620,12 +5596,11 @@ TEST_P(QuicConnectionTest, NoMtuDiscoveryAfterConnectionClosed) { EXPECT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet()); } -TEST_P(QuicConnectionTest, TimeoutAfterSend) { +TEST_P(QuicConnectionTest, TimeoutAfterSendDuringHandshake) { EXPECT_TRUE(connection_.connected()); EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); QuicConfig config; connection_.SetFromConfig(config); - EXPECT_FALSE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_)); const QuicTime::Delta initial_idle_timeout = QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs - 1); @@ -5638,8 +5613,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterSend) { SendStreamDataToPeer( GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo", 0, FIN, nullptr); - if (GetQuicReloadableFlag(quic_use_blackhole_detector) && - GetQuicReloadableFlag(quic_use_idle_network_detector)) { + if (GetQuicReloadableFlag(quic_use_idle_network_detector)) { EXPECT_EQ(default_timeout + five_ms, connection_.GetTimeoutAlarm()->deadline()); } else { @@ -5652,8 +5626,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterSend) { SendStreamDataToPeer( GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo", 3, FIN, nullptr); - if (GetQuicReloadableFlag(quic_use_blackhole_detector) && - GetQuicReloadableFlag(quic_use_idle_network_detector)) { + if (GetQuicReloadableFlag(quic_use_idle_network_detector)) { EXPECT_EQ(default_timeout + five_ms, connection_.GetTimeoutAlarm()->deadline()); } else { @@ -5664,8 +5637,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterSend) { // network event at t=5ms. The alarm will reregister. clock_.AdvanceTime(initial_idle_timeout - five_ms - five_ms); EXPECT_EQ(default_timeout, clock_.ApproximateNow()); - if (!GetQuicReloadableFlag(quic_use_blackhole_detector) || - !GetQuicReloadableFlag(quic_use_idle_network_detector)) { + if (!GetQuicReloadableFlag(quic_use_idle_network_detector)) { connection_.GetTimeoutAlarm()->Fire(); } EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet()); @@ -5694,7 +5666,6 @@ TEST_P(QuicConnectionTest, TimeoutAfterRetransmission) { EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); QuicConfig config; connection_.SetFromConfig(config); - EXPECT_FALSE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_)); const QuicTime start_time = clock_.Now(); const QuicTime::Delta initial_idle_timeout = @@ -5716,8 +5687,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterRetransmission) { SendStreamDataToPeer( GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo", 0, FIN, nullptr); - if (GetQuicReloadableFlag(quic_use_blackhole_detector) && - GetQuicReloadableFlag(quic_use_idle_network_detector)) { + if (GetQuicReloadableFlag(quic_use_idle_network_detector)) { EXPECT_EQ(default_timeout + five_ms, connection_.GetTimeoutAlarm()->deadline()); } else { @@ -5751,8 +5721,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterRetransmission) { ASSERT_EQ(default_timeout.ToDebuggingValue(), clock_.Now().ToDebuggingValue()); EXPECT_EQ(default_timeout, clock_.Now()); - if (!GetQuicReloadableFlag(quic_use_blackhole_detector) || - !GetQuicReloadableFlag(quic_use_idle_network_detector)) { + if (!GetQuicReloadableFlag(quic_use_idle_network_detector)) { connection_.GetTimeoutAlarm()->Fire(); } EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet()); @@ -5773,9 +5742,9 @@ TEST_P(QuicConnectionTest, TimeoutAfterRetransmission) { TestConnectionCloseQuicErrorCode(QUIC_NETWORK_IDLE_TIMEOUT); } -TEST_P(QuicConnectionTest, NewTimeoutAfterSendSilentClose) { - // Same test as above, but complete a handshake which enables silent close, - // causing no connection close packet to be sent. +TEST_P(QuicConnectionTest, TimeoutAfterSendAfterHandshake) { + // When the idle timeout fires, verify that by default we do not send any + // connection close packets. EXPECT_TRUE(connection_.connected()); EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); QuicConfig config; @@ -5789,18 +5758,16 @@ TEST_P(QuicConnectionTest, NewTimeoutAfterSendSilentClose) { client_config.SetInitialSessionFlowControlWindowToSend( kInitialSessionFlowControlWindowForTest); client_config.SetIdleNetworkTimeout( - QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs), - QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs)); + QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs)); client_config.ToHandshakeMessage(&msg, connection_.transport_version()); const QuicErrorCode error = config.ProcessPeerHello(msg, CLIENT, &error_details); EXPECT_THAT(error, IsQuicNoError()); connection_.SetFromConfig(config); - EXPECT_TRUE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_)); const QuicTime::Delta default_idle_timeout = - QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs - 1); + QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs - 1); const QuicTime::Delta five_ms = QuicTime::Delta::FromMilliseconds(5); QuicTime default_timeout = clock_.ApproximateNow() + default_idle_timeout; @@ -5810,8 +5777,7 @@ TEST_P(QuicConnectionTest, NewTimeoutAfterSendSilentClose) { SendStreamDataToPeer( GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo", 0, FIN, nullptr); - if (GetQuicReloadableFlag(quic_use_blackhole_detector) && - GetQuicReloadableFlag(quic_use_idle_network_detector)) { + if (GetQuicReloadableFlag(quic_use_idle_network_detector)) { EXPECT_EQ(default_timeout + five_ms, connection_.GetTimeoutAlarm()->deadline()); } else { @@ -5824,8 +5790,7 @@ TEST_P(QuicConnectionTest, NewTimeoutAfterSendSilentClose) { SendStreamDataToPeer( GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo", 3, FIN, nullptr); - if (GetQuicReloadableFlag(quic_use_blackhole_detector) && - GetQuicReloadableFlag(quic_use_idle_network_detector)) { + if (GetQuicReloadableFlag(quic_use_idle_network_detector)) { EXPECT_EQ(default_timeout + five_ms, connection_.GetTimeoutAlarm()->deadline()); } else { @@ -5836,8 +5801,7 @@ TEST_P(QuicConnectionTest, NewTimeoutAfterSendSilentClose) { // network event at t=5ms. The alarm will reregister. clock_.AdvanceTime(default_idle_timeout - five_ms - five_ms); EXPECT_EQ(default_timeout, clock_.ApproximateNow()); - if (!GetQuicReloadableFlag(quic_use_blackhole_detector) || - !GetQuicReloadableFlag(quic_use_idle_network_detector)) { + if (!GetQuicReloadableFlag(quic_use_idle_network_detector)) { connection_.GetTimeoutAlarm()->Fire(); } EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet()); @@ -5866,8 +5830,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseAndTLP) { if (connection_.PtoEnabled()) { return; } - // Same test as above, but complete a handshake which enables silent close, - // but sending TLPs causes the connection close to be sent. + // Same test as above, but sending TLPs causes a connection close to be sent. EXPECT_TRUE(connection_.connected()); EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); QuicConfig config; @@ -5881,18 +5844,16 @@ TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseAndTLP) { client_config.SetInitialSessionFlowControlWindowToSend( kInitialSessionFlowControlWindowForTest); client_config.SetIdleNetworkTimeout( - QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs), - QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs)); + QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs)); client_config.ToHandshakeMessage(&msg, connection_.transport_version()); const QuicErrorCode error = config.ProcessPeerHello(msg, CLIENT, &error_details); EXPECT_THAT(error, IsQuicNoError()); connection_.SetFromConfig(config); - EXPECT_TRUE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_)); const QuicTime::Delta default_idle_timeout = - QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs - 1); + QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs - 1); const QuicTime::Delta five_ms = QuicTime::Delta::FromMilliseconds(5); QuicTime default_timeout = clock_.ApproximateNow() + default_idle_timeout; @@ -5902,8 +5863,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseAndTLP) { SendStreamDataToPeer( GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo", 0, FIN, nullptr); - if (GetQuicReloadableFlag(quic_use_blackhole_detector) && - GetQuicReloadableFlag(quic_use_idle_network_detector)) { + if (GetQuicReloadableFlag(quic_use_idle_network_detector)) { EXPECT_EQ(default_timeout + five_ms, connection_.GetTimeoutAlarm()->deadline()); } else { @@ -5929,8 +5889,8 @@ TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseAndTLP) { } TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseWithOpenStreams) { - // Same test as above, but complete a handshake which enables silent close, - // but having open streams causes the connection close to be sent. + // Same test as above, but having open streams causes a connection close + // to be sent. EXPECT_TRUE(connection_.connected()); EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); QuicConfig config; @@ -5944,18 +5904,16 @@ TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseWithOpenStreams) { client_config.SetInitialSessionFlowControlWindowToSend( kInitialSessionFlowControlWindowForTest); client_config.SetIdleNetworkTimeout( - QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs), - QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs)); + QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs)); client_config.ToHandshakeMessage(&msg, connection_.transport_version()); const QuicErrorCode error = config.ProcessPeerHello(msg, CLIENT, &error_details); EXPECT_THAT(error, IsQuicNoError()); connection_.SetFromConfig(config); - EXPECT_TRUE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_)); const QuicTime::Delta default_idle_timeout = - QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs - 1); + QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs - 1); const QuicTime::Delta five_ms = QuicTime::Delta::FromMilliseconds(5); QuicTime default_timeout = clock_.ApproximateNow() + default_idle_timeout; @@ -5965,8 +5923,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseWithOpenStreams) { SendStreamDataToPeer( GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo", 0, FIN, nullptr); - if (GetQuicReloadableFlag(quic_use_blackhole_detector) && - GetQuicReloadableFlag(quic_use_idle_network_detector)) { + if (GetQuicReloadableFlag(quic_use_idle_network_detector)) { EXPECT_EQ(default_timeout + five_ms, connection_.GetTimeoutAlarm()->deadline()); } else { @@ -5995,7 +5952,6 @@ TEST_P(QuicConnectionTest, TimeoutAfterReceive) { EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); QuicConfig config; connection_.SetFromConfig(config); - EXPECT_FALSE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_)); const QuicTime::Delta initial_idle_timeout = QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs - 1); @@ -6022,8 +5978,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterReceive) { // network event at t=5ms. The alarm will reregister. clock_.AdvanceTime(initial_idle_timeout - five_ms); EXPECT_EQ(default_timeout, clock_.ApproximateNow()); - if (!GetQuicReloadableFlag(quic_use_blackhole_detector) || - !GetQuicReloadableFlag(quic_use_idle_network_detector)) { + if (!GetQuicReloadableFlag(quic_use_idle_network_detector)) { connection_.GetTimeoutAlarm()->Fire(); } EXPECT_TRUE(connection_.connected()); @@ -6049,7 +6004,6 @@ TEST_P(QuicConnectionTest, TimeoutAfterReceiveNotSendWhenUnacked) { EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); QuicConfig config; connection_.SetFromConfig(config); - EXPECT_FALSE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_)); const QuicTime::Delta initial_idle_timeout = QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs - 1); @@ -6082,8 +6036,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterReceiveNotSendWhenUnacked) { // network event at t=5ms. The alarm will reregister. clock_.AdvanceTime(initial_idle_timeout - five_ms); EXPECT_EQ(default_timeout, clock_.ApproximateNow()); - if (!GetQuicReloadableFlag(quic_use_blackhole_detector) || - !GetQuicReloadableFlag(quic_use_idle_network_detector)) { + if (!GetQuicReloadableFlag(quic_use_idle_network_detector)) { connection_.GetTimeoutAlarm()->Fire(); } EXPECT_TRUE(connection_.connected()); @@ -6120,8 +6073,7 @@ TEST_P(QuicConnectionTest, TimeoutAfter5ClientRTOs) { QuicTagVector connection_options; connection_options.push_back(k5RTO); config.SetConnectionOptionsToSend(connection_options); - QuicConfigPeer::ReceiveIdleNetworkTimeout(&config, SERVER, - kDefaultIdleTimeoutSecs); + QuicConfigPeer::SetNegotiated(&config, true); connection_.SetFromConfig(config); // Send stream data. @@ -6136,10 +6088,8 @@ TEST_P(QuicConnectionTest, TimeoutAfter5ClientRTOs) { EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet()); EXPECT_TRUE(connection_.connected()); } - if (GetQuicReloadableFlag(quic_use_blackhole_detector)) { - EXPECT_CALL(visitor_, OnPathDegrading()); - connection_.PathDegradingTimeout(); - } + EXPECT_CALL(visitor_, OnPathDegrading()); + connection_.PathDegradingTimeout(); EXPECT_EQ(2u, connection_.sent_packet_manager().GetConsecutiveTlpCount()); EXPECT_EQ(4u, connection_.sent_packet_manager().GetConsecutiveRtoCount()); @@ -6147,12 +6097,8 @@ TEST_P(QuicConnectionTest, TimeoutAfter5ClientRTOs) { EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF)); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1)); - if (GetQuicReloadableFlag(quic_use_blackhole_detector)) { - ASSERT_TRUE(connection_.BlackholeDetectionInProgress()); - connection_.GetBlackholeDetectorAlarm()->Fire(); - } else { - connection_.GetRetransmissionAlarm()->Fire(); - } + ASSERT_TRUE(connection_.BlackholeDetectionInProgress()); + connection_.GetBlackholeDetectorAlarm()->Fire(); EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet()); EXPECT_FALSE(connection_.connected()); TestConnectionCloseQuicErrorCode(QUIC_TOO_MANY_RTOS); @@ -7207,7 +7153,8 @@ TEST_P(QuicConnectionTest, BundleAckWithDataOnIncomingAck) { lost_packets.push_back( LostPacket(QuicPacketNumber(1), kMaxOutgoingPacketSize)); EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _)) - .WillOnce(SetArgPointee<5>(lost_packets)); + .WillOnce(DoAll(SetArgPointee<5>(lost_packets), + Return(LossDetectionInterface::DetectionStats()))); EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); ProcessAckPacket(&ack); size_t padding_frame_count = writer_->padding_frames().size(); @@ -7425,31 +7372,31 @@ TEST_P(QuicConnectionTest, GoAway) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - QuicGoAwayFrame goaway; - goaway.last_good_stream_id = 1; - goaway.error_code = QUIC_PEER_GOING_AWAY; - goaway.reason_phrase = "Going away."; + QuicGoAwayFrame* goaway = new QuicGoAwayFrame(); + goaway->last_good_stream_id = 1; + goaway->error_code = QUIC_PEER_GOING_AWAY; + goaway->reason_phrase = "Going away."; EXPECT_CALL(visitor_, OnGoAway(_)); - ProcessGoAwayPacket(&goaway); + ProcessGoAwayPacket(goaway); } TEST_P(QuicConnectionTest, WindowUpdate) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - QuicWindowUpdateFrame window_update; - window_update.stream_id = 3; - window_update.max_data = 1234; + QuicWindowUpdateFrame* window_update = new QuicWindowUpdateFrame(); + window_update->stream_id = 3; + window_update->max_data = 1234; EXPECT_CALL(visitor_, OnWindowUpdateFrame(_)); - ProcessFramePacket(QuicFrame(&window_update)); + ProcessFramePacket(QuicFrame(window_update)); } TEST_P(QuicConnectionTest, Blocked) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - QuicBlockedFrame blocked; - blocked.stream_id = 3; + QuicBlockedFrame* blocked = new QuicBlockedFrame(); + blocked->stream_id = 3; EXPECT_CALL(visitor_, OnBlockedFrame(_)); - ProcessFramePacket(QuicFrame(&blocked)); + ProcessFramePacket(QuicFrame(blocked)); EXPECT_EQ(1u, connection_.GetStats().blocked_frames_received); EXPECT_EQ(0u, connection_.GetStats().blocked_frames_sent); } @@ -7552,7 +7499,8 @@ TEST_P(QuicConnectionTest, CheckSendStats) { lost_packets.push_back( LostPacket(QuicPacketNumber(3), kMaxOutgoingPacketSize)); EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _)) - .WillOnce(SetArgPointee<5>(lost_packets)); + .WillOnce(DoAll(SetArgPointee<5>(lost_packets), + Return(LossDetectionInterface::DetectionStats()))); EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); ProcessAckPacket(&nack_three); @@ -7621,7 +7569,7 @@ TEST_P(QuicConnectionTest, ProcessFramesIfPacketClosedConnection) { kSelfAddress, kPeerAddress, QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false)); EXPECT_EQ(1, connection_close_frame_count_); - EXPECT_THAT(saved_connection_close_frame_.extracted_error_code, + EXPECT_THAT(saved_connection_close_frame_.quic_error_code, IsError(QUIC_PEER_GOING_AWAY)); } @@ -7726,11 +7674,11 @@ TEST_P(QuicConnectionTest, WindowUpdateInstigateAcks) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); // Send a WINDOW_UPDATE frame. - QuicWindowUpdateFrame window_update; - window_update.stream_id = 3; - window_update.max_data = 1234; + QuicWindowUpdateFrame* window_update = new QuicWindowUpdateFrame(); + window_update->stream_id = 3; + window_update->max_data = 1234; EXPECT_CALL(visitor_, OnWindowUpdateFrame(_)); - ProcessFramePacket(QuicFrame(&window_update)); + ProcessFramePacket(QuicFrame(window_update)); // Ensure that this has caused the ACK alarm to be set. QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_); @@ -7741,10 +7689,10 @@ TEST_P(QuicConnectionTest, BlockedFrameInstigateAcks) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); // Send a BLOCKED frame. - QuicBlockedFrame blocked; - blocked.stream_id = 3; + QuicBlockedFrame* blocked = new QuicBlockedFrame(); + blocked->stream_id = 3; EXPECT_CALL(visitor_, OnBlockedFrame(_)); - ProcessFramePacket(QuicFrame(&blocked)); + ProcessFramePacket(QuicFrame(blocked)); // Ensure that this has caused the ACK alarm to be set. QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_); @@ -7902,13 +7850,8 @@ TEST_P(QuicConnectionTest, PathDegradingAlarmForCryptoPacket) { EXPECT_FALSE(connection_.IsPathDegrading()); QuicTime::Delta delay = QuicConnectionPeer::GetSentPacketManager(&connection_) ->GetPathDegradingDelay(); - if (GetQuicReloadableFlag(quic_use_blackhole_detector)) { - EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() - - clock_.ApproximateNow()); - } else { - EXPECT_EQ(delay, connection_.GetPathDegradingAlarm()->deadline() - - clock_.ApproximateNow()); - } + EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() - + clock_.ApproximateNow()); // Fire the path degrading alarm, path degrading signal should be sent to // the visitor. @@ -7941,33 +7884,22 @@ TEST_P(QuicConnectionTest, PathDegradingAlarmForNonCryptoPackets) { QuicTime::Delta delay = QuicConnectionPeer::GetSentPacketManager(&connection_) ->GetPathDegradingDelay(); - if (GetQuicReloadableFlag(quic_use_blackhole_detector)) { - EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() - - clock_.ApproximateNow()); - } else { - EXPECT_EQ(delay, connection_.GetPathDegradingAlarm()->deadline() - - clock_.ApproximateNow()); - } + EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() - + clock_.ApproximateNow()); // Send a second packet. The path degrading alarm's deadline should remain // the same. // Regression test for b/69979024. clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); - QuicTime prev_deadline = connection_.GetPathDegradingAlarm()->deadline(); - if (GetQuicReloadableFlag(quic_use_blackhole_detector)) { - prev_deadline = connection_.GetBlackholeDetectorAlarm()->deadline(); - } + QuicTime prev_deadline = + connection_.GetBlackholeDetectorAlarm()->deadline(); connection_.SendStreamDataWithString( GetNthClientInitiatedStreamId(1, connection_.transport_version()), data, offset, NO_FIN); offset += data_size; EXPECT_TRUE(connection_.PathDegradingDetectionInProgress()); - if (GetQuicReloadableFlag(quic_use_blackhole_detector)) { - EXPECT_EQ(prev_deadline, - connection_.GetBlackholeDetectorAlarm()->deadline()); - } else { - EXPECT_EQ(prev_deadline, connection_.GetPathDegradingAlarm()->deadline()); - } + EXPECT_EQ(prev_deadline, + connection_.GetBlackholeDetectorAlarm()->deadline()); // Now receive an ACK of the first packet. This should advance the path // degrading alarm's deadline since forward progress has been made. @@ -7983,13 +7915,8 @@ TEST_P(QuicConnectionTest, PathDegradingAlarmForNonCryptoPackets) { // Check the deadline of the path degrading alarm. delay = QuicConnectionPeer::GetSentPacketManager(&connection_) ->GetPathDegradingDelay(); - if (GetQuicReloadableFlag(quic_use_blackhole_detector)) { - EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() - - clock_.ApproximateNow()); - } else { - EXPECT_EQ(delay, connection_.GetPathDegradingAlarm()->deadline() - - clock_.ApproximateNow()); - } + EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() - + clock_.ApproximateNow()); if (i == 0) { // Now receive an ACK of the second packet. Since there are no more @@ -8039,13 +7966,8 @@ TEST_P(QuicConnectionTest, RetransmittableOnWireSetsPingAlarm) { EXPECT_TRUE(connection_.PathDegradingDetectionInProgress()); QuicTime::Delta delay = QuicConnectionPeer::GetSentPacketManager(&connection_) ->GetPathDegradingDelay(); - if (GetQuicReloadableFlag(quic_use_blackhole_detector)) { - EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() - - clock_.ApproximateNow()); - } else { - EXPECT_EQ(delay, connection_.GetPathDegradingAlarm()->deadline() - - clock_.ApproximateNow()); - } + EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() - + clock_.ApproximateNow()); ASSERT_TRUE(connection_.sent_packet_manager().HasInFlightPackets()); // The ping alarm is set for the ping timeout, not the shorter // retransmittable_on_wire_timeout. @@ -8081,13 +8003,8 @@ TEST_P(QuicConnectionTest, RetransmittableOnWireSetsPingAlarm) { EXPECT_TRUE(connection_.PathDegradingDetectionInProgress()); delay = QuicConnectionPeer::GetSentPacketManager(&connection_) ->GetPathDegradingDelay(); - if (GetQuicReloadableFlag(quic_use_blackhole_detector)) { - EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() - - clock_.ApproximateNow()); - } else { - EXPECT_EQ(delay, connection_.GetPathDegradingAlarm()->deadline() - - clock_.ApproximateNow()); - } + EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() - + clock_.ApproximateNow()); } // This test verifies that the connection marks path as degrading and does not @@ -8110,30 +8027,17 @@ TEST_P(QuicConnectionTest, NoPathDegradingAlarmIfPathIsDegrading) { // Check the deadline of the path degrading alarm. QuicTime::Delta delay = QuicConnectionPeer::GetSentPacketManager(&connection_) ->GetPathDegradingDelay(); - if (GetQuicReloadableFlag(quic_use_blackhole_detector)) { - EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() - - clock_.ApproximateNow()); - } else { - EXPECT_EQ(delay, connection_.GetPathDegradingAlarm()->deadline() - - clock_.ApproximateNow()); - } + EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() - + clock_.ApproximateNow()); // Send a second packet. The path degrading alarm's deadline should remain // the same. clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); - QuicTime prev_deadline = connection_.GetPathDegradingAlarm()->deadline(); - if (GetQuicReloadableFlag(quic_use_blackhole_detector)) { - prev_deadline = connection_.GetBlackholeDetectorAlarm()->deadline(); - } + QuicTime prev_deadline = connection_.GetBlackholeDetectorAlarm()->deadline(); connection_.SendStreamDataWithString(1, data, offset, NO_FIN); offset += data_size; EXPECT_TRUE(connection_.PathDegradingDetectionInProgress()); - if (GetQuicReloadableFlag(quic_use_blackhole_detector)) { - EXPECT_EQ(prev_deadline, - connection_.GetBlackholeDetectorAlarm()->deadline()); - } else { - EXPECT_EQ(prev_deadline, connection_.GetPathDegradingAlarm()->deadline()); - } + EXPECT_EQ(prev_deadline, connection_.GetBlackholeDetectorAlarm()->deadline()); // Now receive an ACK of the first packet. This should advance the path // degrading alarm's deadline since forward progress has been made. @@ -8147,13 +8051,8 @@ TEST_P(QuicConnectionTest, NoPathDegradingAlarmIfPathIsDegrading) { // Check the deadline of the path degrading alarm. delay = QuicConnectionPeer::GetSentPacketManager(&connection_) ->GetPathDegradingDelay(); - if (GetQuicReloadableFlag(quic_use_blackhole_detector)) { - EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() - - clock_.ApproximateNow()); - } else { - EXPECT_EQ(delay, connection_.GetPathDegradingAlarm()->deadline() - - clock_.ApproximateNow()); - } + EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() - + clock_.ApproximateNow()); // Advance time to the path degrading alarm's deadline and simulate // firing the path degrading alarm. This path will be considered as @@ -8194,30 +8093,17 @@ TEST_P(QuicConnectionTest, UnmarkPathDegradingOnForwardProgress) { // Check the deadline of the path degrading alarm. QuicTime::Delta delay = QuicConnectionPeer::GetSentPacketManager(&connection_) ->GetPathDegradingDelay(); - if (GetQuicReloadableFlag(quic_use_blackhole_detector)) { - EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() - - clock_.ApproximateNow()); - } else { - EXPECT_EQ(delay, connection_.GetPathDegradingAlarm()->deadline() - - clock_.ApproximateNow()); - } + EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() - + clock_.ApproximateNow()); // Send a second packet. The path degrading alarm's deadline should remain // the same. clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); - QuicTime prev_deadline = connection_.GetPathDegradingAlarm()->deadline(); - if (GetQuicReloadableFlag(quic_use_blackhole_detector)) { - prev_deadline = connection_.GetBlackholeDetectorAlarm()->deadline(); - } + QuicTime prev_deadline = connection_.GetBlackholeDetectorAlarm()->deadline(); connection_.SendStreamDataWithString(1, data, offset, NO_FIN); offset += data_size; EXPECT_TRUE(connection_.PathDegradingDetectionInProgress()); - if (GetQuicReloadableFlag(quic_use_blackhole_detector)) { - EXPECT_EQ(prev_deadline, - connection_.GetBlackholeDetectorAlarm()->deadline()); - } else { - EXPECT_EQ(prev_deadline, connection_.GetPathDegradingAlarm()->deadline()); - } + EXPECT_EQ(prev_deadline, connection_.GetBlackholeDetectorAlarm()->deadline()); // Now receive an ACK of the first packet. This should advance the path // degrading alarm's deadline since forward progress has been made. @@ -8231,13 +8117,8 @@ TEST_P(QuicConnectionTest, UnmarkPathDegradingOnForwardProgress) { // Check the deadline of the path degrading alarm. delay = QuicConnectionPeer::GetSentPacketManager(&connection_) ->GetPathDegradingDelay(); - if (GetQuicReloadableFlag(quic_use_blackhole_detector)) { - EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() - - clock_.ApproximateNow()); - } else { - EXPECT_EQ(delay, connection_.GetPathDegradingAlarm()->deadline() - - clock_.ApproximateNow()); - } + EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() - + clock_.ApproximateNow()); // Advance time to the path degrading alarm's deadline and simulate // firing the alarm. @@ -9166,6 +9047,13 @@ TEST_P(QuicConnectionTest, SendMessage) { if (!VersionSupportsMessageFrames(connection_.transport_version())) { return; } + if (connection_.version().UsesTls()) { + QuicConfig config; + QuicConfigPeer::SetReceivedMaxDatagramFrameSize( + &config, kMaxAcceptedDatagramFrameSize); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + connection_.SetFromConfig(config); + } std::string message(connection_.GetCurrentLargestMessagePayload() * 2, 'a'); quiche::QuicheStringPiece message_data(message); QuicMemSliceStorage storage(nullptr, 0, nullptr, 0); @@ -9208,6 +9096,94 @@ TEST_P(QuicConnectionTest, SendMessage) { false)); } +TEST_P(QuicConnectionTest, GetCurrentLargestMessagePayload) { + if (!connection_.version().SupportsMessageFrames()) { + return; + } + // Force use of this encrypter to simplify test expectations by making sure + // that the encryption overhead is constant across versions. + connection_.SetEncrypter(ENCRYPTION_INITIAL, + std::make_unique<TaggingEncrypter>(0x00)); + QuicPacketLength expected_largest_payload = 1319; + if (connection_.version().SendsVariableLengthPacketNumberInLongHeader()) { + expected_largest_payload += 3; + } + if (connection_.version().HasLongHeaderLengths()) { + expected_largest_payload -= 2; + } + if (connection_.version().HasLengthPrefixedConnectionIds()) { + expected_largest_payload -= 1; + } + if (connection_.version().UsesTls()) { + // QUIC+TLS disallows DATAGRAM/MESSAGE frames before the handshake. + EXPECT_EQ(connection_.GetCurrentLargestMessagePayload(), 0); + QuicConfig config; + QuicConfigPeer::SetReceivedMaxDatagramFrameSize( + &config, kMaxAcceptedDatagramFrameSize); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + connection_.SetFromConfig(config); + // Verify the value post-handshake. + EXPECT_EQ(connection_.GetCurrentLargestMessagePayload(), + expected_largest_payload); + } else { + EXPECT_EQ(connection_.GetCurrentLargestMessagePayload(), + expected_largest_payload); + } +} + +TEST_P(QuicConnectionTest, GetGuaranteedLargestMessagePayload) { + if (!connection_.version().SupportsMessageFrames()) { + return; + } + // Force use of this encrypter to simplify test expectations by making sure + // that the encryption overhead is constant across versions. + connection_.SetEncrypter(ENCRYPTION_INITIAL, + std::make_unique<TaggingEncrypter>(0x00)); + QuicPacketLength expected_largest_payload = 1319; + if (connection_.version().HasLongHeaderLengths()) { + expected_largest_payload -= 2; + } + if (connection_.version().HasLengthPrefixedConnectionIds()) { + expected_largest_payload -= 1; + } + if (connection_.version().UsesTls()) { + // QUIC+TLS disallows DATAGRAM/MESSAGE frames before the handshake. + EXPECT_EQ(connection_.GetGuaranteedLargestMessagePayload(), 0); + QuicConfig config; + QuicConfigPeer::SetReceivedMaxDatagramFrameSize( + &config, kMaxAcceptedDatagramFrameSize); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + connection_.SetFromConfig(config); + // Verify the value post-handshake. + EXPECT_EQ(connection_.GetGuaranteedLargestMessagePayload(), + expected_largest_payload); + } else { + EXPECT_EQ(connection_.GetGuaranteedLargestMessagePayload(), + expected_largest_payload); + } +} + +TEST_P(QuicConnectionTest, LimitedLargestMessagePayload) { + if (!connection_.version().SupportsMessageFrames() || + !connection_.version().UsesTls()) { + return; + } + constexpr QuicPacketLength kFrameSizeLimit = 1000; + constexpr QuicPacketLength kPayloadSizeLimit = + kFrameSizeLimit - kQuicFrameTypeSize; + // QUIC+TLS disallows DATAGRAM/MESSAGE frames before the handshake. + EXPECT_EQ(connection_.GetCurrentLargestMessagePayload(), 0); + EXPECT_EQ(connection_.GetGuaranteedLargestMessagePayload(), 0); + QuicConfig config; + QuicConfigPeer::SetReceivedMaxDatagramFrameSize(&config, kFrameSizeLimit); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + connection_.SetFromConfig(config); + // Verify the value post-handshake. + EXPECT_EQ(connection_.GetCurrentLargestMessagePayload(), kPayloadSizeLimit); + EXPECT_EQ(connection_.GetGuaranteedLargestMessagePayload(), + kPayloadSizeLimit); +} + // Test to check that the path challenge/path response logic works // correctly. This test is only for version-99 TEST_P(QuicConnectionTest, PathChallengeResponse) { @@ -9318,17 +9294,13 @@ TEST_P(QuicConnectionTest, StopProcessingGQuicPacketInIetfQuicConnection) { return; } set_perspective(Perspective::IS_SERVER); - QuicFrame frame; if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { - frame = QuicFrame(&crypto_frame_); EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(1); } else { - frame = QuicFrame(QuicStreamFrame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, - 0u, quiche::QuicheStringPiece())); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); } - ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, + kPeerAddress); // Let connection process a Google QUIC packet. peer_framer_.set_version_for_tests( @@ -9639,20 +9611,16 @@ TEST_P(QuicConnectionTest, CheckConnectedBeforeFlush) { /*transport_close_frame_type=*/0)); // Received 2 packets. - QuicFrame frame; if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { - frame = QuicFrame(&crypto_frame_); EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); } else { - frame = QuicFrame(QuicStreamFrame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, - 0u, quiche::QuicheStringPiece())); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); } - ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, + kPeerAddress); QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_); EXPECT_TRUE(ack_alarm->IsSet()); - ProcessFramePacketWithAddresses(QuicFrame(connection_close_frame.get()), + ProcessFramePacketWithAddresses(QuicFrame(connection_close_frame.release()), kSelfAddress, kPeerAddress); // Verify ack alarm is not set. EXPECT_FALSE(ack_alarm->IsSet()); @@ -9892,8 +9860,7 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter6ClientPTOs) { connection_options.push_back(k1PTO); connection_options.push_back(k6PTO); config.SetConnectionOptionsToSend(connection_options); - QuicConfigPeer::ReceiveIdleNetworkTimeout(&config, SERVER, - kDefaultIdleTimeoutSecs); + QuicConfigPeer::SetNegotiated(&config, true); EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); connection_.SetFromConfig(config); EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); @@ -9903,32 +9870,26 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter6ClientPTOs) { GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo", 0, FIN, nullptr); - // 5PTO + 1 connection close. - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(6)); - // Fire the retransmission alarm 5 times. for (int i = 0; i < 5; ++i) { + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); connection_.GetRetransmissionAlarm()->Fire(); EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet()); EXPECT_TRUE(connection_.connected()); } - if (GetQuicReloadableFlag(quic_use_blackhole_detector)) { - EXPECT_CALL(visitor_, OnPathDegrading()); - connection_.PathDegradingTimeout(); - } + EXPECT_CALL(visitor_, OnPathDegrading()); + connection_.PathDegradingTimeout(); EXPECT_EQ(0u, connection_.sent_packet_manager().GetConsecutiveTlpCount()); EXPECT_EQ(0u, connection_.sent_packet_manager().GetConsecutiveRtoCount()); EXPECT_EQ(5u, connection_.sent_packet_manager().GetConsecutivePtoCount()); // Closes connection on 6th PTO. + // May send multiple connecction close packets with multiple PN spaces. + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1)); EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF)); - if (GetQuicReloadableFlag(quic_use_blackhole_detector)) { - ASSERT_TRUE(connection_.BlackholeDetectionInProgress()); - connection_.GetBlackholeDetectorAlarm()->Fire(); - } else { - connection_.GetRetransmissionAlarm()->Fire(); - } + ASSERT_TRUE(connection_.BlackholeDetectionInProgress()); + connection_.GetBlackholeDetectorAlarm()->Fire(); EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet()); EXPECT_FALSE(connection_.connected()); TestConnectionCloseQuicErrorCode(QUIC_TOO_MANY_RTOS); @@ -9940,8 +9901,7 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter7ClientPTOs) { connection_options.push_back(k2PTO); connection_options.push_back(k7PTO); config.SetConnectionOptionsToSend(connection_options); - QuicConfigPeer::ReceiveIdleNetworkTimeout(&config, SERVER, - kDefaultIdleTimeoutSecs); + QuicConfigPeer::SetNegotiated(&config, true); EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); connection_.SetFromConfig(config); EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); @@ -9958,10 +9918,8 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter7ClientPTOs) { EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet()); EXPECT_TRUE(connection_.connected()); } - if (GetQuicReloadableFlag(quic_use_blackhole_detector)) { - EXPECT_CALL(visitor_, OnPathDegrading()); - connection_.PathDegradingTimeout(); - } + EXPECT_CALL(visitor_, OnPathDegrading()); + connection_.PathDegradingTimeout(); EXPECT_EQ(0u, connection_.sent_packet_manager().GetConsecutiveTlpCount()); EXPECT_EQ(0u, connection_.sent_packet_manager().GetConsecutiveRtoCount()); @@ -9970,12 +9928,8 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter7ClientPTOs) { EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF)); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1)); - if (GetQuicReloadableFlag(quic_use_blackhole_detector)) { - ASSERT_TRUE(connection_.BlackholeDetectionInProgress()); - connection_.GetBlackholeDetectorAlarm()->Fire(); - } else { - connection_.GetRetransmissionAlarm()->Fire(); - } + ASSERT_TRUE(connection_.BlackholeDetectionInProgress()); + connection_.GetBlackholeDetectorAlarm()->Fire(); EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet()); EXPECT_FALSE(connection_.connected()); TestConnectionCloseQuicErrorCode(QUIC_TOO_MANY_RTOS); @@ -9986,8 +9940,7 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter8ClientPTOs) { QuicTagVector connection_options; connection_options.push_back(k2PTO); connection_options.push_back(k8PTO); - QuicConfigPeer::ReceiveIdleNetworkTimeout(&config, SERVER, - kDefaultIdleTimeoutSecs); + QuicConfigPeer::SetNegotiated(&config, true); config.SetConnectionOptionsToSend(connection_options); EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); connection_.SetFromConfig(config); @@ -10005,10 +9958,8 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter8ClientPTOs) { EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet()); EXPECT_TRUE(connection_.connected()); } - if (GetQuicReloadableFlag(quic_use_blackhole_detector)) { - EXPECT_CALL(visitor_, OnPathDegrading()); - connection_.PathDegradingTimeout(); - } + EXPECT_CALL(visitor_, OnPathDegrading()); + connection_.PathDegradingTimeout(); EXPECT_EQ(0u, connection_.sent_packet_manager().GetConsecutiveTlpCount()); EXPECT_EQ(0u, connection_.sent_packet_manager().GetConsecutiveRtoCount()); @@ -10017,12 +9968,8 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter8ClientPTOs) { EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF)); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1)); - if (GetQuicReloadableFlag(quic_use_blackhole_detector)) { - ASSERT_TRUE(connection_.BlackholeDetectionInProgress()); - connection_.GetBlackholeDetectorAlarm()->Fire(); - } else { - connection_.GetRetransmissionAlarm()->Fire(); - } + ASSERT_TRUE(connection_.BlackholeDetectionInProgress()); + connection_.GetBlackholeDetectorAlarm()->Fire(); EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet()); EXPECT_FALSE(connection_.connected()); TestConnectionCloseQuicErrorCode(QUIC_TOO_MANY_RTOS); @@ -10032,7 +9979,6 @@ TEST_P(QuicConnectionTest, DeprecateHandshakeMode) { if (!connection_.version().SupportsAntiAmplificationLimit()) { return; } - SetQuicReloadableFlag(quic_send_ping_when_pto_skips_packet_number, true); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); @@ -10054,7 +10000,12 @@ TEST_P(QuicConnectionTest, DeprecateHandshakeMode) { EXPECT_EQ(0u, connection_.GetStats().crypto_retransmit_count); // PTO fires, verify a PING packet gets sent because there is no data to send. - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(3), _, _)); + EXPECT_CALL(*send_algorithm_, + OnPacketSent(_, _, + GetQuicReloadableFlag(quic_default_on_pto) + ? QuicPacketNumber(2) + : QuicPacketNumber(3), + _, _)); EXPECT_CALL(visitor_, SendPing()).WillOnce(Invoke([this]() { SendPing(); })); connection_.GetRetransmissionAlarm()->Fire(); EXPECT_EQ(1u, connection_.GetStats().pto_count); @@ -10134,7 +10085,7 @@ TEST_P(QuicConnectionTest, ConnectionCloseFrameType) { ASSERT_EQ(1u, connection_close_frames.size()); EXPECT_EQ(IETF_QUIC_TRANSPORT_CONNECTION_CLOSE, connection_close_frames[0].close_type); - EXPECT_EQ(kQuicErrorCode, connection_close_frames[0].extracted_error_code); + EXPECT_EQ(kQuicErrorCode, connection_close_frames[0].quic_error_code); EXPECT_EQ(kTransportCloseFrameType, connection_close_frames[0].transport_close_frame_type); } @@ -10216,6 +10167,7 @@ TEST_P(QuicConnectionTest, SendCoalescedPackets) { connection_.set_debug_visitor(&debug_visitor); EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(3); EXPECT_CALL(debug_visitor, OnCoalescedPacketSent(_, _)).Times(1); + EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1); { QuicConnection::ScopedPacketFlusher flusher(&connection_); use_tagging_decrypter(); @@ -10287,6 +10239,7 @@ TEST_P(QuicConnectionTest, MultiplePacketNumberSpacePto) { connection_.SetEncrypter(ENCRYPTION_HANDSHAKE, std::make_unique<TaggingEncrypter>(0x02)); connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE); + EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1); connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_HANDSHAKE); EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet()); @@ -10300,7 +10253,13 @@ TEST_P(QuicConnectionTest, MultiplePacketNumberSpacePto) { // Retransmit handshake data. clock_.AdvanceTime(retransmission_time - clock_.Now()); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(4), _, _)); + EXPECT_CALL(*send_algorithm_, + OnPacketSent(_, _, + GetQuicReloadableFlag(quic_default_on_pto) + ? QuicPacketNumber(3) + : QuicPacketNumber(4), + _, _)); + EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1); connection_.GetRetransmissionAlarm()->Fire(); EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet()); @@ -10313,7 +10272,13 @@ TEST_P(QuicConnectionTest, MultiplePacketNumberSpacePto) { // Retransmit handshake data again. clock_.AdvanceTime(retransmission_time - clock_.Now()); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(7), _, _)); + EXPECT_CALL(*send_algorithm_, + OnPacketSent(_, _, + GetQuicReloadableFlag(quic_default_on_pto) + ? QuicPacketNumber(5) + : QuicPacketNumber(7), + _, _)); + EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1); connection_.GetRetransmissionAlarm()->Fire(); EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet()); @@ -10324,27 +10289,55 @@ TEST_P(QuicConnectionTest, MultiplePacketNumberSpacePto) { // Retransmit application data. clock_.AdvanceTime(retransmission_time - clock_.Now()); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(9), _, _)); + EXPECT_CALL(*send_algorithm_, + OnPacketSent(_, _, + GetQuicReloadableFlag(quic_default_on_pto) + ? QuicPacketNumber(6) + : QuicPacketNumber(9), + _, _)); connection_.GetRetransmissionAlarm()->Fire(); EXPECT_EQ(0x01010101u, writer_->final_bytes_of_last_packet()); } -TEST_P(QuicConnectionTest, ClientParsesRetry) { +void QuicConnectionTest::TestClientRetryHandling(bool invalid_retry_tag, + bool missing_id_in_config, + bool wrong_id_in_config) { + if (invalid_retry_tag) { + ASSERT_FALSE(missing_id_in_config); + ASSERT_FALSE(wrong_id_in_config); + } else { + ASSERT_FALSE(missing_id_in_config && wrong_id_in_config); + } if (!version().HasRetryIntegrityTag()) { return; } - if (version() != - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25)) { + + // These values come from draft-ietf-quic-tls Appendix A.4. + char retry_packet25[] = { + 0xff, 0xff, 0x00, 0x00, 0x19, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, + 0x42, 0x62, 0xb5, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x1e, 0x5e, 0xc5, 0xb0, + 0x14, 0xcb, 0xb1, 0xf0, 0xfd, 0x93, 0xdf, 0x40, 0x48, 0xc4, 0x46, 0xa6}; + char retry_packet27[] = { + 0xff, 0xff, 0x00, 0x00, 0x1b, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, + 0x42, 0x62, 0xb5, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0xa5, 0x23, 0xcb, 0x5b, + 0xa5, 0x24, 0x69, 0x5f, 0x65, 0x69, 0xf2, 0x93, 0xa1, 0x35, 0x9d, 0x8e}; + + char* retry_packet; + size_t retry_packet_length; + if (version() == + ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27)) { + retry_packet = retry_packet27; + retry_packet_length = QUICHE_ARRAYSIZE(retry_packet27); + } else if (version() == + ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25)) { + retry_packet = retry_packet25; + retry_packet_length = QUICHE_ARRAYSIZE(retry_packet25); + } else { // TODO(dschinazi) generate retry packets for all versions once we have // server-side support for generating these programmatically. return; } - // These values come from draft-ietf-quic-tls Appendix A.4. - char retry_packet[] = {0xff, 0xff, 0x00, 0x00, 0x19, 0x00, 0x08, 0xf0, 0x67, - 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5, 0x74, 0x6f, 0x6b, - 0x65, 0x6e, 0x1e, 0x5e, 0xc5, 0xb0, 0x14, 0xcb, 0xb1, - 0xf0, 0xfd, 0x93, 0xdf, 0x40, 0x48, 0xc4, 0x46, 0xa6}; char original_connection_id_bytes[] = {0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08}; char new_connection_id_bytes[] = {0xf0, 0x67, 0xa5, 0x50, @@ -10360,43 +10353,110 @@ TEST_P(QuicConnectionTest, ClientParsesRetry) { std::string retry_token(retry_token_bytes, QUICHE_ARRAYSIZE(retry_token_bytes)); - { - TestConnection connection1( - original_connection_id, kPeerAddress, helper_.get(), - alarm_factory_.get(), writer_.get(), Perspective::IS_CLIENT, version()); - connection1.set_visitor(&visitor_); + if (invalid_retry_tag) { + // Flip the last bit of the retry packet to prevent the integrity tag + // from validating correctly. + retry_packet[retry_packet_length - 1] ^= 1; + } - connection1.ProcessUdpPacket( - kSelfAddress, kPeerAddress, - QuicReceivedPacket(retry_packet, QUICHE_ARRAYSIZE(retry_packet), - clock_.Now())); - EXPECT_TRUE(connection1.GetStats().retry_packet_processed); - EXPECT_EQ(connection1.connection_id(), new_connection_id); - EXPECT_EQ(QuicPacketCreatorPeer::GetRetryToken( - QuicConnectionPeer::GetPacketCreator(&connection1)), - retry_token); + QuicConnectionId config_original_connection_id = original_connection_id; + if (wrong_id_in_config) { + // Flip the first bit of the connection ID. + ASSERT_FALSE(config_original_connection_id.IsEmpty()); + config_original_connection_id.mutable_data()[0] ^= 0x80; } - // Now flip the last bit of the retry packet to prevent the integrity tag - // from validating correctly. - retry_packet[QUICHE_ARRAYSIZE(retry_packet) - 1] ^= 1; + // Make sure the connection uses the connection ID from the test vectors, + QuicConnectionPeer::SetServerConnectionId(&connection_, + original_connection_id); - { - TestConnection connection2( - original_connection_id, kPeerAddress, helper_.get(), - alarm_factory_.get(), writer_.get(), Perspective::IS_CLIENT, version()); - connection2.set_visitor(&visitor_); + // Process the RETRY packet. + connection_.ProcessUdpPacket( + kSelfAddress, kPeerAddress, + QuicReceivedPacket(retry_packet, retry_packet_length, clock_.Now())); - connection2.ProcessUdpPacket( - kSelfAddress, kPeerAddress, - QuicReceivedPacket(retry_packet, QUICHE_ARRAYSIZE(retry_packet), - clock_.Now())); - EXPECT_FALSE(connection2.GetStats().retry_packet_processed); - EXPECT_EQ(connection2.connection_id(), original_connection_id); + if (invalid_retry_tag) { + // Make sure we refuse to process a RETRY with invalid tag. + EXPECT_FALSE(connection_.GetStats().retry_packet_processed); + EXPECT_EQ(connection_.connection_id(), original_connection_id); EXPECT_TRUE(QuicPacketCreatorPeer::GetRetryToken( - QuicConnectionPeer::GetPacketCreator(&connection2)) + QuicConnectionPeer::GetPacketCreator(&connection_)) .empty()); + return; } + + // Make sure we correctly parsed the RETRY. + EXPECT_TRUE(connection_.GetStats().retry_packet_processed); + EXPECT_EQ(connection_.connection_id(), new_connection_id); + EXPECT_EQ(QuicPacketCreatorPeer::GetRetryToken( + QuicConnectionPeer::GetPacketCreator(&connection_)), + retry_token); + // Make sure our fake framer has the new post-retry INITIAL keys. + writer_->framer()->framer()->SetInitialObfuscators(new_connection_id); + + // Test validating the original_connection_id from the config. + QuicConfig received_config; + QuicConfigPeer::SetNegotiated(&received_config, true); + if (!missing_id_in_config) { + QuicConfigPeer::SetReceivedOriginalConnectionId( + &received_config, config_original_connection_id); + } + if (missing_id_in_config || wrong_id_in_config) { + EXPECT_CALL(visitor_, + OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF)) + .Times(1); + } else { + EXPECT_CALL(visitor_, + OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF)) + .Times(0); + } + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)).Times(AnyNumber()); + connection_.SetFromConfig(received_config); + if (missing_id_in_config || wrong_id_in_config) { + EXPECT_FALSE(connection_.connected()); + TestConnectionCloseQuicErrorCode(IETF_QUIC_PROTOCOL_VIOLATION); + } else { + EXPECT_TRUE(connection_.connected()); + } +} + +TEST_P(QuicConnectionTest, ClientParsesRetry) { + TestClientRetryHandling(/*invalid_retry_tag=*/false, + /*missing_id_in_config=*/false, + /*wrong_id_in_config=*/false); +} + +TEST_P(QuicConnectionTest, ClientParsesInvalidRetry) { + TestClientRetryHandling(/*invalid_retry_tag=*/true, + /*missing_id_in_config=*/false, + /*wrong_id_in_config=*/false); +} + +TEST_P(QuicConnectionTest, ClientParsesRetryMissingId) { + TestClientRetryHandling(/*invalid_retry_tag=*/false, + /*missing_id_in_config=*/true, + /*wrong_id_in_config=*/false); +} + +TEST_P(QuicConnectionTest, ClientParsesRetryWrongId) { + TestClientRetryHandling(/*invalid_retry_tag=*/false, + /*missing_id_in_config=*/false, + /*wrong_id_in_config=*/true); +} + +TEST_P(QuicConnectionTest, ClientReceivesOriginalConnectionIdWithoutRetry) { + // Make sure that receiving the original_connection_id transport parameter + // fails the handshake when no RETRY packet was received before it. + QuicConfig received_config; + QuicConfigPeer::SetNegotiated(&received_config, true); + QuicConfigPeer::SetReceivedOriginalConnectionId(&received_config, + TestConnectionId(0x12345)); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)).Times(AnyNumber()); + EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF)) + .Times(1); + connection_.SetFromConfig(received_config); + EXPECT_FALSE(connection_.connected()); + TestConnectionCloseQuicErrorCode(IETF_QUIC_PROTOCOL_VIOLATION); } // Regression test for http://crbug/1047977 @@ -10501,6 +10561,10 @@ TEST_P(QuicConnectionTest, SendPingWhenSkipPacketNumberForPto) { connection_options.push_back(kPTOS); connection_options.push_back(k1PTO); config.SetConnectionOptionsToSend(connection_options); + if (connection_.version().UsesTls()) { + QuicConfigPeer::SetReceivedMaxDatagramFrameSize( + &config, kMaxAcceptedDatagramFrameSize); + } EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); connection_.SetFromConfig(config); EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); @@ -10508,24 +10572,116 @@ TEST_P(QuicConnectionTest, SendPingWhenSkipPacketNumberForPto) { EXPECT_EQ(MESSAGE_STATUS_SUCCESS, SendMessage("message")); EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet()); - // Although there are bytes in flight, no packet gets sent on PTO firing. - if (GetQuicReloadableFlag(quic_send_ping_when_pto_skips_packet_number)) { - // PTO fires, verify a PING packet gets sent because there is no data to - // send. - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, QuicPacketNumber(3), _, _)); - EXPECT_CALL(visitor_, SendPing()).WillOnce(Invoke([this]() { - SendPing(); - })); + // PTO fires, verify a PING packet gets sent because there is no data to + // send. + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(3), _, _)); + EXPECT_CALL(visitor_, SendPing()).WillOnce(Invoke([this]() { SendPing(); })); + connection_.GetRetransmissionAlarm()->Fire(); + EXPECT_EQ(1u, connection_.GetStats().pto_count); + EXPECT_EQ(0u, connection_.GetStats().crypto_retransmit_count); + EXPECT_EQ(1u, writer_->ping_frames().size()); +} + +// Regression test for b/155757133 +TEST_P(QuicConnectionTest, DonotChangeQueuedAcks) { + if (!connection_.SupportsMultiplePacketNumberSpaces()) { + return; + } + const size_t kMinRttMs = 40; + RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats()); + rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs), + QuicTime::Delta::Zero(), QuicTime::Zero()); + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + EXPECT_CALL(*send_algorithm_, OnCongestionEvent(_, _, _, _, _)); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + + ProcessPacket(2); + ProcessPacket(3); + ProcessPacket(4); + // Process a packet containing stream frame followed by ACK of packets 1. + QuicFrames frames; + frames.push_back(QuicFrame(QuicStreamFrame( + QuicUtils::GetFirstBidirectionalStreamId( + connection_.version().transport_version, Perspective::IS_CLIENT), + false, 0u, quiche::QuicheStringPiece()))); + QuicAckFrame ack_frame = InitAckFrame(1); + frames.push_back(QuicFrame(&ack_frame)); + // Receiving stream frame causes something to send. + EXPECT_CALL(visitor_, OnStreamFrame(_)).WillOnce(Invoke([this]() { + connection_.SendControlFrame(QuicFrame(new QuicWindowUpdateFrame(1, 0, 0))); + // Verify now the queued ACK contains packet number 2. + EXPECT_TRUE(QuicPacketCreatorPeer::QueuedFrames( + QuicConnectionPeer::GetPacketCreator(&connection_))[0] + .ack_frame->packets.Contains(QuicPacketNumber(2))); + })); + ProcessFramesPacketAtLevel(9, frames, ENCRYPTION_FORWARD_SECURE); + if (GetQuicReloadableFlag(quic_donot_change_queued_ack)) { + EXPECT_TRUE(writer_->ack_frames()[0].packets.Contains(QuicPacketNumber(2))); } else { - // No packet gets sent. - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); + // ACK frame changes mid packet serialiation! + EXPECT_FALSE( + writer_->ack_frames()[0].packets.Contains(QuicPacketNumber(2))); } - connection_.GetRetransmissionAlarm()->Fire(); - if (GetQuicReloadableFlag(quic_send_ping_when_pto_skips_packet_number)) { - EXPECT_EQ(1u, connection_.GetStats().pto_count); - EXPECT_EQ(0u, connection_.GetStats().crypto_retransmit_count); - EXPECT_EQ(1u, writer_->ping_frames().size()); +} + +TEST_P(QuicConnectionTest, DonotExtendIdleTimeOnUndecryptablePackets) { + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + QuicConfig config; + connection_.SetFromConfig(config); + // Subtract a second from the idle timeout on the client side. + QuicTime initial_deadline = + clock_.ApproximateNow() + + QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs - 1); + EXPECT_EQ(initial_deadline, connection_.GetTimeoutAlarm()->deadline()); + + // Received an undecryptable packet. + clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); + const uint8_t tag = 0x07; + peer_framer_.SetEncrypter(ENCRYPTION_FORWARD_SECURE, + std::make_unique<TaggingEncrypter>(tag)); + ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_FORWARD_SECURE); + if (GetQuicReloadableFlag(quic_extend_idle_time_on_decryptable_packets)) { + // Verify deadline does not get extended. + EXPECT_EQ(initial_deadline, connection_.GetTimeoutAlarm()->deadline()); + } + if (GetQuicReloadableFlag(quic_extend_idle_time_on_decryptable_packets)) { + EXPECT_CALL(visitor_, OnConnectionClosed(_, _)).Times(1); + } else { + EXPECT_CALL(visitor_, OnConnectionClosed(_, _)).Times(0); + } + QuicTime::Delta delay = initial_deadline - clock_.ApproximateNow(); + clock_.AdvanceTime(delay); + if (GetQuicReloadableFlag(quic_extend_idle_time_on_decryptable_packets)) { + connection_.GetTimeoutAlarm()->Fire(); + } + if (GetQuicReloadableFlag(quic_extend_idle_time_on_decryptable_packets)) { + // Verify connection gets closed. + EXPECT_FALSE(connection_.connected()); + } else { + // Verify the timeout alarm deadline is updated. + EXPECT_TRUE(connection_.connected()); + EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet()); + } +} + +TEST_P(QuicConnectionTest, BundleAckWithImmediateResponse) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + + EXPECT_CALL(visitor_, OnStreamFrame(_)).WillOnce(Invoke([this]() { + connection_.SendControlFrame(QuicFrame(new QuicWindowUpdateFrame(1, 0, 0))); + })); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); + ProcessDataPacket(1); + QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_); + if (GetQuicReloadableFlag(quic_advance_ack_timeout_update)) { + // Verify ACK is bundled with WINDOW_UPDATE. + EXPECT_FALSE(writer_->ack_frames().empty()); + EXPECT_FALSE(ack_alarm->IsSet()); + } else { + // ACK is pending. + EXPECT_TRUE(writer_->ack_frames().empty()); + EXPECT_TRUE(ack_alarm->IsSet()); } } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_constants.h b/chromium/net/third_party/quiche/src/quic/core/quic_constants.h index 15f0abbad5a..51ad0f0c084 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_constants.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_constants.h @@ -72,9 +72,9 @@ const QuicPacketCount kMinInitialCongestionWindow = 10; // Minimum size of initial flow control window, for both stream and session. // This is only enforced when version.AllowsLowFlowControlLimits() is false. -const uint32_t kMinimumFlowControlSendWindow = 16 * 1024; // 16 KB +const QuicByteCount kMinimumFlowControlSendWindow = 16 * 1024; // 16 KB // Default size of initial flow control window, for both stream and session. -const uint32_t kDefaultFlowControlSendWindow = 16 * 1024; // 16 KB +const QuicByteCount kDefaultFlowControlSendWindow = 16 * 1024; // 16 KB // Maximum flow control receive window limits for connection and stream. const QuicByteCount kStreamReceiveWindowLimit = 16 * 1024 * 1024; // 16 MB @@ -131,8 +131,6 @@ static const int64_t kMinTailLossProbeTimeoutMs = 10; // The timeout before the handshake succeeds. const int64_t kInitialIdleTimeoutSecs = 5; -// The default idle timeout. -const int64_t kDefaultIdleTimeoutSecs = 30; // The maximum idle timeout that can be negotiated. const int64_t kMaximumIdleTimeoutSecs = 60 * 10; // 10 minutes. // The default timeout for a connection until the crypto handshake succeeds. @@ -250,6 +248,9 @@ const size_t kMaxNewTokenTokenLength = 0xffff; // Default initial rtt used before any samples are received. const int kInitialRttMs = 100; +// Default threshold of packet reordering before a packet is declared lost. +static const QuicPacketCount kDefaultPacketReorderingThreshold = 3; + // Default fraction (1/4) of an RTT the algorithm waits before determining a // packet is lost due to early retransmission by time based loss detection. static const int kDefaultLossDelayShift = 2; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.cc index f4b01ff3333..ba00b8816b0 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.cc @@ -292,9 +292,6 @@ void QuicControlFrameManager::WriteBufferedFrames() { DCHECK(session_->connection()->connected()) << ENDPOINT << "Try to write control frames when connection is closed."; while (HasBufferedFrames()) { - if (!session_->write_with_transmission()) { - session_->SetTransmissionType(NOT_RETRANSMISSION); - } QuicFrame frame_to_send = control_frames_.at(least_unsent_ - least_unacked_); QuicFrame copy = CopyRetransmittableControlFrame(frame_to_send); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h index 8c33ee91447..5ba93f24848 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h @@ -12,6 +12,7 @@ #include "net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h" #include "net/third_party/quiche/src/quic/core/quic_server_id.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_logging.h" namespace quic { @@ -50,7 +51,14 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientHandshaker HandshakeState GetHandshakeState() const override; size_t BufferSizeLimitForLevel(EncryptionLevel level) const override; void OnOneRttPacketAcknowledged() override {} + void OnHandshakePacketSent() override {} + void OnConnectionClosed(QuicErrorCode /*error*/, + ConnectionCloseSource /*source*/) override {} void OnHandshakeDoneReceived() override; + void OnApplicationState( + std::unique_ptr<ApplicationState> /*application_state*/) override { + QUICHE_NOTREACHED(); + } // From QuicCryptoHandshaker void OnHandshakeMessage(const CryptoHandshakeMessage& message) override; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker_test.cc index 92de76f300d..3ea08a51941 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker_test.cc @@ -47,6 +47,7 @@ class InsecureProofVerifier : public ProofVerifier { QuicAsyncStatus VerifyCertChain( const std::string& /*hostname*/, + const uint16_t /*port*/, const std::vector<std::string>& /*certs*/, const std::string& /*ocsp_response*/, const std::string& /*cert_sct*/, @@ -69,13 +70,14 @@ class DummyProofSource : public ProofSource { // ProofSource override. void GetProof(const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, const std::string& hostname, const std::string& /*server_config*/, QuicTransportVersion /*transport_version*/, quiche::QuicheStringPiece /*chlo_hash*/, std::unique_ptr<Callback> callback) override { QuicReferenceCountedPointer<ProofSource::Chain> chain = - GetCertChain(server_address, hostname); + GetCertChain(server_address, client_address, hostname); QuicCryptoProof proof; proof.signature = "Dummy signature"; proof.leaf_cert_scts = "Dummy timestamp"; @@ -84,6 +86,7 @@ class DummyProofSource : public ProofSource { QuicReferenceCountedPointer<Chain> GetCertChain( const QuicSocketAddress& /*server_address*/, + const QuicSocketAddress& /*client_address*/, const std::string& /*hostname*/) override { std::vector<std::string> certs; certs.push_back("Dummy cert"); @@ -93,12 +96,15 @@ class DummyProofSource : public ProofSource { void ComputeTlsSignature( const QuicSocketAddress& /*server_address*/, + const QuicSocketAddress& /*client_address*/, const std::string& /*hostname*/, uint16_t /*signature_algorit*/, quiche::QuicheStringPiece /*in*/, std::unique_ptr<SignatureCallback> callback) override { callback->Run(true, "Dummy signature", /*details=*/nullptr); } + + TicketCrypter* GetTicketCrypter() override { return nullptr; } }; class Handshaker : public QuicCryptoClientHandshaker { @@ -136,11 +142,13 @@ class QuicCryptoClientHandshakerTest {version_})), session_(connection_, false), crypto_client_config_(std::make_unique<InsecureProofVerifier>()), - client_stream_(new QuicCryptoClientStream(server_id_, - &session_, - nullptr, - &crypto_client_config_, - &proof_handler_)), + client_stream_( + new QuicCryptoClientStream(server_id_, + &session_, + nullptr, + &crypto_client_config_, + &proof_handler_, + /*has_application_state = */ false)), handshaker_(server_id_, client_stream_, &session_, diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc index 62990c1faa5..36dc4cdb4c3 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc @@ -11,6 +11,7 @@ #include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h" #include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h" #include "net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/core/quic_session.h" @@ -31,7 +32,8 @@ QuicCryptoClientStream::QuicCryptoClientStream( QuicSession* session, std::unique_ptr<ProofVerifyContext> verify_context, QuicCryptoClientConfig* crypto_config, - ProofHandler* proof_handler) + ProofHandler* proof_handler, + bool has_application_state) : QuicCryptoClientStreamBase(session) { DCHECK_EQ(Perspective::IS_CLIENT, session->connection()->perspective()); switch (session->connection()->version().handshake_protocol) { @@ -43,7 +45,7 @@ QuicCryptoClientStream::QuicCryptoClientStream( case PROTOCOL_TLS1_3: handshaker_ = std::make_unique<TlsClientHandshaker>( server_id, this, session, std::move(verify_context), crypto_config, - proof_handler); + proof_handler, has_application_state); break; case PROTOCOL_UNSUPPORTED: QUIC_BUG << "Attempting to create QuicCryptoClientStream for unknown " @@ -111,8 +113,22 @@ void QuicCryptoClientStream::OnOneRttPacketAcknowledged() { handshaker_->OnOneRttPacketAcknowledged(); } +void QuicCryptoClientStream::OnHandshakePacketSent() { + handshaker_->OnHandshakePacketSent(); +} + +void QuicCryptoClientStream::OnConnectionClosed(QuicErrorCode error, + ConnectionCloseSource source) { + handshaker_->OnConnectionClosed(error, source); +} + void QuicCryptoClientStream::OnHandshakeDoneReceived() { handshaker_->OnHandshakeDoneReceived(); } +void QuicCryptoClientStream::OnApplicationState( + std::unique_ptr<ApplicationState> application_state) { + handshaker_->OnApplicationState(std::move(application_state)); +} + } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h index 5af0a663fd7..23f83c7e390 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h @@ -16,10 +16,15 @@ #include "net/third_party/quiche/src/quic/core/quic_crypto_stream.h" #include "net/third_party/quiche/src/quic/core/quic_server_id.h" #include "net/third_party/quiche/src/quic/core/quic_session.h" +#include "net/third_party/quiche/src/quic/core/quic_versions.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" namespace quic { +namespace test { +class QuicCryptoClientStreamPeer; +} // namespace test + class QUIC_EXPORT_PRIVATE QuicCryptoClientStreamBase : public QuicCryptoStream { public: explicit QuicCryptoClientStreamBase(QuicSession* session); @@ -58,6 +63,9 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStreamBase : public QuicCryptoStream { // client. Does not count update messages that were received prior // to handshake confirmation. virtual int num_scup_messages_received() const = 0; + + virtual void OnApplicationState( + std::unique_ptr<ApplicationState> application_state) = 0; }; class QUIC_EXPORT_PRIVATE QuicCryptoClientStream @@ -148,8 +156,19 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStream // Called when a 1RTT packet has been acknowledged. virtual void OnOneRttPacketAcknowledged() = 0; + // Called when a packet of ENCRYPTION_HANDSHAKE gets sent. + virtual void OnHandshakePacketSent() = 0; + + // Called when connection gets closed. + virtual void OnConnectionClosed(QuicErrorCode error, + ConnectionCloseSource source) = 0; + // Called when handshake done has been received. virtual void OnHandshakeDoneReceived() = 0; + + // Called when application state is received. + virtual void OnApplicationState( + std::unique_ptr<ApplicationState> application_state) = 0; }; // ProofHandler is an interface that handles callbacks from the crypto @@ -175,7 +194,8 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStream QuicSession* session, std::unique_ptr<ProofVerifyContext> verify_context, QuicCryptoClientConfig* crypto_config, - ProofHandler* proof_handler); + ProofHandler* proof_handler, + bool has_application_state); QuicCryptoClientStream(const QuicCryptoClientStream&) = delete; QuicCryptoClientStream& operator=(const QuicCryptoClientStream&) = delete; @@ -198,10 +218,16 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStream CryptoMessageParser* crypto_message_parser() override; void OnPacketDecrypted(EncryptionLevel /*level*/) override {} void OnOneRttPacketAcknowledged() override; + void OnHandshakePacketSent() override; + void OnConnectionClosed(QuicErrorCode error, + ConnectionCloseSource source) override; void OnHandshakeDoneReceived() override; HandshakeState GetHandshakeState() const override; size_t BufferSizeLimitForLevel(EncryptionLevel level) const override; + void OnApplicationState( + std::unique_ptr<ApplicationState> application_state) override; + std::string chlo_hash() const; protected: @@ -210,6 +236,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStream } private: + friend class test::QuicCryptoClientStreamPeer; std::unique_ptr<HandshakerInterface> handshaker_; }; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream_test.cc index bcd6a1f536e..6542382d670 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream_test.cc @@ -34,10 +34,12 @@ namespace { const char kServerHostname[] = "test.example.com"; const uint16_t kServerPort = 443; +// This test tests the client-side of the QUIC crypto handshake. It does not +// test the TLS handshake - that is in tls_client_handshaker_test.cc. class QuicCryptoClientStreamTest : public QuicTest { public: QuicCryptoClientStreamTest() - : supported_versions_(AllSupportedVersions()), + : supported_versions_(AllSupportedVersionsWithQuicCrypto()), server_id_(kServerHostname, kServerPort, false), crypto_config_(crypto_test_utils::ProofVerifierForTesting(), std::make_unique<test::SimpleSessionCache>()), @@ -64,26 +66,6 @@ class QuicCryptoClientStreamTest : public QuicTest { CreateSession(); } - void UseTlsHandshake() { - supported_versions_.clear(); - for (ParsedQuicVersion version : AllSupportedVersions()) { - if (version.handshake_protocol != PROTOCOL_TLS1_3) { - continue; - } - supported_versions_.push_back(version); - } - } - - void UseQuicCryptoHandshake() { - supported_versions_.clear(); - for (ParsedQuicVersion version : AllSupportedVersions()) { - if (version.handshake_protocol != PROTOCOL_QUIC_CRYPTO) { - continue; - } - supported_versions_.push_back(version); - } - } - void CompleteCryptoHandshake() { int proof_verify_details_calls = 1; if (stream()->handshake_protocol() != PROTOCOL_TLS1_3) { @@ -127,59 +109,7 @@ TEST_F(QuicCryptoClientStreamTest, ConnectedAfterSHLO) { EXPECT_FALSE(stream()->IsResumption()); } -TEST_F(QuicCryptoClientStreamTest, ConnectedAfterTlsHandshake) { - UseTlsHandshake(); - CreateConnection(); - CompleteCryptoHandshake(); - EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol()); - EXPECT_TRUE(stream()->encryption_established()); - EXPECT_TRUE(stream()->one_rtt_keys_available()); - EXPECT_FALSE(stream()->IsResumption()); -} - -TEST_F(QuicCryptoClientStreamTest, - ProofVerifyDetailsAvailableAfterTlsHandshake) { - UseTlsHandshake(); - CreateConnection(); - - EXPECT_CALL(*session_, OnProofVerifyDetailsAvailable(testing::_)); - stream()->CryptoConnect(); - QuicConfig config; - crypto_test_utils::HandshakeWithFakeServer( - &config, server_crypto_config_.get(), &server_helper_, &alarm_factory_, - connection_, stream(), AlpnForVersion(connection_->version())); - EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol()); - EXPECT_TRUE(stream()->encryption_established()); - EXPECT_TRUE(stream()->one_rtt_keys_available()); -} - -TEST_F(QuicCryptoClientStreamTest, TlsResumption) { - UseTlsHandshake(); - // Enable resumption on the server: - SSL_CTX_clear_options(server_crypto_config_->ssl_ctx(), SSL_OP_NO_TICKET); - CreateConnection(); - - // Finish establishing the first connection: - CompleteCryptoHandshake(); - - EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol()); - EXPECT_TRUE(stream()->encryption_established()); - EXPECT_TRUE(stream()->one_rtt_keys_available()); - EXPECT_FALSE(stream()->IsResumption()); - - // Create a second connection - CreateConnection(); - CompleteCryptoHandshake(); - - EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol()); - EXPECT_TRUE(stream()->encryption_established()); - EXPECT_TRUE(stream()->one_rtt_keys_available()); - EXPECT_TRUE(stream()->IsResumption()); -} - TEST_F(QuicCryptoClientStreamTest, MessageAfterHandshake) { - UseQuicCryptoHandshake(); - CreateConnection(); CompleteCryptoHandshake(); EXPECT_CALL( @@ -191,8 +121,6 @@ TEST_F(QuicCryptoClientStreamTest, MessageAfterHandshake) { } TEST_F(QuicCryptoClientStreamTest, BadMessageType) { - UseQuicCryptoHandshake(); - CreateConnection(); stream()->CryptoConnect(); message_.set_tag(kCHLO); @@ -204,8 +132,6 @@ TEST_F(QuicCryptoClientStreamTest, BadMessageType) { } TEST_F(QuicCryptoClientStreamTest, NegotiatedParameters) { - UseQuicCryptoHandshake(); - CreateConnection(); CompleteCryptoHandshake(); const QuicConfig* config = session_->config(); @@ -218,8 +144,6 @@ TEST_F(QuicCryptoClientStreamTest, NegotiatedParameters) { } TEST_F(QuicCryptoClientStreamTest, ExpiredServerConfig) { - UseQuicCryptoHandshake(); - CreateConnection(); // Seed the config with a cached server config. CompleteCryptoHandshake(); @@ -278,8 +202,6 @@ TEST_F(QuicCryptoClientStreamTest, InvalidCachedServerConfig) { TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdate) { // Test that the crypto client stream can receive server config updates after // the connection has been established. - UseQuicCryptoHandshake(); - CreateConnection(); CompleteCryptoHandshake(); QuicCryptoClientConfig::CachedState* state = @@ -331,8 +253,6 @@ TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdate) { TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdateWithCert) { // Test that the crypto client stream can receive and use server config // updates with certificates after the connection has been established. - UseQuicCryptoHandshake(); - CreateConnection(); CompleteCryptoHandshake(); // Build a server config update message with certificates @@ -365,7 +285,7 @@ TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdateWithCert) { crypto_config.BuildServerConfigUpdateMessage( session_->transport_version(), stream()->chlo_hash(), tokens, QuicSocketAddress(QuicIpAddress::Loopback6(), 1234), - QuicIpAddress::Loopback6(), connection_->clock(), + QuicSocketAddress(QuicIpAddress::Loopback6(), 4321), connection_->clock(), QuicRandom::GetInstance(), &cache, stream()->crypto_negotiated_params(), &network_params, std::unique_ptr<BuildServerConfigUpdateMessageResultCallback>( @@ -388,8 +308,6 @@ TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdateWithCert) { } TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdateBeforeHandshake) { - UseQuicCryptoHandshake(); - CreateConnection(); EXPECT_CALL( *connection_, CloseConnection(QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE, _, _)); @@ -402,7 +320,6 @@ TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdateBeforeHandshake) { TEST_F(QuicCryptoClientStreamTest, PreferredVersion) { // This mimics the case where client receives version negotiation packet, such // that, the preferred version is different from the packets' version. - UseQuicCryptoHandshake(); connection_ = new PacketSavingConnection( &client_helper_, &alarm_factory_, Perspective::IS_CLIENT, ParsedVersionOfIndex(supported_versions_, 1)); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc index c651351702e..66f82298476 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc @@ -129,9 +129,9 @@ void QuicCryptoServerStream::OnHandshakeMessage( DCHECK(process_client_hello_cb_ == nullptr); validate_client_hello_cb_ = cb.get(); crypto_config_->ValidateClientHello( - message, GetClientAddress().host(), - session()->connection()->self_address(), transport_version(), - session()->connection()->clock(), signed_config_, std::move(cb)); + message, GetClientAddress(), session()->connection()->self_address(), + transport_version(), session()->connection()->clock(), signed_config_, + std::move(cb)); } void QuicCryptoServerStream::FinishProcessingHandshakeMessage( @@ -245,7 +245,7 @@ void QuicCryptoServerStream::SendServerConfigUpdate( crypto_config_->BuildServerConfigUpdateMessage( session()->transport_version(), chlo_hash_, previous_source_address_tokens_, session()->connection()->self_address(), - GetClientAddress().host(), session()->connection()->clock(), + GetClientAddress(), session()->connection()->clock(), session()->connection()->random_generator(), compressed_certs_cache_, *crypto_negotiated_params_, cached_network_params, std::move(cb)); } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h index fd14d27a270..52d4874994d 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h @@ -42,6 +42,9 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerStream CachedNetworkParameters cached_network_params) override; void OnPacketDecrypted(EncryptionLevel level) override; void OnOneRttPacketAcknowledged() override {} + void OnHandshakePacketSent() override {} + void OnConnectionClosed(QuicErrorCode /*error*/, + ConnectionCloseSource /*source*/) override {} void OnHandshakeDoneReceived() override; bool ShouldSendExpectCTHeader() const override; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.cc index 0a77ca7aee9..8ea63ba0876 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.cc @@ -37,8 +37,8 @@ std::unique_ptr<QuicCryptoServerStreamBase> CreateCryptoServerStream( return std::unique_ptr<QuicCryptoServerStream>(new QuicCryptoServerStream( crypto_config, compressed_certs_cache, session, helper)); case PROTOCOL_TLS1_3: - return std::unique_ptr<TlsServerHandshaker>(new TlsServerHandshaker( - session, crypto_config->ssl_ctx(), crypto_config->proof_source())); + return std::unique_ptr<TlsServerHandshaker>( + new TlsServerHandshaker(session, *crypto_config)); case PROTOCOL_UNSUPPORTED: break; } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc index 60882b861e2..debfc3b0f52 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc @@ -50,7 +50,9 @@ namespace { const char kServerHostname[] = "test.example.com"; const uint16_t kServerPort = 443; -class QuicCryptoServerStreamTest : public QuicTestWithParam<bool> { +// This test tests the server-side of the QUIC crypto handshake. It does not +// test the TLS handshake - that is in tls_server_handshaker_test.cc. +class QuicCryptoServerStreamTest : public QuicTest { public: QuicCryptoServerStreamTest() : QuicCryptoServerStreamTest(crypto_test_utils::ProofSourceForTesting()) { @@ -152,28 +154,6 @@ class QuicCryptoServerStreamTest : public QuicTestWithParam<bool> { server_connection_, server_stream(), 0); } - void UseTlsHandshake() { - client_options_.only_tls_versions = true; - supported_versions_.clear(); - for (ParsedQuicVersion version : AllSupportedVersions()) { - if (version.handshake_protocol != PROTOCOL_TLS1_3) { - continue; - } - supported_versions_.push_back(version); - } - } - - void UseQuicCryptoHandshake() { - client_options_.only_quic_crypto_versions = true; - supported_versions_.clear(); - for (ParsedQuicVersion version : AllSupportedVersions()) { - if (version.handshake_protocol != PROTOCOL_QUIC_CRYPTO) { - continue; - } - supported_versions_.push_back(version); - } - } - protected: // Every connection gets its own MockQuicConnectionHelper and // MockAlarmFactory, tracked separately from the server and client state so @@ -197,43 +177,28 @@ class QuicCryptoServerStreamTest : public QuicTestWithParam<bool> { crypto_test_utils::FakeClientOptions client_options_; // Which QUIC versions the client and server support. - ParsedQuicVersionVector supported_versions_ = AllSupportedVersions(); + ParsedQuicVersionVector supported_versions_ = + AllSupportedVersionsWithQuicCrypto(); }; -INSTANTIATE_TEST_SUITE_P(Tests, - QuicCryptoServerStreamTest, - ::testing::Bool(), - ::testing::PrintToStringParamName()); - -TEST_P(QuicCryptoServerStreamTest, NotInitiallyConected) { +TEST_F(QuicCryptoServerStreamTest, NotInitiallyConected) { Initialize(); EXPECT_FALSE(server_stream()->encryption_established()); EXPECT_FALSE(server_stream()->one_rtt_keys_available()); } -TEST_P(QuicCryptoServerStreamTest, ConnectedAfterCHLO) { +TEST_F(QuicCryptoServerStreamTest, ConnectedAfterCHLO) { // CompleteCryptoHandshake returns the number of client hellos sent. This // test should send: // * One to get a source-address token and certificates. // * One to complete the handshake. - UseQuicCryptoHandshake(); Initialize(); EXPECT_EQ(2, CompleteCryptoHandshake()); EXPECT_TRUE(server_stream()->encryption_established()); EXPECT_TRUE(server_stream()->one_rtt_keys_available()); } -TEST_P(QuicCryptoServerStreamTest, ConnectedAfterTlsHandshake) { - UseTlsHandshake(); - Initialize(); - CompleteCryptoHandshake(); - EXPECT_EQ(PROTOCOL_TLS1_3, server_stream()->handshake_protocol()); - EXPECT_TRUE(server_stream()->encryption_established()); - EXPECT_TRUE(server_stream()->one_rtt_keys_available()); -} - -TEST_P(QuicCryptoServerStreamTest, ForwardSecureAfterCHLO) { - UseQuicCryptoHandshake(); +TEST_F(QuicCryptoServerStreamTest, ForwardSecureAfterCHLO) { Initialize(); InitializeFakeClient(); @@ -254,8 +219,7 @@ TEST_P(QuicCryptoServerStreamTest, ForwardSecureAfterCHLO) { server_session_->connection()->encryption_level()); } -TEST_P(QuicCryptoServerStreamTest, ZeroRTT) { - UseQuicCryptoHandshake(); +TEST_F(QuicCryptoServerStreamTest, ZeroRTT) { Initialize(); InitializeFakeClient(); @@ -286,8 +250,7 @@ TEST_P(QuicCryptoServerStreamTest, ZeroRTT) { EXPECT_TRUE(server_stream()->ZeroRttAttempted()); } -TEST_P(QuicCryptoServerStreamTest, FailByPolicy) { - UseQuicCryptoHandshake(); +TEST_F(QuicCryptoServerStreamTest, FailByPolicy) { Initialize(); InitializeFakeClient(); @@ -299,8 +262,7 @@ TEST_P(QuicCryptoServerStreamTest, FailByPolicy) { AdvanceHandshakeWithFakeClient(); } -TEST_P(QuicCryptoServerStreamTest, MessageAfterHandshake) { - UseQuicCryptoHandshake(); +TEST_F(QuicCryptoServerStreamTest, MessageAfterHandshake) { Initialize(); CompleteCryptoHandshake(); EXPECT_CALL( @@ -311,8 +273,7 @@ TEST_P(QuicCryptoServerStreamTest, MessageAfterHandshake) { Perspective::IS_CLIENT); } -TEST_P(QuicCryptoServerStreamTest, BadMessageType) { - UseQuicCryptoHandshake(); +TEST_F(QuicCryptoServerStreamTest, BadMessageType) { Initialize(); message_.set_tag(kSHLO); @@ -322,7 +283,7 @@ TEST_P(QuicCryptoServerStreamTest, BadMessageType) { Perspective::IS_SERVER); } -TEST_P(QuicCryptoServerStreamTest, OnlySendSCUPAfterHandshakeComplete) { +TEST_F(QuicCryptoServerStreamTest, OnlySendSCUPAfterHandshakeComplete) { // An attempt to send a SCUP before completing handshake should fail. Initialize(); @@ -330,8 +291,7 @@ TEST_P(QuicCryptoServerStreamTest, OnlySendSCUPAfterHandshakeComplete) { EXPECT_EQ(0, server_stream()->NumServerConfigUpdateMessagesSent()); } -TEST_P(QuicCryptoServerStreamTest, SendSCUPAfterHandshakeComplete) { - UseQuicCryptoHandshake(); +TEST_F(QuicCryptoServerStreamTest, SendSCUPAfterHandshakeComplete) { Initialize(); InitializeFakeClient(); @@ -363,13 +323,7 @@ class QuicCryptoServerStreamTestWithFailingProofSource std::unique_ptr<FailingProofSource>(new FailingProofSource)) {} }; -INSTANTIATE_TEST_SUITE_P(MoreTests, - QuicCryptoServerStreamTestWithFailingProofSource, - ::testing::Bool(), - ::testing::PrintToStringParamName()); - -TEST_P(QuicCryptoServerStreamTestWithFailingProofSource, Test) { - UseQuicCryptoHandshake(); +TEST_F(QuicCryptoServerStreamTestWithFailingProofSource, Test) { Initialize(); InitializeFakeClient(); @@ -399,16 +353,10 @@ class QuicCryptoServerStreamTestWithFakeProofSource QuicCryptoServerConfigPeer crypto_config_peer_; }; -INSTANTIATE_TEST_SUITE_P(YetMoreTests, - QuicCryptoServerStreamTestWithFakeProofSource, - ::testing::Bool(), - ::testing::PrintToStringParamName()); - // Regression test for b/35422225, in which multiple CHLOs arriving on the same // connection in close succession could cause a crash, especially when the use // of Mentat signing meant that it took a while for each CHLO to be processed. -TEST_P(QuicCryptoServerStreamTestWithFakeProofSource, MultipleChlo) { - UseQuicCryptoHandshake(); +TEST_F(QuicCryptoServerStreamTestWithFakeProofSource, MultipleChlo) { Initialize(); GetFakeProofSource()->Activate(); EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _, _, _)) diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.cc index 094613c7395..20704fb627a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.cc @@ -38,8 +38,7 @@ QuicCryptoStream::QuicCryptoStream(QuicSession* session) substreams_{{{this, ENCRYPTION_INITIAL}, {this, ENCRYPTION_HANDSHAKE}, {this, ENCRYPTION_ZERO_RTT}, - {this, ENCRYPTION_FORWARD_SECURE}}}, - writevdata_at_level_(GetQuicReloadableFlag(quic_writevdata_at_level)) { + {this, ENCRYPTION_FORWARD_SECURE}}} { // The crypto stream is exempt from connection level flow control. DisableConnectionFlowControlForThisStream(); } @@ -200,16 +199,20 @@ void QuicCryptoStream::OnStreamReset(const QuicRstStreamFrame& /*frame*/) { } void QuicCryptoStream::NeuterUnencryptedStreamData() { + NeuterStreamDataOfEncryptionLevel(ENCRYPTION_INITIAL); +} + +void QuicCryptoStream::NeuterStreamDataOfEncryptionLevel( + EncryptionLevel level) { if (!QuicVersionUsesCryptoFrames(session()->transport_version())) { - for (const auto& interval : bytes_consumed_[ENCRYPTION_INITIAL]) { + for (const auto& interval : bytes_consumed_[level]) { QuicByteCount newly_acked_length = 0; send_buffer().OnStreamDataAcked( interval.min(), interval.max() - interval.min(), &newly_acked_length); } return; } - QuicStreamSendBuffer* send_buffer = - &substreams_[ENCRYPTION_INITIAL].send_buffer; + QuicStreamSendBuffer* send_buffer = &substreams_[level].send_buffer; // TODO(nharper): Consider adding a Clear() method to QuicStreamSendBuffer to // replace the following code. QuicIntervalSet<QuicStreamOffset> to_ack = send_buffer->bytes_acked(); @@ -221,7 +224,7 @@ void QuicCryptoStream::NeuterUnencryptedStreamData() { } } -void QuicCryptoStream::OnStreamDataConsumed(size_t bytes_consumed) { +void QuicCryptoStream::OnStreamDataConsumed(QuicByteCount bytes_consumed) { if (QuicVersionUsesCryptoFrames(session()->transport_version())) { QUIC_BUG << "Stream data consumed when CRYPTO frames should be in use"; } @@ -232,12 +235,21 @@ void QuicCryptoStream::OnStreamDataConsumed(size_t bytes_consumed) { QuicStream::OnStreamDataConsumed(bytes_consumed); } +namespace { + +constexpr std::array<EncryptionLevel, NUM_ENCRYPTION_LEVELS> +AllEncryptionLevels() { + return {ENCRYPTION_INITIAL, ENCRYPTION_HANDSHAKE, ENCRYPTION_ZERO_RTT, + ENCRYPTION_FORWARD_SECURE}; +} + +} // namespace + bool QuicCryptoStream::HasPendingCryptoRetransmission() const { if (!QuicVersionUsesCryptoFrames(session()->transport_version())) { return false; } - for (EncryptionLevel level : - {ENCRYPTION_INITIAL, ENCRYPTION_ZERO_RTT, ENCRYPTION_FORWARD_SECURE}) { + for (EncryptionLevel level : AllEncryptionLevels()) { if (substreams_[level].send_buffer.HasPendingRetransmission()) { return true; } @@ -248,8 +260,7 @@ bool QuicCryptoStream::HasPendingCryptoRetransmission() const { void QuicCryptoStream::WritePendingCryptoRetransmission() { QUIC_BUG_IF(!QuicVersionUsesCryptoFrames(session()->transport_version())) << "Versions less than 47 don't write CRYPTO frames"; - for (EncryptionLevel level : - {ENCRYPTION_INITIAL, ENCRYPTION_ZERO_RTT, ENCRYPTION_FORWARD_SECURE}) { + for (EncryptionLevel level : AllEncryptionLevels()) { QuicStreamSendBuffer* send_buffer = &substreams_[level].send_buffer; while (send_buffer->HasPendingRetransmission()) { auto pending = send_buffer->NextPendingRetransmission(); @@ -283,33 +294,9 @@ void QuicCryptoStream::WritePendingRetransmission() { pending.offset = retransmission.begin()->min(); pending.length = retransmission.begin()->max() - retransmission.begin()->min(); - QuicConsumedData consumed(0, false); - if (!writevdata_at_level_) { - EncryptionLevel current_encryption_level = - session()->connection()->encryption_level(); - // Set appropriate encryption level. - session()->connection()->SetDefaultEncryptionLevel( - retransmission_encryption_level); - consumed = stream_delegate()->WritevData( - id(), pending.length, pending.offset, NO_FIN, - HANDSHAKE_RETRANSMISSION, QuicheNullOpt); - QUIC_DVLOG(1) << ENDPOINT << "stream " << id() - << " tries to retransmit stream data [" << pending.offset - << ", " << pending.offset + pending.length - << ") with encryption level: " - << retransmission_encryption_level - << ", consumed: " << consumed; - OnStreamFrameRetransmitted(pending.offset, consumed.bytes_consumed, - consumed.fin_consumed); - // Restore encryption level. - session()->connection()->SetDefaultEncryptionLevel( - current_encryption_level); - } else { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_writevdata_at_level, 1, 2); - consumed = RetransmitStreamDataAtLevel(pending.offset, pending.length, - retransmission_encryption_level, - HANDSHAKE_RETRANSMISSION); - } + QuicConsumedData consumed = RetransmitStreamDataAtLevel( + pending.offset, pending.length, retransmission_encryption_level, + HANDSHAKE_RETRANSMISSION); if (consumed.bytes_consumed < pending.length) { // The connection is write blocked. break; @@ -334,35 +321,12 @@ bool QuicCryptoStream::RetransmitStreamData(QuicStreamOffset offset, } } retransmission.Difference(bytes_acked()); - EncryptionLevel current_encryption_level = - session()->connection()->encryption_level(); for (const auto& interval : retransmission) { QuicStreamOffset retransmission_offset = interval.min(); QuicByteCount retransmission_length = interval.max() - interval.min(); - QuicConsumedData consumed(0, false); - if (!writevdata_at_level_) { - // Set appropriate encryption level. - session()->connection()->SetDefaultEncryptionLevel(send_encryption_level); - consumed = stream_delegate()->WritevData(id(), retransmission_length, - retransmission_offset, NO_FIN, - type, QuicheNullOpt); - QUIC_DVLOG(1) << ENDPOINT << "stream " << id() - << " is forced to retransmit stream data [" - << retransmission_offset << ", " - << retransmission_offset + retransmission_length - << "), with encryption level: " << send_encryption_level - << ", consumed: " << consumed; - OnStreamFrameRetransmitted(retransmission_offset, consumed.bytes_consumed, - consumed.fin_consumed); - // Restore encryption level. - session()->connection()->SetDefaultEncryptionLevel( - current_encryption_level); - } else { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_writevdata_at_level, 2, 2); - consumed = RetransmitStreamDataAtLevel(retransmission_offset, - retransmission_length, - send_encryption_level, type); - } + QuicConsumedData consumed = RetransmitStreamDataAtLevel( + retransmission_offset, retransmission_length, send_encryption_level, + type); if (consumed.bytes_consumed < retransmission_length) { // The connection is write blocked. return false; @@ -378,7 +342,6 @@ QuicConsumedData QuicCryptoStream::RetransmitStreamDataAtLevel( EncryptionLevel encryption_level, TransmissionType type) { DCHECK_EQ(HANDSHAKE_RETRANSMISSION, type); - DCHECK(writevdata_at_level_); const auto consumed = stream_delegate()->WritevData( id(), retransmission_length, retransmission_offset, NO_FIN, type, encryption_level); @@ -398,9 +361,11 @@ uint64_t QuicCryptoStream::crypto_bytes_read() const { if (!QuicVersionUsesCryptoFrames(session()->transport_version())) { return stream_bytes_read(); } - return substreams_[ENCRYPTION_INITIAL].sequencer.NumBytesConsumed() + - substreams_[ENCRYPTION_ZERO_RTT].sequencer.NumBytesConsumed() + - substreams_[ENCRYPTION_FORWARD_SECURE].sequencer.NumBytesConsumed(); + uint64_t bytes_read = 0; + for (EncryptionLevel level : AllEncryptionLevels()) { + bytes_read += substreams_[level].sequencer.NumBytesConsumed(); + } + return bytes_read; } uint64_t QuicCryptoStream::BytesReadOnLevel(EncryptionLevel level) const { @@ -453,8 +418,7 @@ void QuicCryptoStream::RetransmitData(QuicCryptoFrame* crypto_frame, void QuicCryptoStream::WriteBufferedCryptoFrames() { QUIC_BUG_IF(!QuicVersionUsesCryptoFrames(session()->transport_version())) << "Versions less than 47 don't use CRYPTO frames"; - for (EncryptionLevel level : - {ENCRYPTION_INITIAL, ENCRYPTION_ZERO_RTT, ENCRYPTION_FORWARD_SECURE}) { + for (EncryptionLevel level : AllEncryptionLevels()) { QuicStreamSendBuffer* send_buffer = &substreams_[level].send_buffer; const size_t data_length = send_buffer->stream_offset() - send_buffer->stream_bytes_written(); @@ -476,8 +440,7 @@ void QuicCryptoStream::WriteBufferedCryptoFrames() { bool QuicCryptoStream::HasBufferedCryptoFrames() const { QUIC_BUG_IF(!QuicVersionUsesCryptoFrames(session()->transport_version())) << "Versions less than 47 don't use CRYPTO frames"; - for (EncryptionLevel level : - {ENCRYPTION_INITIAL, ENCRYPTION_ZERO_RTT, ENCRYPTION_FORWARD_SECURE}) { + for (EncryptionLevel level : AllEncryptionLevels()) { const QuicStreamSendBuffer& send_buffer = substreams_[level].send_buffer; DCHECK_GE(send_buffer.stream_offset(), send_buffer.stream_bytes_written()); if (send_buffer.stream_offset() > send_buffer.stream_bytes_written()) { @@ -506,8 +469,7 @@ bool QuicCryptoStream::IsWaitingForAcks() const { if (!QuicVersionUsesCryptoFrames(session()->transport_version())) { return QuicStream::IsWaitingForAcks(); } - for (EncryptionLevel level : - {ENCRYPTION_INITIAL, ENCRYPTION_ZERO_RTT, ENCRYPTION_FORWARD_SECURE}) { + for (EncryptionLevel level : AllEncryptionLevels()) { if (substreams_[level].send_buffer.stream_bytes_outstanding()) { return true; } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h index 82f81fe9832..49d37042390 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h @@ -91,6 +91,9 @@ class QUIC_EXPORT_PRIVATE QuicCryptoStream : public QuicStream { // Called when a 1RTT packet has been acknowledged. virtual void OnOneRttPacketAcknowledged() = 0; + // Called when a packet of ENCRYPTION_HANDSHAKE gets sent. + virtual void OnHandshakePacketSent() = 0; + // Called when a handshake done frame has been received. virtual void OnHandshakeDoneReceived() = 0; @@ -104,8 +107,11 @@ class QUIC_EXPORT_PRIVATE QuicCryptoStream : public QuicStream { // Called to cancel retransmission of unencrypted crypto stream data. void NeuterUnencryptedStreamData(); + // Called to cancel retransmission of data of encryption |level|. + void NeuterStreamDataOfEncryptionLevel(EncryptionLevel level); + // Override to record the encryption level of consumed data. - void OnStreamDataConsumed(size_t bytes_consumed) override; + void OnStreamDataConsumed(QuicByteCount bytes_consumed) override; // Returns whether there are any bytes pending retransmission in CRYPTO // frames. @@ -197,9 +203,6 @@ class QUIC_EXPORT_PRIVATE QuicCryptoStream : public QuicStream { // Keeps state for data sent/received in CRYPTO frames at each encryption // level. std::array<CryptoSubstream, NUM_ENCRYPTION_LEVELS> substreams_; - - // Latched value of gfe2_reloadable_flag_quic_writevdata_at_level. - const bool writevdata_at_level_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream_test.cc index 436e572308b..5f414e6a98a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream_test.cc @@ -58,6 +58,7 @@ class MockQuicCryptoStream : public QuicCryptoStream, } void OnPacketDecrypted(EncryptionLevel /*level*/) override {} void OnOneRttPacketAcknowledged() override {} + void OnHandshakePacketSent() override {} void OnHandshakeDoneReceived() override {} HandshakeState GetHandshakeState() const override { return HANDSHAKE_START; } @@ -253,6 +254,48 @@ TEST_F(QuicCryptoStreamTest, RetransmitCryptoDataInCryptoFrames) { EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level()); } +// Regression test for handling the missing ENCRYPTION_HANDSHAKE in +// quic_crypto_stream.cc. This test is essentially the same as +// RetransmitCryptoDataInCryptoFrames, except it uses ENCRYPTION_HANDSHAKE in +// place of ENCRYPTION_ZERO_RTT. +TEST_F(QuicCryptoStreamTest, RetransmitEncryptionHandshakeLevelCryptoFrames) { + if (!QuicVersionUsesCryptoFrames(connection_->transport_version())) { + return; + } + EXPECT_CALL(*connection_, SendCryptoData(_, _, _)).Times(0); + InSequence s; + // Send [0, 1000) in ENCRYPTION_INITIAL. + EXPECT_EQ(ENCRYPTION_INITIAL, connection_->encryption_level()); + std::string data(1000, 'a'); + EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_INITIAL, 1000, 0)) + .WillOnce(Invoke(connection_, + &MockQuicConnection::QuicConnection_SendCryptoData)); + stream_->WriteCryptoData(ENCRYPTION_INITIAL, data); + // Send [1000, 2000) in ENCRYPTION_HANDSHAKE. + connection_->SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE); + std::unique_ptr<NullEncrypter> encrypter = + std::make_unique<NullEncrypter>(Perspective::IS_CLIENT); + connection_->SetEncrypter(ENCRYPTION_HANDSHAKE, std::move(encrypter)); + EXPECT_EQ(ENCRYPTION_HANDSHAKE, connection_->encryption_level()); + EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_HANDSHAKE, 1000, 0)) + .WillOnce(Invoke(connection_, + &MockQuicConnection::QuicConnection_SendCryptoData)); + stream_->WriteCryptoData(ENCRYPTION_HANDSHAKE, data); + connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level()); + + // Lost [1000, 1200). + QuicCryptoFrame lost_frame(ENCRYPTION_HANDSHAKE, 0, 200); + stream_->OnCryptoFrameLost(&lost_frame); + EXPECT_TRUE(stream_->HasPendingCryptoRetransmission()); + // Verify [1000, 1200) is sent. + EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_HANDSHAKE, 200, 0)) + .WillOnce(Invoke(connection_, + &MockQuicConnection::QuicConnection_SendCryptoData)); + stream_->WritePendingCryptoRetransmission(); + EXPECT_FALSE(stream_->HasPendingCryptoRetransmission()); +} + TEST_F(QuicCryptoStreamTest, NeuterUnencryptedStreamData) { if (QuicVersionUsesCryptoFrames(connection_->transport_version())) { return; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.cc b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.cc index c160ced24b6..c0d39700f41 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.cc @@ -15,6 +15,7 @@ #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quic/core/quic_versions.h" +#include "net/third_party/quiche/src/quic/core/tls_chlo_extractor.h" #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" @@ -60,14 +61,11 @@ class PacketCollector : public QuicPacketCreator::DelegateInterface, ~PacketCollector() override = default; // QuicPacketCreator::DelegateInterface methods: - void OnSerializedPacket(SerializedPacket* serialized_packet) override { + void OnSerializedPacket(SerializedPacket serialized_packet) override { // Make a copy of the serialized packet to send later. packets_.emplace_back( - new QuicEncryptedPacket(CopyBuffer(*serialized_packet), - serialized_packet->encrypted_length, true)); - serialized_packet->encrypted_buffer = nullptr; - DeleteFrames(&(serialized_packet->retransmittable_frames)); - serialized_packet->retransmittable_frames.clear(); + new QuicEncryptedPacket(CopyBuffer(serialized_packet), + serialized_packet.encrypted_length, true)); } char* GetPacketBuffer() override { @@ -180,7 +178,7 @@ class StatelessConnectionTerminator { QuicTimeWaitListManager* time_wait_list_manager_; }; -// Class which extracts the ALPN from a CHLO packet. +// Class which extracts the ALPN from a QUIC_CRYPTO CHLO packet. class ChloAlpnExtractor : public ChloExtractor::Delegate { public: void OnChlo(QuicTransportVersion /*version*/, @@ -310,7 +308,7 @@ void QuicDispatcher::ProcessPacket(const QuicSocketAddress& self_address, QuicConnectionId QuicDispatcher::MaybeReplaceServerConnectionId( QuicConnectionId server_connection_id, - ParsedQuicVersion version) { + ParsedQuicVersion version) const { if (server_connection_id.length() == expected_server_connection_id_length_) { return server_connection_id; } @@ -476,16 +474,42 @@ void QuicDispatcher::ProcessHeader(ReceivedPacketInfo* packet_info) { QuicConnectionId server_connection_id = packet_info->destination_connection_id; // Packet's connection ID is unknown. Apply the validity checks. - // TODO(wub): Determine the fate completely in ValidityChecks, then call - // ProcessUnauthenticatedHeaderFate in one place. QuicPacketFate fate = ValidityChecks(*packet_info); ChloAlpnExtractor alpn_extractor; switch (fate) { case kFateProcess: { if (packet_info->version.handshake_protocol == PROTOCOL_TLS1_3) { - // TODO(nharper): Support buffering non-ClientHello packets when using - // TLS. - ProcessChlo(/*alpn=*/"", packet_info); + bool has_full_tls_chlo = false; + std::vector<std::string> alpns; + if (buffered_packets_.HasBufferedPackets( + packet_info->destination_connection_id)) { + // If we already have buffered packets for this connection ID, + // use the associated TlsChloExtractor to parse this packet. + has_full_tls_chlo = + buffered_packets_.IngestPacketForTlsChloExtraction( + packet_info->destination_connection_id, packet_info->version, + packet_info->packet, &alpns); + } else { + // If we do not have a BufferedPacketList for this connection ID, + // create a single-use one to check whether this packet contains a + // full single-packet CHLO. + TlsChloExtractor tls_chlo_extractor; + tls_chlo_extractor.IngestPacket(packet_info->version, + packet_info->packet); + if (tls_chlo_extractor.HasParsedFullChlo()) { + // This packet contains a full single-packet CHLO. + has_full_tls_chlo = true; + alpns = tls_chlo_extractor.alpns(); + } + } + if (has_full_tls_chlo) { + ProcessChlo(alpns, packet_info); + } else { + // This packet does not contain a full CHLO. It could be a 0-RTT + // packet that arrived before the CHLO (due to loss or reordering), + // or it could be a fragment of a multi-packet CHLO. + BufferEarlyPacket(*packet_info); + } break; } if (GetQuicFlag(FLAGS_quic_allow_chlo_buffering) && @@ -497,7 +521,7 @@ void QuicDispatcher::ProcessHeader(ReceivedPacketInfo* packet_info) { BufferEarlyPacket(*packet_info); break; } - ProcessChlo(alpn_extractor.ConsumeAlpn(), packet_info); + ProcessChlo({alpn_extractor.ConsumeAlpn()}, packet_info); } break; case kFateTimeWait: // Add this connection_id to the time-wait state, to safely reject @@ -524,36 +548,55 @@ void QuicDispatcher::ProcessHeader(ReceivedPacketInfo* packet_info) { } } +std::string QuicDispatcher::SelectAlpn(const std::vector<std::string>& alpns) { + if (alpns.empty()) { + return ""; + } + if (alpns.size() > 1u) { + const std::vector<std::string>& supported_alpns = + version_manager_->GetSupportedAlpns(); + for (const std::string& alpn : alpns) { + if (std::find(supported_alpns.begin(), supported_alpns.end(), alpn) != + supported_alpns.end()) { + return alpn; + } + } + } + return alpns[0]; +} + QuicDispatcher::QuicPacketFate QuicDispatcher::ValidityChecks( const ReceivedPacketInfo& packet_info) { if (!packet_info.version_flag) { - // The Android network conformance test contains a UDP test that sends a - // 12-byte packet with the following format: - // - 0x0c (public flags: 8-byte connection ID, 1-byte packet number) - // - randomized 8-byte connection ID - // - 0x01 (1-byte packet number) - // - 0x00 (private flags) - // - 0x07 (PING frame). - // That packet is invalid and we would normally drop it but in order to - // unblock this conformance testing we have the following workaround that - // will be removed once the fixed test is deployed. - // TODO(b/139691956) Remove this workaround once fixed test is deployed. - if (packet_info.packet.length() == 12 && - packet_info.packet.data()[0] == 0x0c && - packet_info.packet.data()[9] == 0x01 && - packet_info.packet.data()[10] == 0x00 && - packet_info.packet.data()[11] == 0x07) { - QUIC_DLOG(INFO) << "Received Android UDP network conformance test " - "packet with connection ID " - << packet_info.destination_connection_id; - // Respond with a public reset that the test will know how to parse - // then return kFateDrop to stop processing of this packet. - time_wait_list_manager()->SendPublicReset( - packet_info.self_address, packet_info.peer_address, - packet_info.destination_connection_id, - /*ietf_quic=*/false, GetPerPacketContext()); - return kFateDrop; - } + // The Android network conformance test contains a UDP test that sends a + // 12-byte packet with the following format: + // - 0x0c (public flags: 8-byte connection ID, 1-byte packet number) + // - randomized 8-byte connection ID + // - 0x01 (1-byte packet number) + // - 0x00 (private flags) + // - 0x07 (PING frame). + // That packet is invalid and we would normally drop it but in order to + // unblock this conformance testing we have the following workaround that + // will be removed once the fixed test is deployed. + // TODO(b/139691956) Remove this workaround once fixed test is deployed. + if (!GetQuicReloadableFlag( + quic_remove_android_conformance_test_workaround) && + packet_info.packet.length() == 12 && + packet_info.packet.data()[0] == 0x0c && + packet_info.packet.data()[9] == 0x01 && + packet_info.packet.data()[10] == 0x00 && + packet_info.packet.data()[11] == 0x07) { + QUIC_DLOG(INFO) << "Received Android UDP network conformance test " + "packet with connection ID " + << packet_info.destination_connection_id; + // Respond with a public reset that the test will know how to parse + // then return kFateDrop to stop processing of this packet. + time_wait_list_manager()->SendPublicReset( + packet_info.self_address, packet_info.peer_address, + packet_info.destination_connection_id, + /*ietf_quic=*/false, GetPerPacketContext()); + return kFateDrop; + } QUIC_DLOG(INFO) << "Packet without version arrived for unknown connection ID " @@ -574,7 +617,12 @@ void QuicDispatcher::CleanUpSession(SessionMap::iterator it, QuicTimeWaitListManager::SEND_STATELESS_RESET; if (connection->termination_packets() != nullptr && !connection->termination_packets()->empty()) { - action = QuicTimeWaitListManager::SEND_TERMINATION_PACKETS; + if (GetQuicRestartFlag(quic_replace_time_wait_list_encryption_level)) { + QUIC_RESTART_FLAG_COUNT(quic_replace_time_wait_list_encryption_level); + action = QuicTimeWaitListManager::SEND_CONNECTION_CLOSE_PACKETS; + } else { + action = QuicTimeWaitListManager::SEND_TERMINATION_PACKETS; + } } else { if (!connection->IsHandshakeComplete()) { if (!VersionHasIetfInvariantHeader(connection->transport_version())) { @@ -831,9 +879,10 @@ void QuicDispatcher::ProcessBufferedChlos(size_t max_connections_to_create) { QuicConnectionId original_connection_id = server_connection_id; server_connection_id = MaybeReplaceServerConnectionId(server_connection_id, packet_list.version); + std::string alpn = SelectAlpn(packet_list.alpns); std::unique_ptr<QuicSession> session = CreateQuicSession(server_connection_id, packets.front().peer_address, - packet_list.alpn, packet_list.version); + alpn, packet_list.version); if (original_connection_id != server_connection_id) { session->connection()->AddIncomingConnectionId(original_connection_id); session->connection()->InstallInitialCrypters(original_connection_id); @@ -889,13 +938,13 @@ void QuicDispatcher::BufferEarlyPacket(const ReceivedPacketInfo& packet_info) { packet_info.destination_connection_id, packet_info.form != GOOGLE_QUIC_PACKET, packet_info.packet, packet_info.self_address, packet_info.peer_address, /*is_chlo=*/false, - /*alpn=*/"", packet_info.version); + /*alpns=*/{}, packet_info.version); if (rs != EnqueuePacketResult::SUCCESS) { OnBufferPacketFailure(rs, packet_info.destination_connection_id); } } -void QuicDispatcher::ProcessChlo(const std::string& alpn, +void QuicDispatcher::ProcessChlo(const std::vector<std::string>& alpns, ReceivedPacketInfo* packet_info) { if (!buffered_packets_.HasBufferedPackets( packet_info->destination_connection_id) && @@ -911,7 +960,7 @@ void QuicDispatcher::ProcessChlo(const std::string& alpn, packet_info->destination_connection_id, packet_info->form != GOOGLE_QUIC_PACKET, packet_info->packet, packet_info->self_address, packet_info->peer_address, - /*is_chlo=*/true, alpn, packet_info->version); + /*is_chlo=*/true, alpns, packet_info->version); if (rs != EnqueuePacketResult::SUCCESS) { OnBufferPacketFailure(rs, packet_info->destination_connection_id); } @@ -923,6 +972,7 @@ void QuicDispatcher::ProcessChlo(const std::string& alpn, packet_info->destination_connection_id = MaybeReplaceServerConnectionId( original_connection_id, packet_info->version); // Creates a new session and process all buffered packets for this connection. + std::string alpn = SelectAlpn(alpns); std::unique_ptr<QuicSession> session = CreateQuicSession(packet_info->destination_connection_id, packet_info->peer_address, alpn, packet_info->version); @@ -975,6 +1025,11 @@ const ParsedQuicVersionVector& QuicDispatcher::GetSupportedVersions() { return version_manager_->GetSupportedVersions(); } +const ParsedQuicVersionVector& +QuicDispatcher::GetSupportedVersionsWithQuicCrypto() { + return version_manager_->GetSupportedVersionsWithQuicCrypto(); +} + void QuicDispatcher::DeliverPacketsToSession( const std::list<BufferedPacket>& packets, QuicSession* session) { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.h b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.h index 71cbb5771be..73ab3ec4fd0 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.h @@ -196,7 +196,8 @@ class QUIC_NO_EXPORT QuicDispatcher // Called when |packet_info| is a CHLO packet. Creates a new connection and // delivers any buffered packets for that connection id. - void ProcessChlo(const std::string& alpn, ReceivedPacketInfo* packet_info); + void ProcessChlo(const std::vector<std::string>& alpns, + ReceivedPacketInfo* packet_info); // Return true if dispatcher wants to destroy session outside of // OnConnectionClosed() call stack. @@ -210,6 +211,8 @@ class QUIC_NO_EXPORT QuicDispatcher const ParsedQuicVersionVector& GetSupportedVersions(); + const ParsedQuicVersionVector& GetSupportedVersionsWithQuicCrypto(); + const QuicConfig& config() const { return *config_; } const QuicCryptoServerConfig* crypto_config() const { return crypto_config_; } @@ -298,12 +301,22 @@ class QUIC_NO_EXPORT QuicDispatcher // Called if a packet from an unseen connection is reset or rejected. virtual void OnNewConnectionRejected() {} + // Selects the preferred ALPN from a vector of ALPNs. + // This runs through the list of ALPNs provided by the client and picks the + // first one it supports. If no supported versions are found, the first + // element of the vector is returned. + std::string SelectAlpn(const std::vector<std::string>& alpns); + + // If the connection ID length is different from what the dispatcher expects, + // replace the connection ID with a random one of the right length, + // and save it to make sure the mapping is persistent. + QuicConnectionId MaybeReplaceServerConnectionId( + QuicConnectionId server_connection_id, + ParsedQuicVersion version) const; + private: friend class test::QuicDispatcherPeer; - typedef QuicUnorderedSet<QuicConnectionId, QuicConnectionIdHash> - QuicConnectionIdSet; - // TODO(fayang): Consider to rename this function to // ProcessValidatedPacketWithUnknownConnectionId. void ProcessHeader(ReceivedPacketInfo* packet_info); @@ -313,13 +326,6 @@ class QUIC_NO_EXPORT QuicDispatcher const std::list<QuicBufferedPacketStore::BufferedPacket>& packets, QuicSession* session); - // If the connection ID length is different from what the dispatcher expects, - // replace the connection ID with a random one of the right length, - // and save it to make sure the mapping is persistent. - QuicConnectionId MaybeReplaceServerConnectionId( - QuicConnectionId server_connection_id, - ParsedQuicVersion version); - // Returns true if |version| is a supported protocol version. bool IsSupportedVersion(const ParsedQuicVersion version); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc index 7e54dd24cf0..814462e9d01 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc @@ -14,6 +14,7 @@ #include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" +#include "net/third_party/quiche/src/quic/core/quic_config.h" #include "net/third_party/quiche/src/quic/core/quic_connection_id.h" #include "net/third_party/quiche/src/quic/core/quic_crypto_stream.h" #include "net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.h" @@ -27,6 +28,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" #include "net/third_party/quiche/src/quic/test_tools/fake_proof_source.h" +#include "net/third_party/quiche/src/quic/test_tools/first_flight.h" #include "net/third_party/quiche/src/quic/test_tools/mock_quic_time_wait_list_manager.h" #include "net/third_party/quiche/src/quic/test_tools/quic_buffered_packet_store_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_crypto_server_config_peer.h" @@ -78,13 +80,27 @@ class TestQuicSpdyServerSession : public QuicServerSessionBase { ~TestQuicSpdyServerSession() override { DeleteConnection(); } - MOCK_METHOD2(OnConnectionClosed, - void(const QuicConnectionCloseFrame& frame, - ConnectionCloseSource source)); - MOCK_METHOD1(CreateIncomingStream, QuicSpdyStream*(QuicStreamId id)); - MOCK_METHOD1(CreateIncomingStream, QuicSpdyStream*(PendingStream* pending)); - MOCK_METHOD0(CreateOutgoingBidirectionalStream, QuicSpdyStream*()); - MOCK_METHOD0(CreateOutgoingUnidirectionalStream, QuicSpdyStream*()); + MOCK_METHOD(void, + OnConnectionClosed, + (const QuicConnectionCloseFrame& frame, + ConnectionCloseSource source), + (override)); + MOCK_METHOD(QuicSpdyStream*, + CreateIncomingStream, + (QuicStreamId id), + (override)); + MOCK_METHOD(QuicSpdyStream*, + CreateIncomingStream, + (PendingStream*), + (override)); + MOCK_METHOD(QuicSpdyStream*, + CreateOutgoingBidirectionalStream, + (), + (override)); + MOCK_METHOD(QuicSpdyStream*, + CreateOutgoingUnidirectionalStream, + (), + (override)); std::unique_ptr<QuicCryptoServerStreamBase> CreateQuicCryptoServerStream( const QuicCryptoServerConfig* crypto_config, @@ -114,15 +130,18 @@ class TestDispatcher : public QuicDispatcher { kQuicDefaultConnectionIdLength), random_(random) {} - MOCK_METHOD4( - CreateQuicSession, - std::unique_ptr<QuicSession>(QuicConnectionId connection_id, - const QuicSocketAddress& peer_address, - quiche::QuicheStringPiece alpn, - const quic::ParsedQuicVersion& version)); + MOCK_METHOD(std::unique_ptr<QuicSession>, + CreateQuicSession, + (QuicConnectionId connection_id, + const QuicSocketAddress& peer_address, + quiche::QuicheStringPiece alpn, + const quic::ParsedQuicVersion& version), + (override)); - MOCK_METHOD1(ShouldCreateOrBufferPacketForConnection, - bool(const ReceivedPacketInfo& packet_info)); + MOCK_METHOD(bool, + ShouldCreateOrBufferPacketForConnection, + (const ReceivedPacketInfo& packet_info), + (override)); struct TestQuicPerPacketContext : public QuicPerPacketContext { std::string custom_packet_context; @@ -201,7 +220,7 @@ class QuicDispatcherTestBase : public QuicTestWithParam<ParsedQuicVersion> { connection_id_(1) {} void SetUp() override { - dispatcher_->InitializeWithWriter(new MockPacketWriter()); + dispatcher_->InitializeWithWriter(new NiceMock<MockPacketWriter>()); // Set the counter to some value to start with. QuicDispatcherPeer::set_new_sessions_allowed_per_event_loop( dispatcher_.get(), kMaxNumSessionsToCreate); @@ -294,17 +313,26 @@ class QuicDispatcherTestBase : public QuicTestWithParam<ParsedQuicVersion> { client_connection_id_included, packet_number_length, &versions)); std::unique_ptr<QuicReceivedPacket> received_packet( ConstructReceivedPacket(*packet, mock_helper_.GetClock()->Now())); + ProcessReceivedPacket(std::move(received_packet), peer_address, version, + server_connection_id); + } - if (ChloExtractor::Extract(*packet, version, {}, nullptr, + void ProcessReceivedPacket( + std::unique_ptr<QuicReceivedPacket> received_packet, + const QuicSocketAddress& peer_address, + const ParsedQuicVersion& version, + const QuicConnectionId& server_connection_id) { + if (version.UsesQuicCrypto() && + ChloExtractor::Extract(*received_packet, version, {}, nullptr, server_connection_id.length())) { // Add CHLO packet to the beginning to be verified first, because it is // also processed first by new session. data_connection_map_[server_connection_id].push_front( - std::string(packet->data(), packet->length())); + std::string(received_packet->data(), received_packet->length())); } else { // For non-CHLO, always append to last. data_connection_map_[server_connection_id].push_back( - std::string(packet->data(), packet->length())); + std::string(received_packet->data(), received_packet->length())); } dispatcher_->ProcessPacket(server_address_, peer_address, *received_packet); } @@ -353,16 +381,56 @@ class QuicDispatcherTestBase : public QuicTestWithParam<ParsedQuicVersion> { std::string SerializeCHLO() { CryptoHandshakeMessage client_hello; client_hello.set_tag(kCHLO); - client_hello.SetStringPiece(kALPN, "hq"); + client_hello.SetStringPiece(kALPN, ExpectedAlpn()); return std::string(client_hello.GetSerialized().AsStringPiece()); } - std::string ExpectedAlpnForVersion(ParsedQuicVersion version) { - if (version.handshake_protocol == PROTOCOL_TLS1_3) { - // TODO(b/149597791) Remove this once we can parse ALPN with TLS. - return ""; + void ProcessUndecryptableEarlyPacket( + const QuicSocketAddress& peer_address, + const QuicConnectionId& server_connection_id) { + ProcessUndecryptableEarlyPacket(version_, peer_address, + server_connection_id); + } + + void ProcessUndecryptableEarlyPacket( + const ParsedQuicVersion& version, + const QuicSocketAddress& peer_address, + const QuicConnectionId& server_connection_id) { + std::unique_ptr<QuicEncryptedPacket> encrypted_packet = + GetUndecryptableEarlyPacket(version, server_connection_id); + std::unique_ptr<QuicReceivedPacket> received_packet(ConstructReceivedPacket( + *encrypted_packet, mock_helper_.GetClock()->Now())); + ProcessReceivedPacket(std::move(received_packet), peer_address, version, + server_connection_id); + } + + void ProcessFirstFlight(const QuicSocketAddress& peer_address, + const QuicConnectionId& server_connection_id) { + ProcessFirstFlight(version_, peer_address, server_connection_id); + } + + void ProcessFirstFlight(const ParsedQuicVersion& version, + const QuicSocketAddress& peer_address, + const QuicConnectionId& server_connection_id) { + ProcessFirstFlight(version, peer_address, server_connection_id, + EmptyQuicConnectionId()); + } + + void ProcessFirstFlight(const ParsedQuicVersion& version, + const QuicSocketAddress& peer_address, + const QuicConnectionId& server_connection_id, + const QuicConnectionId& client_connection_id) { + std::vector<std::unique_ptr<QuicReceivedPacket>> packets = + GetFirstFlightOfPackets(version, server_connection_id, + client_connection_id); + for (auto&& packet : packets) { + ProcessReceivedPacket(std::move(packet), peer_address, version, + server_connection_id); } - return "hq"; + } + + std::string ExpectedAlpnForVersion(ParsedQuicVersion version) { + return AlpnForVersion(version); } std::string ExpectedAlpn() { return ExpectedAlpnForVersion(version_); } @@ -388,8 +456,7 @@ class QuicDispatcherTestBase : public QuicTestWithParam<ParsedQuicVersion> { EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection( ReceivedPacketInfoConnectionIdEquals(connection_id))); - ProcessPacket(client_address, connection_id, true, version, SerializeCHLO(), - true, CONNECTION_ID_PRESENT, PACKET_4BYTE_PACKET_NUMBER, 1); + ProcessFirstFlight(version, client_address, connection_id); } void VerifyVersionNotSupported(ParsedQuicVersion version) { @@ -398,10 +465,11 @@ class QuicDispatcherTestBase : public QuicTestWithParam<ParsedQuicVersion> { EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address, _, _)) .Times(0); - ProcessPacket(client_address, connection_id, true, version, SerializeCHLO(), - true, CONNECTION_ID_PRESENT, PACKET_4BYTE_PACKET_NUMBER, 1); + ProcessFirstFlight(version, client_address, connection_id); } + void TestTlsMultiPacketClientHello(bool add_reordering); + ParsedQuicVersion version_; MockQuicConnectionHelper mock_helper_; MockAlarmFactory mock_alarm_factory_; @@ -432,7 +500,7 @@ INSTANTIATE_TEST_SUITE_P(QuicDispatcherTestsOneVersion, ::testing::PrintToStringParamName()); TEST_P(QuicDispatcherTestAllVersions, TlsClientHelloCreatesSession) { - if (version_.handshake_protocol != PROTOCOL_TLS1_3) { + if (version_.UsesQuicCrypto()) { return; } QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); @@ -452,9 +520,64 @@ TEST_P(QuicDispatcherTestAllVersions, TlsClientHelloCreatesSession) { EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection( ReceivedPacketInfoConnectionIdEquals(TestConnectionId(1)))); - ProcessPacket(client_address, TestConnectionId(1), true, version_, - SerializeCHLO(), true, CONNECTION_ID_PRESENT, - PACKET_4BYTE_PACKET_NUMBER, 1); + + ProcessFirstFlight(client_address, TestConnectionId(1)); +} + +void QuicDispatcherTestBase::TestTlsMultiPacketClientHello( + bool add_reordering) { + if (!version_.UsesTls()) { + return; + } + QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); + QuicConnectionId server_connection_id = TestConnectionId(); + QuicConfig client_config = DefaultQuicConfig(); + // Add a 2000-byte custom parameter to increase the length of the CHLO. + constexpr auto kCustomParameterId = + static_cast<TransportParameters::TransportParameterId>(0xff33); + std::string kCustomParameterValue(2000, '-'); + client_config.custom_transport_parameters_to_send()[kCustomParameterId] = + kCustomParameterValue; + std::vector<std::unique_ptr<QuicReceivedPacket>> packets = + GetFirstFlightOfPackets(version_, client_config, server_connection_id); + ASSERT_EQ(packets.size(), 2u); + if (add_reordering) { + std::swap(packets[0], packets[1]); + } + + // Processing the first packet should not create a new session. + EXPECT_CALL(*dispatcher_, + ShouldCreateOrBufferPacketForConnection( + ReceivedPacketInfoConnectionIdEquals(server_connection_id))); + ProcessReceivedPacket(std::move(packets[0]), client_address, version_, + server_connection_id); + + EXPECT_EQ(dispatcher_->session_map().size(), 0u) + << "No session should be created before the rest of the CHLO arrives."; + + // Processing the second packet should create the new session. + EXPECT_CALL(*dispatcher_, + CreateQuicSession(server_connection_id, client_address, + Eq(ExpectedAlpn()), _)) + .WillOnce(Return(ByMove(CreateSession( + dispatcher_.get(), config_, server_connection_id, client_address, + &mock_helper_, &mock_alarm_factory_, &crypto_config_, + QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)))); + EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()), + ProcessUdpPacket(_, _, _)) + .Times(2); + + ProcessReceivedPacket(std::move(packets[1]), client_address, version_, + server_connection_id); + EXPECT_EQ(dispatcher_->session_map().size(), 1u); +} + +TEST_P(QuicDispatcherTestAllVersions, TlsMultiPacketClientHello) { + TestTlsMultiPacketClientHello(/*add_reordering=*/false); +} + +TEST_P(QuicDispatcherTestAllVersions, TlsMultiPacketClientHelloWithReordering) { + TestTlsMultiPacketClientHello(/*add_reordering=*/true); } TEST_P(QuicDispatcherTestAllVersions, ProcessPackets) { @@ -475,7 +598,7 @@ TEST_P(QuicDispatcherTestAllVersions, ProcessPackets) { EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection( ReceivedPacketInfoConnectionIdEquals(TestConnectionId(1)))); - ProcessPacket(client_address, TestConnectionId(1), true, SerializeCHLO()); + ProcessFirstFlight(client_address, TestConnectionId(1)); EXPECT_CALL(*dispatcher_, CreateQuicSession(TestConnectionId(2), client_address, @@ -492,7 +615,7 @@ TEST_P(QuicDispatcherTestAllVersions, ProcessPackets) { EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection( ReceivedPacketInfoConnectionIdEquals(TestConnectionId(2)))); - ProcessPacket(client_address, TestConnectionId(2), true, SerializeCHLO()); + ProcessFirstFlight(client_address, TestConnectionId(2)); EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()), ProcessUdpPacket(_, _, _)) @@ -525,9 +648,7 @@ TEST_P(QuicDispatcherTestAllVersions, DispatcherDoesNotRejectPacketNumberZero) { EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection( ReceivedPacketInfoConnectionIdEquals(TestConnectionId(1)))); - ProcessPacket(client_address, TestConnectionId(1), true, version_, - SerializeCHLO(), true, CONNECTION_ID_PRESENT, - PACKET_4BYTE_PACKET_NUMBER, 1); + ProcessFirstFlight(client_address, TestConnectionId(1)); // Packet number 256 with packet number length 1 would be considered as 0 in // dispatcher. ProcessPacket(client_address, TestConnectionId(1), false, version_, "", true, @@ -543,13 +664,8 @@ TEST_P(QuicDispatcherTestOneVersion, StatelessVersionNegotiation) { *time_wait_list_manager_, SendVersionNegotiationPacket(TestConnectionId(1), _, _, _, _, _, _, _)) .Times(1); - // Pad the CHLO message with enough data to make the packet large enough - // to trigger version negotiation. - std::string chlo = SerializeCHLO() + std::string(1200, 'a'); - DCHECK_LE(1200u, chlo.length()); - ProcessPacket(client_address, TestConnectionId(1), true, - QuicVersionReservedForNegotiation(), chlo, true, - CONNECTION_ID_PRESENT, PACKET_4BYTE_PACKET_NUMBER, 1); + ProcessFirstFlight(QuicVersionReservedForNegotiation(), client_address, + TestConnectionId(1)); } TEST_P(QuicDispatcherTestOneVersion, @@ -562,13 +678,8 @@ TEST_P(QuicDispatcherTestOneVersion, EXPECT_CALL(*time_wait_list_manager_, SendVersionNegotiationPacket(connection_id, _, _, _, _, _, _, _)) .Times(1); - // Pad the CHLO message with enough data to make the packet large enough - // to trigger version negotiation. - std::string chlo = SerializeCHLO() + std::string(1200, 'a'); - DCHECK_LE(1200u, chlo.length()); - ProcessPacket(client_address, connection_id, true, - QuicVersionReservedForNegotiation(), chlo, true, - CONNECTION_ID_PRESENT, PACKET_4BYTE_PACKET_NUMBER, 1); + ProcessFirstFlight(QuicVersionReservedForNegotiation(), client_address, + connection_id); } TEST_P(QuicDispatcherTestOneVersion, @@ -581,14 +692,8 @@ TEST_P(QuicDispatcherTestOneVersion, SendVersionNegotiationPacket( TestConnectionId(1), TestConnectionId(2), _, _, _, _, _, _)) .Times(1); - // Pad the CHLO message with enough data to make the packet large enough - // to trigger version negotiation. - std::string chlo = SerializeCHLO() + std::string(1200, 'a'); - DCHECK_LE(1200u, chlo.length()); - ProcessPacket(client_address, TestConnectionId(1), TestConnectionId(2), true, - QuicVersionReservedForNegotiation(), chlo, true, - CONNECTION_ID_PRESENT, CONNECTION_ID_PRESENT, - PACKET_4BYTE_PACKET_NUMBER, 1); + ProcessFirstFlight(QuicVersionReservedForNegotiation(), client_address, + TestConnectionId(1), TestConnectionId(2)); } TEST_P(QuicDispatcherTestOneVersion, NoVersionNegotiationWithSmallPacket) { @@ -652,7 +757,7 @@ TEST_P(QuicDispatcherTestAllVersions, Shutdown) { EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection( ReceivedPacketInfoConnectionIdEquals(TestConnectionId(1)))); - ProcessPacket(client_address, TestConnectionId(1), true, SerializeCHLO()); + ProcessFirstFlight(client_address, TestConnectionId(1)); EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()), CloseConnection(QUIC_PEER_GOING_AWAY, _, _)); @@ -681,7 +786,7 @@ TEST_P(QuicDispatcherTestAllVersions, TimeWaitListManager) { EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection( ReceivedPacketInfoConnectionIdEquals(TestConnectionId(1)))); - ProcessPacket(client_address, connection_id, true, SerializeCHLO()); + ProcessFirstFlight(client_address, connection_id); // Now close the connection, which should add it to the time wait list. session1_->connection()->CloseConnection( @@ -717,7 +822,8 @@ TEST_P(QuicDispatcherTestAllVersions, NoVersionPacketToTimeWaitListManager) { .Times(0); EXPECT_CALL(*time_wait_list_manager_, SendPublicReset(_, _, _, _, _)) .Times(1); - ProcessPacket(client_address, connection_id, false, SerializeCHLO()); + ProcessPacket(client_address, connection_id, /*has_version_flag=*/false, + "data"); } TEST_P(QuicDispatcherTestAllVersions, @@ -772,7 +878,7 @@ TEST_P(QuicDispatcherTestAllVersions, LongConnectionIdLengthReplaced) { EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection( ReceivedPacketInfoConnectionIdEquals(bad_connection_id))); - ProcessPacket(client_address, bad_connection_id, true, SerializeCHLO()); + ProcessFirstFlight(client_address, bad_connection_id); } // Makes sure zero-byte connection IDs are replaced by 8-byte ones. @@ -809,7 +915,7 @@ TEST_P(QuicDispatcherTestAllVersions, InvalidShortConnectionIdLengthReplaced) { EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection( ReceivedPacketInfoConnectionIdEquals(bad_connection_id))); - ProcessPacket(client_address, bad_connection_id, true, SerializeCHLO()); + ProcessFirstFlight(client_address, bad_connection_id); } // Makes sure TestConnectionId(1) creates a new connection and @@ -839,7 +945,7 @@ TEST_P(QuicDispatcherTestAllVersions, MixGoodAndBadConnectionIdLengthPackets) { EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection( ReceivedPacketInfoConnectionIdEquals(TestConnectionId(1)))); - ProcessPacket(client_address, TestConnectionId(1), true, SerializeCHLO()); + ProcessFirstFlight(client_address, TestConnectionId(1)); EXPECT_CALL(*dispatcher_, CreateQuicSession(fixed_connection_id, client_address, @@ -857,7 +963,7 @@ TEST_P(QuicDispatcherTestAllVersions, MixGoodAndBadConnectionIdLengthPackets) { EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection( ReceivedPacketInfoConnectionIdEquals(bad_connection_id))); - ProcessPacket(client_address, bad_connection_id, true, SerializeCHLO()); + ProcessFirstFlight(client_address, bad_connection_id); EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()), ProcessUdpPacket(_, _, _)) @@ -881,7 +987,8 @@ TEST_P(QuicDispatcherTestAllVersions, ProcessPacketWithZeroPort) { EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _, _, _)) .Times(0); - ProcessPacket(client_address, TestConnectionId(1), true, SerializeCHLO()); + ProcessPacket(client_address, TestConnectionId(1), /*has_version_flag=*/true, + "data"); } TEST_P(QuicDispatcherTestAllVersions, @@ -900,10 +1007,14 @@ TEST_P(QuicDispatcherTestAllVersions, EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _, _, _)) .Times(0); - ProcessPacket(client_address, EmptyQuicConnectionId(), true, SerializeCHLO()); + ProcessFirstFlight(client_address, EmptyQuicConnectionId()); } TEST_P(QuicDispatcherTestAllVersions, OKSeqNoPacketProcessed) { + if (version_.UsesTls()) { + // QUIC+TLS allows clients to start with any packet number. + return; + } QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); QuicConnectionId connection_id = TestConnectionId(1); @@ -1165,7 +1276,10 @@ TEST_P(QuicDispatcherTestOneVersion, VersionNegotiationProbeEndToEnd) { } TEST_P(QuicDispatcherTestOneVersion, AndroidConformanceTestOld) { - // TODO(b/139691956) Remove this test once the workaround is removed. + if (GetQuicReloadableFlag(quic_remove_android_conformance_test_workaround)) { + // TODO(b/139691956) Remove this test once the flag is deprecated. + return; + } SavingWriter* saving_writer = new SavingWriter(); // dispatcher_ takes ownership of saving_writer. QuicDispatcherPeer::UseWriter(dispatcher_.get(), saving_writer); @@ -1339,7 +1453,7 @@ TEST_P(QuicDispatcherTestAllVersions, StopAcceptingNewConnections) { .WillOnce(WithArg<2>(Invoke([this](const QuicEncryptedPacket& packet) { ValidatePacket(TestConnectionId(1), packet); }))); - ProcessPacket(client_address, TestConnectionId(1), true, SerializeCHLO()); + ProcessFirstFlight(client_address, TestConnectionId(1)); dispatcher_->StopAcceptingNewConnections(); EXPECT_FALSE(dispatcher_->accept_new_connections()); @@ -1349,7 +1463,7 @@ TEST_P(QuicDispatcherTestAllVersions, StopAcceptingNewConnections) { CreateQuicSession(TestConnectionId(2), client_address, Eq(ExpectedAlpn()), _)) .Times(0u); - ProcessPacket(client_address, TestConnectionId(2), true, SerializeCHLO()); + ProcessFirstFlight(client_address, TestConnectionId(2)); // Existing connections should be able to continue. EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()), @@ -1370,7 +1484,7 @@ TEST_P(QuicDispatcherTestAllVersions, StartAcceptingNewConnections) { CreateQuicSession(TestConnectionId(2), client_address, Eq(ExpectedAlpn()), _)) .Times(0u); - ProcessPacket(client_address, TestConnectionId(2), true, SerializeCHLO()); + ProcessFirstFlight(client_address, TestConnectionId(2)); dispatcher_->StartAcceptingNewConnections(); EXPECT_TRUE(dispatcher_->accept_new_connections()); @@ -1387,7 +1501,18 @@ TEST_P(QuicDispatcherTestAllVersions, StartAcceptingNewConnections) { .WillOnce(WithArg<2>(Invoke([this](const QuicEncryptedPacket& packet) { ValidatePacket(TestConnectionId(1), packet); }))); - ProcessPacket(client_address, TestConnectionId(1), true, SerializeCHLO()); + ProcessFirstFlight(client_address, TestConnectionId(1)); +} + +TEST_P(QuicDispatcherTestOneVersion, SelectAlpn) { + EXPECT_EQ(QuicDispatcherPeer::SelectAlpn(dispatcher_.get(), {}), ""); + EXPECT_EQ(QuicDispatcherPeer::SelectAlpn(dispatcher_.get(), {""}), ""); + EXPECT_EQ(QuicDispatcherPeer::SelectAlpn(dispatcher_.get(), {"hq"}), "hq"); + // Q033 is no longer supported but Q050 is. + QuicEnableVersion(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50)); + EXPECT_EQ( + QuicDispatcherPeer::SelectAlpn(dispatcher_.get(), {"h3-Q033", "h3-Q050"}), + "h3-Q050"); } // Verify the stopgap test: Packets with truncated connection IDs should be @@ -1462,7 +1587,7 @@ class QuicDispatcherWriteBlockedListTest : public QuicDispatcherTestBase { EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection( ReceivedPacketInfoConnectionIdEquals(TestConnectionId(1)))); - ProcessPacket(client_address, TestConnectionId(1), true, SerializeCHLO()); + ProcessFirstFlight(client_address, TestConnectionId(1)); EXPECT_CALL(*dispatcher_, CreateQuicSession(_, client_address, Eq(ExpectedAlpn()), _)) @@ -1478,7 +1603,7 @@ class QuicDispatcherWriteBlockedListTest : public QuicDispatcherTestBase { EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection( ReceivedPacketInfoConnectionIdEquals(TestConnectionId(2)))); - ProcessPacket(client_address, TestConnectionId(2), true, SerializeCHLO()); + ProcessFirstFlight(client_address, TestConnectionId(2)); blocked_list_ = QuicDispatcherPeer::GetWriteBlockedList(dispatcher_.get()); } @@ -1724,69 +1849,100 @@ class BufferedPacketStoreTest : public QuicDispatcherTestBase { public: BufferedPacketStoreTest() : QuicDispatcherTestBase(), - server_addr_(QuicSocketAddress(QuicIpAddress::Any4(), 5)), - client_addr_(QuicIpAddress::Loopback4(), 1234), - signed_config_(new QuicSignedServerConfig) {} + client_addr_(QuicIpAddress::Loopback4(), 1234) {} - void SetUp() override { - QuicDispatcherTestBase::SetUp(); - clock_ = QuicDispatcherPeer::GetHelper(dispatcher_.get())->GetClock(); + void ProcessFirstFlight(const ParsedQuicVersion& version, + const QuicSocketAddress& peer_address, + const QuicConnectionId& server_connection_id) { + QuicDispatcherTestBase::ProcessFirstFlight(version, peer_address, + server_connection_id); + } - ASSERT_EQ(PROTOCOL_QUIC_CRYPTO, version_.handshake_protocol); - ASSERT_NE(QUIC_VERSION_UNSUPPORTED, version_.transport_version); + void ProcessFirstFlight(const QuicSocketAddress& peer_address, + const QuicConnectionId& server_connection_id) { + ProcessFirstFlight(version_, peer_address, server_connection_id); + } - CryptoHandshakeMessage chlo = - crypto_test_utils::GenerateDefaultInchoateCHLO( - clock_, version_.transport_version, &crypto_config_); - // Pass an inchoate CHLO. - crypto_test_utils::GenerateFullCHLO( - chlo, &crypto_config_, server_addr_, client_addr_, - version_.transport_version, clock_, signed_config_, - QuicDispatcherPeer::GetCache(dispatcher_.get()), &full_chlo_); + void ProcessFirstFlight(const QuicConnectionId& server_connection_id) { + ProcessFirstFlight(client_addr_, server_connection_id); } - std::string SerializeFullCHLO() { - return std::string(full_chlo_.GetSerialized().AsStringPiece()); + void ProcessFirstFlight(const ParsedQuicVersion& version, + const QuicConnectionId& server_connection_id) { + ProcessFirstFlight(version, client_addr_, server_connection_id); + } + + void ProcessUndecryptableEarlyPacket( + const ParsedQuicVersion& version, + const QuicSocketAddress& peer_address, + const QuicConnectionId& server_connection_id) { + QuicDispatcherTestBase::ProcessUndecryptableEarlyPacket( + version, peer_address, server_connection_id); + } + + void ProcessUndecryptableEarlyPacket( + const QuicSocketAddress& peer_address, + const QuicConnectionId& server_connection_id) { + ProcessUndecryptableEarlyPacket(version_, peer_address, + server_connection_id); + } + + void ProcessUndecryptableEarlyPacket( + const QuicConnectionId& server_connection_id) { + ProcessUndecryptableEarlyPacket(version_, client_addr_, + server_connection_id); } protected: - QuicSocketAddress server_addr_; QuicSocketAddress client_addr_; - QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config_; - const QuicClock* clock_; - CryptoHandshakeMessage full_chlo_; }; -ParsedQuicVersionVector BufferedPacketStoreTestParams() { - ParsedQuicVersionVector versions; - for (const ParsedQuicVersion& version : CurrentSupportedVersions()) { - if (version.handshake_protocol != PROTOCOL_QUIC_CRYPTO) { - // TODO(b/149597791) Remove this once we can parse ALPN with TLS. - break; - } - versions.push_back(version); - } - return versions; -} - INSTANTIATE_TEST_SUITE_P(BufferedPacketStoreTests, BufferedPacketStoreTest, - ::testing::ValuesIn(BufferedPacketStoreTestParams()), + ::testing::ValuesIn(CurrentSupportedVersions()), ::testing::PrintToStringParamName()); +TEST_P(BufferedPacketStoreTest, ProcessNonChloPacketBeforeChlo) { + InSequence s; + QuicConnectionId conn_id = TestConnectionId(1); + // Non-CHLO should be buffered upon arrival, and should trigger + // ShouldCreateOrBufferPacketForConnection(). + EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection( + ReceivedPacketInfoConnectionIdEquals(conn_id))); + // Process non-CHLO packet. + ProcessUndecryptableEarlyPacket(conn_id); + EXPECT_EQ(0u, dispatcher_->session_map().size()) + << "No session should be created before CHLO arrives."; + + // When CHLO arrives, a new session should be created, and all packets + // buffered should be delivered to the session. + EXPECT_CALL(*dispatcher_, + CreateQuicSession(conn_id, client_addr_, Eq(ExpectedAlpn()), _)) + .WillOnce(Return(ByMove(CreateSession( + dispatcher_.get(), config_, conn_id, client_addr_, &mock_helper_, + &mock_alarm_factory_, &crypto_config_, + QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)))); + EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()), + ProcessUdpPacket(_, _, _)) + .Times(2) // non-CHLO + CHLO. + .WillRepeatedly( + WithArg<2>(Invoke([this, conn_id](const QuicEncryptedPacket& packet) { + if (version_.UsesQuicCrypto()) { + ValidatePacket(conn_id, packet); + } + }))); + ProcessFirstFlight(conn_id); +} + TEST_P(BufferedPacketStoreTest, ProcessNonChloPacketsUptoLimitAndProcessChlo) { InSequence s; - QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); QuicConnectionId conn_id = TestConnectionId(1); // A bunch of non-CHLO should be buffered upon arrival, and the first one // should trigger ShouldCreateOrBufferPacketForConnection(). EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection( ReceivedPacketInfoConnectionIdEquals(conn_id))); for (size_t i = 1; i <= kDefaultMaxUndecryptablePackets + 1; ++i) { - ProcessPacket(client_address, conn_id, true, - quiche::QuicheStrCat("data packet ", i + 1), - CONNECTION_ID_PRESENT, PACKET_4BYTE_PACKET_NUMBER, - /*packet_number=*/i + 1); + ProcessUndecryptableEarlyPacket(conn_id); } EXPECT_EQ(0u, dispatcher_->session_map().size()) << "No session should be created before CHLO arrives."; @@ -1795,10 +1951,10 @@ TEST_P(BufferedPacketStoreTest, ProcessNonChloPacketsUptoLimitAndProcessChlo) { data_connection_map_[conn_id].pop_back(); // When CHLO arrives, a new session should be created, and all packets // buffered should be delivered to the session. - EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_address, - quiche::QuicheStringPiece(), _)) + EXPECT_CALL(*dispatcher_, + CreateQuicSession(conn_id, client_addr_, Eq(ExpectedAlpn()), _)) .WillOnce(Return(ByMove(CreateSession( - dispatcher_.get(), config_, conn_id, client_address, &mock_helper_, + dispatcher_.get(), config_, conn_id, client_addr_, &mock_helper_, &mock_alarm_factory_, &crypto_config_, QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)))); @@ -1809,9 +1965,11 @@ TEST_P(BufferedPacketStoreTest, ProcessNonChloPacketsUptoLimitAndProcessChlo) { .Times(kDefaultMaxUndecryptablePackets + 1) // + 1 for CHLO. .WillRepeatedly( WithArg<2>(Invoke([this, conn_id](const QuicEncryptedPacket& packet) { - ValidatePacket(conn_id, packet); + if (version_.UsesQuicCrypto()) { + ValidatePacket(conn_id, packet); + } }))); - ProcessPacket(client_address, conn_id, true, SerializeFullCHLO()); + ProcessFirstFlight(conn_id); } TEST_P(BufferedPacketStoreTest, @@ -1825,10 +1983,7 @@ TEST_P(BufferedPacketStoreTest, EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection( ReceivedPacketInfoConnectionIdEquals(conn_id))); - ProcessPacket(client_address, conn_id, true, - quiche::QuicheStrCat("data packet on connection ", i), - CONNECTION_ID_PRESENT, PACKET_4BYTE_PACKET_NUMBER, - /*packet_number=*/2); + ProcessUndecryptableEarlyPacket(client_address, conn_id); } // Pop out the packet on last connection as it shouldn't be enqueued in store @@ -1849,7 +2004,7 @@ TEST_P(BufferedPacketStoreTest, ReceivedPacketInfoConnectionIdEquals(conn_id))); } EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_address, - quiche::QuicheStringPiece(), _)) + Eq(ExpectedAlpn()), _)) .WillOnce(Return(ByMove(CreateSession( dispatcher_.get(), config_, conn_id, client_address, &mock_helper_, &mock_alarm_factory_, &crypto_config_, @@ -1862,48 +2017,45 @@ TEST_P(BufferedPacketStoreTest, .Times(num_packet_to_process) .WillRepeatedly(WithArg<2>( Invoke([this, conn_id](const QuicEncryptedPacket& packet) { - ValidatePacket(conn_id, packet); + if (version_.UsesQuicCrypto()) { + ValidatePacket(conn_id, packet); + } }))); - ProcessPacket(client_address, conn_id, true, SerializeFullCHLO()); + ProcessFirstFlight(client_address, conn_id); } } // Tests that store delivers empty packet list if CHLO arrives firstly. TEST_P(BufferedPacketStoreTest, DeliverEmptyPackets) { QuicConnectionId conn_id = TestConnectionId(1); - QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection( ReceivedPacketInfoConnectionIdEquals(conn_id))); - EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_address, - quiche::QuicheStringPiece(), _)) + EXPECT_CALL(*dispatcher_, + CreateQuicSession(conn_id, client_addr_, Eq(ExpectedAlpn()), _)) .WillOnce(Return(ByMove(CreateSession( - dispatcher_.get(), config_, conn_id, client_address, &mock_helper_, + dispatcher_.get(), config_, conn_id, client_addr_, &mock_helper_, &mock_alarm_factory_, &crypto_config_, QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)))); EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()), - ProcessUdpPacket(_, client_address, _)); - ProcessPacket(client_address, conn_id, true, SerializeFullCHLO()); + ProcessUdpPacket(_, client_addr_, _)); + ProcessFirstFlight(conn_id); } // Tests that a retransmitted CHLO arrives after a connection for the // CHLO has been created. TEST_P(BufferedPacketStoreTest, ReceiveRetransmittedCHLO) { InSequence s; - QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); QuicConnectionId conn_id = TestConnectionId(1); - ProcessPacket(client_address, conn_id, true, - quiche::QuicheStrCat("data packet ", 2), CONNECTION_ID_PRESENT, - PACKET_4BYTE_PACKET_NUMBER, - /*packet_number=*/2); + ProcessUndecryptableEarlyPacket(conn_id); // When CHLO arrives, a new session should be created, and all packets // buffered should be delivered to the session. - EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_address, - quiche::QuicheStringPiece(), _)) + EXPECT_CALL(*dispatcher_, + CreateQuicSession(conn_id, client_addr_, Eq(ExpectedAlpn()), _)) .Times(1) // Only triggered by 1st CHLO. .WillOnce(Return(ByMove(CreateSession( - dispatcher_.get(), config_, conn_id, client_address, &mock_helper_, + dispatcher_.get(), config_, conn_id, client_addr_, &mock_helper_, &mock_alarm_factory_, &crypto_config_, QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)))); EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()), @@ -1911,11 +2063,18 @@ TEST_P(BufferedPacketStoreTest, ReceiveRetransmittedCHLO) { .Times(3) // Triggered by 1 data packet and 2 CHLOs. .WillRepeatedly( WithArg<2>(Invoke([this, conn_id](const QuicEncryptedPacket& packet) { - ValidatePacket(conn_id, packet); + if (version_.UsesQuicCrypto()) { + ValidatePacket(conn_id, packet); + } }))); - ProcessPacket(client_address, conn_id, true, SerializeFullCHLO()); - ProcessPacket(client_address, conn_id, true, SerializeFullCHLO()); + std::vector<std::unique_ptr<QuicReceivedPacket>> packets = + GetFirstFlightOfPackets(version_, conn_id); + ASSERT_EQ(packets.size(), 1u); + // Receive the CHLO once. + ProcessReceivedPacket(packets[0]->Clone(), client_addr_, version_, conn_id); + // Receive the CHLO a second time to simulate retransmission. + ProcessReceivedPacket(std::move(packets[0]), client_addr_, version_, conn_id); } // Tests that expiration of a connection add connection id to time wait list. @@ -1926,9 +2085,8 @@ TEST_P(BufferedPacketStoreTest, ReceiveCHLOAfterExpiration) { QuicDispatcherPeer::GetBufferedPackets(dispatcher_.get()); QuicBufferedPacketStorePeer::set_clock(store, mock_helper_.GetClock()); - QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); QuicConnectionId conn_id = TestConnectionId(1); - ProcessPacket(client_address, conn_id, true, + ProcessPacket(client_addr_, conn_id, true, quiche::QuicheStrCat("data packet ", 2), CONNECTION_ID_PRESENT, PACKET_4BYTE_PACKET_NUMBER, /*packet_number=*/2); @@ -1943,7 +2101,7 @@ TEST_P(BufferedPacketStoreTest, ReceiveCHLOAfterExpiration) { // list. ASSERT_TRUE(time_wait_list_manager_->IsConnectionIdInTimeWait(conn_id)); EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, conn_id, _, _)); - ProcessPacket(client_address, conn_id, true, SerializeFullCHLO()); + ProcessFirstFlight(conn_id); } TEST_P(BufferedPacketStoreTest, ProcessCHLOsUptoLimitAndBufferTheRest) { @@ -1964,7 +2122,7 @@ TEST_P(BufferedPacketStoreTest, ProcessCHLOsUptoLimitAndBufferTheRest) { if (conn_id <= kMaxNumSessionsToCreate) { EXPECT_CALL(*dispatcher_, CreateQuicSession(TestConnectionId(conn_id), client_addr_, - quiche::QuicheStringPiece(), _)) + Eq(ExpectedAlpn()), _)) .WillOnce(Return(ByMove(CreateSession( dispatcher_.get(), config_, TestConnectionId(conn_id), client_addr_, &mock_helper_, &mock_alarm_factory_, @@ -1975,11 +2133,12 @@ TEST_P(BufferedPacketStoreTest, ProcessCHLOsUptoLimitAndBufferTheRest) { ProcessUdpPacket(_, _, _)) .WillOnce(WithArg<2>( Invoke([this, conn_id](const QuicEncryptedPacket& packet) { - ValidatePacket(TestConnectionId(conn_id), packet); + if (version_.UsesQuicCrypto()) { + ValidatePacket(TestConnectionId(conn_id), packet); + } }))); } - ProcessPacket(client_addr_, TestConnectionId(conn_id), true, - SerializeFullCHLO()); + ProcessFirstFlight(TestConnectionId(conn_id)); if (conn_id <= kMaxNumSessionsToCreate + kDefaultMaxConnectionsInStore && conn_id > kMaxNumSessionsToCreate) { EXPECT_TRUE(store->HasChloForConnection(TestConnectionId(conn_id))); @@ -1998,7 +2157,7 @@ TEST_P(BufferedPacketStoreTest, ProcessCHLOsUptoLimitAndBufferTheRest) { ++conn_id) { EXPECT_CALL(*dispatcher_, CreateQuicSession(TestConnectionId(conn_id), client_addr_, - quiche::QuicheStringPiece(), _)) + Eq(ExpectedAlpn()), _)) .WillOnce(Return(ByMove(CreateSession( dispatcher_.get(), config_, TestConnectionId(conn_id), client_addr_, &mock_helper_, &mock_alarm_factory_, &crypto_config_, @@ -2007,12 +2166,14 @@ TEST_P(BufferedPacketStoreTest, ProcessCHLOsUptoLimitAndBufferTheRest) { ProcessUdpPacket(_, _, _)) .WillOnce(WithArg<2>( Invoke([this, conn_id](const QuicEncryptedPacket& packet) { - ValidatePacket(TestConnectionId(conn_id), packet); + if (version_.UsesQuicCrypto()) { + ValidatePacket(TestConnectionId(conn_id), packet); + } }))); } EXPECT_CALL(*dispatcher_, CreateQuicSession(TestConnectionId(kNumCHLOs), client_addr_, - quiche::QuicheStringPiece(), _)) + Eq(ExpectedAlpn()), _)) .Times(0); while (store->HasChlosBuffered()) { @@ -2032,7 +2193,7 @@ TEST_P(BufferedPacketStoreTest, BufferDuplicatedCHLO) { if (conn_id <= kMaxNumSessionsToCreate) { EXPECT_CALL(*dispatcher_, CreateQuicSession(TestConnectionId(conn_id), client_addr_, - quiche::QuicheStringPiece(), _)) + Eq(ExpectedAlpn()), _)) .WillOnce(Return(ByMove(CreateSession( dispatcher_.get(), config_, TestConnectionId(conn_id), client_addr_, &mock_helper_, &mock_alarm_factory_, @@ -2043,22 +2204,23 @@ TEST_P(BufferedPacketStoreTest, BufferDuplicatedCHLO) { ProcessUdpPacket(_, _, _)) .WillOnce(WithArg<2>( Invoke([this, conn_id](const QuicEncryptedPacket& packet) { - ValidatePacket(TestConnectionId(conn_id), packet); + if (version_.UsesQuicCrypto()) { + ValidatePacket(TestConnectionId(conn_id), packet); + } }))); } - ProcessPacket(client_addr_, TestConnectionId(conn_id), true, - SerializeFullCHLO()); + ProcessFirstFlight(TestConnectionId(conn_id)); } // Retransmit CHLO on last connection should be dropped. QuicConnectionId last_connection = TestConnectionId(kMaxNumSessionsToCreate + 1); - ProcessPacket(client_addr_, last_connection, true, SerializeFullCHLO()); + ProcessFirstFlight(last_connection); size_t packets_buffered = 2; // Reset counter and process buffered CHLO. EXPECT_CALL(*dispatcher_, CreateQuicSession(last_connection, client_addr_, - quiche::QuicheStringPiece(), _)) + Eq(ExpectedAlpn()), _)) .WillOnce(Return(ByMove(CreateSession( dispatcher_.get(), config_, last_connection, client_addr_, &mock_helper_, &mock_alarm_factory_, &crypto_config_, @@ -2069,7 +2231,9 @@ TEST_P(BufferedPacketStoreTest, BufferDuplicatedCHLO) { .Times(packets_buffered) .WillRepeatedly(WithArg<2>( Invoke([this, last_connection](const QuicEncryptedPacket& packet) { - ValidatePacket(last_connection, packet); + if (version_.UsesQuicCrypto()) { + ValidatePacket(last_connection, packet); + } }))); dispatcher_->ProcessBufferedChlos(kMaxNumSessionsToCreate); } @@ -2082,7 +2246,7 @@ TEST_P(BufferedPacketStoreTest, BufferNonChloPacketsUptoLimitWithChloBuffered) { if (conn_id <= kMaxNumSessionsToCreate) { EXPECT_CALL(*dispatcher_, CreateQuicSession(TestConnectionId(conn_id), client_addr_, - quiche::QuicheStringPiece(), _)) + Eq(ExpectedAlpn()), _)) .WillOnce(Return(ByMove(CreateSession( dispatcher_.get(), config_, TestConnectionId(conn_id), client_addr_, &mock_helper_, &mock_alarm_factory_, @@ -2093,11 +2257,12 @@ TEST_P(BufferedPacketStoreTest, BufferNonChloPacketsUptoLimitWithChloBuffered) { ProcessUdpPacket(_, _, _)) .WillRepeatedly(WithArg<2>( Invoke([this, conn_id](const QuicEncryptedPacket& packet) { - ValidatePacket(TestConnectionId(conn_id), packet); + if (version_.UsesQuicCrypto()) { + ValidatePacket(TestConnectionId(conn_id), packet); + } }))); } - ProcessPacket(client_addr_, TestConnectionId(conn_id), true, - SerializeFullCHLO()); + ProcessFirstFlight(TestConnectionId(conn_id)); } // Process another |kDefaultMaxUndecryptablePackets| + 1 data packets. The @@ -2109,7 +2274,7 @@ TEST_P(BufferedPacketStoreTest, BufferNonChloPacketsUptoLimitWithChloBuffered) { // Reset counter and process buffered CHLO. EXPECT_CALL(*dispatcher_, CreateQuicSession(last_connection_id, client_addr_, - quiche::QuicheStringPiece(), _)) + Eq(ExpectedAlpn()), _)) .WillOnce(Return(ByMove(CreateSession( dispatcher_.get(), config_, last_connection_id, client_addr_, &mock_helper_, &mock_alarm_factory_, &crypto_config_, @@ -2121,7 +2286,9 @@ TEST_P(BufferedPacketStoreTest, BufferNonChloPacketsUptoLimitWithChloBuffered) { .Times(kDefaultMaxUndecryptablePackets + 1) .WillRepeatedly(WithArg<2>( Invoke([this, last_connection_id](const QuicEncryptedPacket& packet) { - ValidatePacket(last_connection_id, packet); + if (version_.UsesQuicCrypto()) { + ValidatePacket(last_connection_id, packet); + } }))); dispatcher_->ProcessBufferedChlos(kMaxNumSessionsToCreate); } @@ -2133,9 +2300,7 @@ TEST_P(BufferedPacketStoreTest, ReceiveCHLOForBufferedConnection) { QuicDispatcherPeer::GetBufferedPackets(dispatcher_.get()); uint64_t conn_id = 1; - ProcessPacket(client_addr_, TestConnectionId(conn_id), true, "data packet", - CONNECTION_ID_PRESENT, PACKET_4BYTE_PACKET_NUMBER, - /*packet_number=*/1); + ProcessUndecryptableEarlyPacket(TestConnectionId(conn_id)); // Fill packet buffer to full with CHLOs on other connections. Need to feed // extra CHLOs because the first |kMaxNumSessionsToCreate| are going to create // session directly. @@ -2145,7 +2310,7 @@ TEST_P(BufferedPacketStoreTest, ReceiveCHLOForBufferedConnection) { if (conn_id <= kMaxNumSessionsToCreate + 1) { EXPECT_CALL(*dispatcher_, CreateQuicSession(TestConnectionId(conn_id), client_addr_, - quiche::QuicheStringPiece(), _)) + Eq(ExpectedAlpn()), _)) .WillOnce(Return(ByMove(CreateSession( dispatcher_.get(), config_, TestConnectionId(conn_id), client_addr_, &mock_helper_, &mock_alarm_factory_, @@ -2156,18 +2321,18 @@ TEST_P(BufferedPacketStoreTest, ReceiveCHLOForBufferedConnection) { ProcessUdpPacket(_, _, _)) .WillOnce(WithArg<2>( Invoke([this, conn_id](const QuicEncryptedPacket& packet) { - ValidatePacket(TestConnectionId(conn_id), packet); + if (version_.UsesQuicCrypto()) { + ValidatePacket(TestConnectionId(conn_id), packet); + } }))); } - ProcessPacket(client_addr_, TestConnectionId(conn_id), true, - SerializeFullCHLO()); + ProcessFirstFlight(TestConnectionId(conn_id)); } EXPECT_FALSE(store->HasChloForConnection( /*connection_id=*/TestConnectionId(1))); // CHLO on connection 1 should still be buffered. - ProcessPacket(client_addr_, /*server_connection_id=*/TestConnectionId(1), - true, SerializeFullCHLO()); + ProcessFirstFlight(TestConnectionId(1)); EXPECT_TRUE(store->HasChloForConnection( /*connection_id=*/TestConnectionId(1))); } @@ -2183,9 +2348,10 @@ TEST_P(BufferedPacketStoreTest, ProcessBufferedChloWithDifferentVersion) { ParsedQuicVersion version = supported_versions[(conn_id - 1) % supported_versions.size()]; if (conn_id <= kMaxNumSessionsToCreate) { - EXPECT_CALL(*dispatcher_, - CreateQuicSession(TestConnectionId(conn_id), client_addr_, - quiche::QuicheStringPiece(), version)) + EXPECT_CALL( + *dispatcher_, + CreateQuicSession(TestConnectionId(conn_id), client_addr_, + Eq(ExpectedAlpnForVersion(version)), version)) .WillOnce(Return(ByMove(CreateSession( dispatcher_.get(), config_, TestConnectionId(conn_id), client_addr_, &mock_helper_, &mock_alarm_factory_, @@ -2196,12 +2362,12 @@ TEST_P(BufferedPacketStoreTest, ProcessBufferedChloWithDifferentVersion) { ProcessUdpPacket(_, _, _)) .WillRepeatedly(WithArg<2>( Invoke([this, conn_id](const QuicEncryptedPacket& packet) { - ValidatePacket(TestConnectionId(conn_id), packet); + if (version_.UsesQuicCrypto()) { + ValidatePacket(TestConnectionId(conn_id), packet); + } }))); } - ProcessPacket(client_addr_, TestConnectionId(conn_id), true, version, - SerializeFullCHLO(), true, CONNECTION_ID_PRESENT, - PACKET_4BYTE_PACKET_NUMBER, 1); + ProcessFirstFlight(version, TestConnectionId(conn_id)); } // Process buffered CHLOs. Verify the version is correct. @@ -2211,7 +2377,7 @@ TEST_P(BufferedPacketStoreTest, ProcessBufferedChloWithDifferentVersion) { supported_versions[(conn_id - 1) % supported_versions.size()]; EXPECT_CALL(*dispatcher_, CreateQuicSession(TestConnectionId(conn_id), client_addr_, - quiche::QuicheStringPiece(), version)) + Eq(ExpectedAlpnForVersion(version)), version)) .WillOnce(Return(ByMove(CreateSession( dispatcher_.get(), config_, TestConnectionId(conn_id), client_addr_, &mock_helper_, &mock_alarm_factory_, &crypto_config_, @@ -2220,7 +2386,9 @@ TEST_P(BufferedPacketStoreTest, ProcessBufferedChloWithDifferentVersion) { ProcessUdpPacket(_, _, _)) .WillRepeatedly(WithArg<2>( Invoke([this, conn_id](const QuicEncryptedPacket& packet) { - ValidatePacket(TestConnectionId(conn_id), packet); + if (version_.UsesQuicCrypto()) { + ValidatePacket(TestConnectionId(conn_id), packet); + } }))); } dispatcher_->ProcessBufferedChlos(kMaxNumSessionsToCreate); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.cc b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.cc index db97d32572d..6afccfece10 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.cc @@ -2,7 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <cstdint> +#include <cstring> + +#include "third_party/boringssl/src/include/openssl/ssl.h" #include "net/third_party/quiche/src/quic/core/quic_error_codes.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h" namespace quic { @@ -13,15 +19,14 @@ namespace quic { const char* QuicRstStreamErrorCodeToString(QuicRstStreamErrorCode error) { switch (error) { RETURN_STRING_LITERAL(QUIC_STREAM_NO_ERROR); - RETURN_STRING_LITERAL(QUIC_STREAM_CONNECTION_ERROR); RETURN_STRING_LITERAL(QUIC_ERROR_PROCESSING_STREAM); RETURN_STRING_LITERAL(QUIC_MULTIPLE_TERMINATION_OFFSETS); RETURN_STRING_LITERAL(QUIC_BAD_APPLICATION_PAYLOAD); + RETURN_STRING_LITERAL(QUIC_STREAM_CONNECTION_ERROR); RETURN_STRING_LITERAL(QUIC_STREAM_PEER_GOING_AWAY); RETURN_STRING_LITERAL(QUIC_STREAM_CANCELLED); RETURN_STRING_LITERAL(QUIC_RST_ACKNOWLEDGEMENT); RETURN_STRING_LITERAL(QUIC_REFUSED_STREAM); - RETURN_STRING_LITERAL(QUIC_STREAM_LAST_ERROR); RETURN_STRING_LITERAL(QUIC_INVALID_PROMISE_URL); RETURN_STRING_LITERAL(QUIC_UNAUTHORIZED_PROMISE_URL); RETURN_STRING_LITERAL(QUIC_DUPLICATE_PROMISE_URL); @@ -29,8 +34,27 @@ const char* QuicRstStreamErrorCodeToString(QuicRstStreamErrorCode error) { RETURN_STRING_LITERAL(QUIC_INVALID_PROMISE_METHOD); RETURN_STRING_LITERAL(QUIC_PUSH_STREAM_TIMED_OUT); RETURN_STRING_LITERAL(QUIC_HEADERS_TOO_LARGE); - RETURN_STRING_LITERAL(QUIC_DATA_AFTER_CLOSE_OFFSET); RETURN_STRING_LITERAL(QUIC_STREAM_TTL_EXPIRED); + RETURN_STRING_LITERAL(QUIC_DATA_AFTER_CLOSE_OFFSET); + RETURN_STRING_LITERAL(QUIC_STREAM_GENERAL_PROTOCOL_ERROR); + RETURN_STRING_LITERAL(QUIC_STREAM_INTERNAL_ERROR); + RETURN_STRING_LITERAL(QUIC_STREAM_STREAM_CREATION_ERROR); + RETURN_STRING_LITERAL(QUIC_STREAM_CLOSED_CRITICAL_STREAM); + RETURN_STRING_LITERAL(QUIC_STREAM_FRAME_UNEXPECTED); + RETURN_STRING_LITERAL(QUIC_STREAM_FRAME_ERROR); + RETURN_STRING_LITERAL(QUIC_STREAM_EXCESSIVE_LOAD); + RETURN_STRING_LITERAL(QUIC_STREAM_ID_ERROR); + RETURN_STRING_LITERAL(QUIC_STREAM_SETTINGS_ERROR); + RETURN_STRING_LITERAL(QUIC_STREAM_MISSING_SETTINGS); + RETURN_STRING_LITERAL(QUIC_STREAM_REQUEST_REJECTED); + RETURN_STRING_LITERAL(QUIC_STREAM_REQUEST_INCOMPLETE); + RETURN_STRING_LITERAL(QUIC_STREAM_CONNECT_ERROR); + RETURN_STRING_LITERAL(QUIC_STREAM_VERSION_FALLBACK); + RETURN_STRING_LITERAL(QUIC_STREAM_DECOMPRESSION_FAILED); + RETURN_STRING_LITERAL(QUIC_STREAM_ENCODER_STREAM_ERROR); + RETURN_STRING_LITERAL(QUIC_STREAM_DECODER_STREAM_ERROR); + RETURN_STRING_LITERAL(QUIC_STREAM_UNKNOWN_APPLICATION_ERROR_CODE); + RETURN_STRING_LITERAL(QUIC_STREAM_LAST_ERROR); } // Return a default value so that we return this when |error| doesn't match // any of the QuicRstStreamErrorCodes. This can happen when the RstStream @@ -177,6 +201,8 @@ const char* QuicErrorCodeToString(QuicErrorCode error) { RETURN_STRING_LITERAL(QUIC_HTTP_CLOSED_CRITICAL_STREAM); RETURN_STRING_LITERAL(QUIC_HTTP_MISSING_SETTINGS_FRAME); RETURN_STRING_LITERAL(QUIC_HTTP_DUPLICATE_SETTING_IDENTIFIER); + RETURN_STRING_LITERAL(QUIC_HTTP_INVALID_MAX_PUSH_ID); + RETURN_STRING_LITERAL(QUIC_HTTP_STREAM_LIMIT_TOO_LOW); RETURN_STRING_LITERAL(QUIC_HPACK_INDEX_VARINT_ERROR); RETURN_STRING_LITERAL(QUIC_HPACK_NAME_LENGTH_VARINT_ERROR); RETURN_STRING_LITERAL(QUIC_HPACK_VALUE_LENGTH_VARINT_ERROR); @@ -206,5 +232,513 @@ const char* QuicErrorCodeToString(QuicErrorCode error) { return "INVALID_ERROR_CODE"; } +std::string QuicIetfTransportErrorCodeString(QuicIetfTransportErrorCodes c) { + if (static_cast<uint64_t>(c) >= 0xff00u) { + return quiche::QuicheStrCat("Private(", static_cast<uint64_t>(c), ")"); + } + if (c >= CRYPTO_ERROR_FIRST && c <= CRYPTO_ERROR_LAST) { + const int tls_error = static_cast<int>(c - CRYPTO_ERROR_FIRST); + const char* tls_error_description = SSL_alert_desc_string_long(tls_error); + if (strcmp("unknown", tls_error_description) != 0) { + return quiche::QuicheStrCat("CRYPTO_ERROR(", tls_error_description, ")"); + } + return quiche::QuicheStrCat("CRYPTO_ERROR(unknown(", tls_error, "))"); + } + + switch (c) { + RETURN_STRING_LITERAL(NO_IETF_QUIC_ERROR); + RETURN_STRING_LITERAL(INTERNAL_ERROR); + RETURN_STRING_LITERAL(SERVER_BUSY_ERROR); + RETURN_STRING_LITERAL(FLOW_CONTROL_ERROR); + RETURN_STRING_LITERAL(STREAM_LIMIT_ERROR); + RETURN_STRING_LITERAL(STREAM_STATE_ERROR); + RETURN_STRING_LITERAL(FINAL_SIZE_ERROR); + RETURN_STRING_LITERAL(FRAME_ENCODING_ERROR); + RETURN_STRING_LITERAL(TRANSPORT_PARAMETER_ERROR); + RETURN_STRING_LITERAL(CONNECTION_ID_LIMIT_ERROR); + RETURN_STRING_LITERAL(PROTOCOL_VIOLATION); + RETURN_STRING_LITERAL(INVALID_TOKEN); + RETURN_STRING_LITERAL(CRYPTO_BUFFER_EXCEEDED); + // CRYPTO_ERROR is handled in the if before this switch, these cases do not + // change behavior and are only here to make the compiler happy. + case CRYPTO_ERROR_FIRST: + case CRYPTO_ERROR_LAST: + DCHECK(false) << "Unexpected error " << static_cast<uint64_t>(c); + break; + } + + return quiche::QuicheStrCat("Unknown(", static_cast<uint64_t>(c), ")"); +} + +std::ostream& operator<<(std::ostream& os, + const QuicIetfTransportErrorCodes& c) { + os << QuicIetfTransportErrorCodeString(c); + return os; +} + +QuicErrorCodeToIetfMapping QuicErrorCodeToTransportErrorCode( + QuicErrorCode error) { + switch (error) { + case QUIC_NO_ERROR: + return {true, static_cast<uint64_t>(NO_IETF_QUIC_ERROR)}; + case QUIC_INTERNAL_ERROR: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_STREAM_DATA_AFTER_TERMINATION: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_INVALID_PACKET_HEADER: + return {true, static_cast<uint64_t>(FRAME_ENCODING_ERROR)}; + case QUIC_INVALID_FRAME_DATA: + return {true, static_cast<uint64_t>(FRAME_ENCODING_ERROR)}; + case QUIC_MISSING_PAYLOAD: + return {true, static_cast<uint64_t>(FRAME_ENCODING_ERROR)}; + case QUIC_INVALID_FEC_DATA: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_INVALID_STREAM_DATA: + return {true, static_cast<uint64_t>(FRAME_ENCODING_ERROR)}; + case QUIC_OVERLAPPING_STREAM_DATA: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_UNENCRYPTED_STREAM_DATA: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_MAYBE_CORRUPTED_MEMORY: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_UNENCRYPTED_FEC_DATA: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_INVALID_RST_STREAM_DATA: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_INVALID_CONNECTION_CLOSE_DATA: + return {true, static_cast<uint64_t>(FRAME_ENCODING_ERROR)}; + case QUIC_INVALID_GOAWAY_DATA: + return {true, static_cast<uint64_t>(FRAME_ENCODING_ERROR)}; + case QUIC_INVALID_WINDOW_UPDATE_DATA: + return {true, static_cast<uint64_t>(FRAME_ENCODING_ERROR)}; + case QUIC_INVALID_BLOCKED_DATA: + return {true, static_cast<uint64_t>(FRAME_ENCODING_ERROR)}; + case QUIC_INVALID_STOP_WAITING_DATA: + return {true, static_cast<uint64_t>(FRAME_ENCODING_ERROR)}; + case QUIC_INVALID_PATH_CLOSE_DATA: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_INVALID_ACK_DATA: + return {true, static_cast<uint64_t>(FRAME_ENCODING_ERROR)}; + case QUIC_INVALID_MESSAGE_DATA: + return {true, static_cast<uint64_t>(FRAME_ENCODING_ERROR)}; + case QUIC_INVALID_VERSION_NEGOTIATION_PACKET: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_INVALID_PUBLIC_RST_PACKET: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_DECRYPTION_FAILURE: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_ENCRYPTION_FAILURE: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_PACKET_TOO_LARGE: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_PEER_GOING_AWAY: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_INVALID_STREAM_ID: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_INVALID_PRIORITY: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_TOO_MANY_OPEN_STREAMS: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_TOO_MANY_AVAILABLE_STREAMS: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_PUBLIC_RESET: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_INVALID_VERSION: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_INVALID_HEADER_ID: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_INVALID_NEGOTIATED_VALUE: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_DECOMPRESSION_FAILURE: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_NETWORK_IDLE_TIMEOUT: + return {true, static_cast<uint64_t>(NO_IETF_QUIC_ERROR)}; + case QUIC_HANDSHAKE_TIMEOUT: + return {true, static_cast<uint64_t>(NO_IETF_QUIC_ERROR)}; + case QUIC_ERROR_MIGRATING_ADDRESS: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_ERROR_MIGRATING_PORT: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_PACKET_WRITE_ERROR: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_PACKET_READ_ERROR: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_EMPTY_STREAM_FRAME_NO_FIN: + return {true, static_cast<uint64_t>(FRAME_ENCODING_ERROR)}; + case QUIC_INVALID_HEADERS_STREAM_DATA: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA: + return {true, static_cast<uint64_t>(FLOW_CONTROL_ERROR)}; + case QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_FLOW_CONTROL_INVALID_WINDOW: + return {true, static_cast<uint64_t>(FLOW_CONTROL_ERROR)}; + case QUIC_CONNECTION_IP_POOLED: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_CONNECTION_CANCELLED: + return {true, static_cast<uint64_t>(NO_IETF_QUIC_ERROR)}; + case QUIC_BAD_PACKET_LOSS_RATE: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_PUBLIC_RESETS_POST_HANDSHAKE: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_FAILED_TO_SERIALIZE_PACKET: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_TOO_MANY_RTOS: + return {true, static_cast<uint64_t>(NO_IETF_QUIC_ERROR)}; + case QUIC_HANDSHAKE_FAILED: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_CRYPTO_TAGS_OUT_OF_ORDER: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_CRYPTO_TOO_MANY_ENTRIES: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_CRYPTO_INVALID_VALUE_LENGTH: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_INVALID_CRYPTO_MESSAGE_TYPE: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_INVALID_CHANNEL_ID_SIGNATURE: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_UNSUPPORTED_PROOF_DEMAND: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_CRYPTO_INTERNAL_ERROR: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_CRYPTO_VERSION_NOT_SUPPORTED: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_CRYPTO_NO_SUPPORT: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_CRYPTO_TOO_MANY_REJECTS: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_PROOF_INVALID: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_CRYPTO_DUPLICATE_TAG: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_CRYPTO_SERVER_CONFIG_EXPIRED: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_CRYPTO_CHLO_TOO_LARGE: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_VERSION_NEGOTIATION_MISMATCH: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_BAD_MULTIPATH_FLAG: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_MULTIPATH_PATH_DOES_NOT_EXIST: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_MULTIPATH_PATH_NOT_ACTIVE: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_IP_ADDRESS_CHANGED: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_CONNECTION_MIGRATION_TOO_MANY_CHANGES: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_CONNECTION_MIGRATION_NON_MIGRATABLE_STREAM: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_CONNECTION_MIGRATION_DISABLED_BY_CONFIG: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_CONNECTION_MIGRATION_INTERNAL_ERROR: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_CONNECTION_MIGRATION_HANDSHAKE_UNCONFIRMED: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_TOO_MANY_STREAM_DATA_INTERVALS: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_STREAM_SEQUENCER_INVALID_STATE: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_TOO_MANY_SESSIONS_ON_SERVER: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_STREAM_LENGTH_OVERFLOW: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_INVALID_MAX_DATA_FRAME_DATA: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_INVALID_MAX_STREAM_DATA_FRAME_DATA: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_MAX_STREAMS_DATA: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_STREAMS_BLOCKED_DATA: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_INVALID_STREAM_BLOCKED_DATA: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_INVALID_NEW_CONNECTION_ID_DATA: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_INVALID_STOP_SENDING_FRAME_DATA: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_INVALID_PATH_CHALLENGE_DATA: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_INVALID_PATH_RESPONSE_DATA: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case IETF_QUIC_PROTOCOL_VIOLATION: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_INVALID_NEW_TOKEN: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_DATA_RECEIVED_ON_WRITE_UNIDIRECTIONAL_STREAM: + return {true, static_cast<uint64_t>(STREAM_STATE_ERROR)}; + case QUIC_TRY_TO_WRITE_DATA_ON_READ_UNIDIRECTIONAL_STREAM: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_INVALID_RETIRE_CONNECTION_ID_DATA: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_STREAMS_BLOCKED_ERROR: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_MAX_STREAMS_ERROR: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_HTTP_DECODER_ERROR: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_STALE_CONNECTION_CANCELLED: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_IETF_GQUIC_ERROR_MISSING: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_WINDOW_UPDATE_RECEIVED_ON_READ_UNIDIRECTIONAL_STREAM: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_TOO_MANY_BUFFERED_CONTROL_FRAMES: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_TRANSPORT_INVALID_CLIENT_INDICATION: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_QPACK_DECOMPRESSION_FAILED: + return {false, static_cast<uint64_t>( + QuicHttpQpackErrorCode::DECOMPRESSION_FAILED)}; + case QUIC_QPACK_ENCODER_STREAM_ERROR: + return {false, static_cast<uint64_t>( + QuicHttpQpackErrorCode::ENCODER_STREAM_ERROR)}; + case QUIC_QPACK_DECODER_STREAM_ERROR: + return {false, static_cast<uint64_t>( + QuicHttpQpackErrorCode::DECODER_STREAM_ERROR)}; + case QUIC_STREAM_DATA_BEYOND_CLOSE_OFFSET: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_STREAM_MULTIPLE_OFFSET: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_HTTP_FRAME_TOO_LARGE: + return {false, static_cast<uint64_t>(QuicHttp3ErrorCode::EXCESSIVE_LOAD)}; + case QUIC_HTTP_FRAME_ERROR: + return {false, static_cast<uint64_t>(QuicHttp3ErrorCode::FRAME_ERROR)}; + case QUIC_HTTP_FRAME_UNEXPECTED_ON_SPDY_STREAM: + return {false, + static_cast<uint64_t>(QuicHttp3ErrorCode::FRAME_UNEXPECTED)}; + case QUIC_HTTP_FRAME_UNEXPECTED_ON_CONTROL_STREAM: + return {false, + static_cast<uint64_t>(QuicHttp3ErrorCode::FRAME_UNEXPECTED)}; + case QUIC_HTTP_INVALID_FRAME_SEQUENCE_ON_SPDY_STREAM: + return {false, + static_cast<uint64_t>(QuicHttp3ErrorCode::FRAME_UNEXPECTED)}; + case QUIC_HTTP_INVALID_FRAME_SEQUENCE_ON_CONTROL_STREAM: + return {false, + static_cast<uint64_t>(QuicHttp3ErrorCode::FRAME_UNEXPECTED)}; + case QUIC_HTTP_DUPLICATE_UNIDIRECTIONAL_STREAM: + return {false, + static_cast<uint64_t>(QuicHttp3ErrorCode::STREAM_CREATION_ERROR)}; + case QUIC_HTTP_SERVER_INITIATED_BIDIRECTIONAL_STREAM: + return {false, + static_cast<uint64_t>(QuicHttp3ErrorCode::STREAM_CREATION_ERROR)}; + case QUIC_HTTP_STREAM_WRONG_DIRECTION: + return {true, static_cast<uint64_t>(STREAM_STATE_ERROR)}; + case QUIC_HTTP_CLOSED_CRITICAL_STREAM: + return {false, static_cast<uint64_t>( + QuicHttp3ErrorCode::CLOSED_CRITICAL_STREAM)}; + case QUIC_HTTP_MISSING_SETTINGS_FRAME: + return {false, + static_cast<uint64_t>(QuicHttp3ErrorCode::MISSING_SETTINGS)}; + case QUIC_HTTP_DUPLICATE_SETTING_IDENTIFIER: + return {false, static_cast<uint64_t>(QuicHttp3ErrorCode::SETTINGS_ERROR)}; + case QUIC_HTTP_INVALID_MAX_PUSH_ID: + return {false, static_cast<uint64_t>(QuicHttp3ErrorCode::ID_ERROR)}; + case QUIC_HTTP_STREAM_LIMIT_TOO_LOW: + return {false, static_cast<uint64_t>( + QuicHttp3ErrorCode::GENERAL_PROTOCOL_ERROR)}; + case QUIC_HPACK_INDEX_VARINT_ERROR: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_HPACK_NAME_LENGTH_VARINT_ERROR: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_HPACK_VALUE_LENGTH_VARINT_ERROR: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_HPACK_NAME_TOO_LONG: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_HPACK_VALUE_TOO_LONG: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_HPACK_NAME_HUFFMAN_ERROR: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_HPACK_VALUE_HUFFMAN_ERROR: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_HPACK_MISSING_DYNAMIC_TABLE_SIZE_UPDATE: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_HPACK_INVALID_INDEX: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_HPACK_INVALID_NAME_INDEX: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_NOT_ALLOWED: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_HPACK_INITIAL_TABLE_SIZE_UPDATE_IS_ABOVE_LOW_WATER_MARK: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_HPACK_TABLE_SIZE_UPDATE_IS_ABOVE_ACKNOWLEDGED_SETTING: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_HPACK_TRUNCATED_BLOCK: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_HPACK_FRAGMENT_TOO_LONG: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_LAST_ERROR: + return {false, static_cast<uint64_t>(QUIC_LAST_ERROR)}; + } + // This function should not be called with unknown error code. + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; +} + +// Convert a QuicRstStreamErrorCode to an application error code to be used in +// an IETF QUIC RESET_STREAM frame +uint64_t RstStreamErrorCodeToIetfResetStreamErrorCode( + QuicRstStreamErrorCode rst_stream_error_code) { + switch (rst_stream_error_code) { + case QUIC_STREAM_NO_ERROR: + return static_cast<uint64_t>(QuicHttp3ErrorCode::HTTP3_NO_ERROR); + case QUIC_ERROR_PROCESSING_STREAM: + return static_cast<uint64_t>(QuicHttp3ErrorCode::GENERAL_PROTOCOL_ERROR); + case QUIC_MULTIPLE_TERMINATION_OFFSETS: + return static_cast<uint64_t>(QuicHttp3ErrorCode::GENERAL_PROTOCOL_ERROR); + case QUIC_BAD_APPLICATION_PAYLOAD: + return static_cast<uint64_t>(QuicHttp3ErrorCode::GENERAL_PROTOCOL_ERROR); + case QUIC_STREAM_CONNECTION_ERROR: + return static_cast<uint64_t>(QuicHttp3ErrorCode::INTERNAL_ERROR); + case QUIC_STREAM_PEER_GOING_AWAY: + return static_cast<uint64_t>(QuicHttp3ErrorCode::GENERAL_PROTOCOL_ERROR); + case QUIC_STREAM_CANCELLED: + return static_cast<uint64_t>(QuicHttp3ErrorCode::REQUEST_CANCELLED); + case QUIC_RST_ACKNOWLEDGEMENT: + return static_cast<uint64_t>(QuicHttp3ErrorCode::HTTP3_NO_ERROR); + case QUIC_REFUSED_STREAM: + return static_cast<uint64_t>(QuicHttp3ErrorCode::ID_ERROR); + case QUIC_INVALID_PROMISE_URL: + return static_cast<uint64_t>(QuicHttp3ErrorCode::STREAM_CREATION_ERROR); + case QUIC_UNAUTHORIZED_PROMISE_URL: + return static_cast<uint64_t>(QuicHttp3ErrorCode::STREAM_CREATION_ERROR); + case QUIC_DUPLICATE_PROMISE_URL: + return static_cast<uint64_t>(QuicHttp3ErrorCode::STREAM_CREATION_ERROR); + case QUIC_PROMISE_VARY_MISMATCH: + return static_cast<uint64_t>(QuicHttp3ErrorCode::REQUEST_CANCELLED); + case QUIC_INVALID_PROMISE_METHOD: + return static_cast<uint64_t>(QuicHttp3ErrorCode::STREAM_CREATION_ERROR); + case QUIC_PUSH_STREAM_TIMED_OUT: + return static_cast<uint64_t>(QuicHttp3ErrorCode::REQUEST_CANCELLED); + case QUIC_HEADERS_TOO_LARGE: + return static_cast<uint64_t>(QuicHttp3ErrorCode::EXCESSIVE_LOAD); + case QUIC_STREAM_TTL_EXPIRED: + return static_cast<uint64_t>(QuicHttp3ErrorCode::REQUEST_CANCELLED); + case QUIC_DATA_AFTER_CLOSE_OFFSET: + return static_cast<uint64_t>(QuicHttp3ErrorCode::GENERAL_PROTOCOL_ERROR); + case QUIC_STREAM_GENERAL_PROTOCOL_ERROR: + return static_cast<uint64_t>(QuicHttp3ErrorCode::GENERAL_PROTOCOL_ERROR); + case QUIC_STREAM_INTERNAL_ERROR: + return static_cast<uint64_t>(QuicHttp3ErrorCode::INTERNAL_ERROR); + case QUIC_STREAM_STREAM_CREATION_ERROR: + return static_cast<uint64_t>(QuicHttp3ErrorCode::STREAM_CREATION_ERROR); + case QUIC_STREAM_CLOSED_CRITICAL_STREAM: + return static_cast<uint64_t>(QuicHttp3ErrorCode::CLOSED_CRITICAL_STREAM); + case QUIC_STREAM_FRAME_UNEXPECTED: + return static_cast<uint64_t>(QuicHttp3ErrorCode::FRAME_UNEXPECTED); + case QUIC_STREAM_FRAME_ERROR: + return static_cast<uint64_t>(QuicHttp3ErrorCode::FRAME_ERROR); + case QUIC_STREAM_EXCESSIVE_LOAD: + return static_cast<uint64_t>(QuicHttp3ErrorCode::EXCESSIVE_LOAD); + case QUIC_STREAM_ID_ERROR: + return static_cast<uint64_t>(QuicHttp3ErrorCode::ID_ERROR); + case QUIC_STREAM_SETTINGS_ERROR: + return static_cast<uint64_t>(QuicHttp3ErrorCode::SETTINGS_ERROR); + case QUIC_STREAM_MISSING_SETTINGS: + return static_cast<uint64_t>(QuicHttp3ErrorCode::MISSING_SETTINGS); + case QUIC_STREAM_REQUEST_REJECTED: + return static_cast<uint64_t>(QuicHttp3ErrorCode::REQUEST_REJECTED); + case QUIC_STREAM_REQUEST_INCOMPLETE: + return static_cast<uint64_t>(QuicHttp3ErrorCode::REQUEST_INCOMPLETE); + case QUIC_STREAM_CONNECT_ERROR: + return static_cast<uint64_t>(QuicHttp3ErrorCode::CONNECT_ERROR); + case QUIC_STREAM_VERSION_FALLBACK: + return static_cast<uint64_t>(QuicHttp3ErrorCode::VERSION_FALLBACK); + case QUIC_STREAM_DECOMPRESSION_FAILED: + return static_cast<uint64_t>( + QuicHttpQpackErrorCode::DECOMPRESSION_FAILED); + case QUIC_STREAM_ENCODER_STREAM_ERROR: + return static_cast<uint64_t>( + QuicHttpQpackErrorCode::ENCODER_STREAM_ERROR); + case QUIC_STREAM_DECODER_STREAM_ERROR: + return static_cast<uint64_t>( + QuicHttpQpackErrorCode::DECODER_STREAM_ERROR); + case QUIC_STREAM_UNKNOWN_APPLICATION_ERROR_CODE: + return static_cast<uint64_t>(QuicHttp3ErrorCode::INTERNAL_ERROR); + case QUIC_STREAM_LAST_ERROR: + return static_cast<uint64_t>(QuicHttp3ErrorCode::INTERNAL_ERROR); + } + return static_cast<uint64_t>(QuicHttp3ErrorCode::INTERNAL_ERROR); +} + +// Convert the application error code of an IETF QUIC RESET_STREAM frame +// to QuicRstStreamErrorCode. +QuicRstStreamErrorCode IetfResetStreamErrorCodeToRstStreamErrorCode( + uint64_t ietf_error_code) { + switch (ietf_error_code) { + case static_cast<uint64_t>(QuicHttp3ErrorCode::HTTP3_NO_ERROR): + return QUIC_STREAM_NO_ERROR; + case static_cast<uint64_t>(QuicHttp3ErrorCode::GENERAL_PROTOCOL_ERROR): + return QUIC_STREAM_GENERAL_PROTOCOL_ERROR; + case static_cast<uint64_t>(QuicHttp3ErrorCode::INTERNAL_ERROR): + return QUIC_STREAM_INTERNAL_ERROR; + case static_cast<uint64_t>(QuicHttp3ErrorCode::STREAM_CREATION_ERROR): + return QUIC_STREAM_STREAM_CREATION_ERROR; + case static_cast<uint64_t>(QuicHttp3ErrorCode::CLOSED_CRITICAL_STREAM): + return QUIC_STREAM_CLOSED_CRITICAL_STREAM; + case static_cast<uint64_t>(QuicHttp3ErrorCode::FRAME_UNEXPECTED): + return QUIC_STREAM_FRAME_UNEXPECTED; + case static_cast<uint64_t>(QuicHttp3ErrorCode::FRAME_ERROR): + return QUIC_STREAM_FRAME_ERROR; + case static_cast<uint64_t>(QuicHttp3ErrorCode::EXCESSIVE_LOAD): + return QUIC_STREAM_EXCESSIVE_LOAD; + case static_cast<uint64_t>(QuicHttp3ErrorCode::ID_ERROR): + return QUIC_STREAM_ID_ERROR; + case static_cast<uint64_t>(QuicHttp3ErrorCode::SETTINGS_ERROR): + return QUIC_STREAM_SETTINGS_ERROR; + case static_cast<uint64_t>(QuicHttp3ErrorCode::MISSING_SETTINGS): + return QUIC_STREAM_MISSING_SETTINGS; + case static_cast<uint64_t>(QuicHttp3ErrorCode::REQUEST_REJECTED): + return QUIC_STREAM_REQUEST_REJECTED; + case static_cast<uint64_t>(QuicHttp3ErrorCode::REQUEST_CANCELLED): + return QUIC_STREAM_CANCELLED; + case static_cast<uint64_t>(QuicHttp3ErrorCode::REQUEST_INCOMPLETE): + return QUIC_STREAM_REQUEST_INCOMPLETE; + case static_cast<uint64_t>(QuicHttp3ErrorCode::CONNECT_ERROR): + return QUIC_STREAM_CONNECT_ERROR; + case static_cast<uint64_t>(QuicHttp3ErrorCode::VERSION_FALLBACK): + return QUIC_STREAM_VERSION_FALLBACK; + case static_cast<uint64_t>(QuicHttpQpackErrorCode::DECOMPRESSION_FAILED): + return QUIC_STREAM_DECOMPRESSION_FAILED; + case static_cast<uint64_t>(QuicHttpQpackErrorCode::ENCODER_STREAM_ERROR): + return QUIC_STREAM_ENCODER_STREAM_ERROR; + case static_cast<uint64_t>(QuicHttpQpackErrorCode::DECODER_STREAM_ERROR): + return QUIC_STREAM_DECODER_STREAM_ERROR; + } + return QUIC_STREAM_UNKNOWN_APPLICATION_ERROR_CODE; +} + #undef RETURN_STRING_LITERAL // undef for jumbo builds + } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h index 0548e9b0fe0..f057fea1028 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h @@ -56,6 +56,53 @@ enum QuicRstStreamErrorCode { QUIC_STREAM_TTL_EXPIRED, // The stream received data that goes beyond its close offset. QUIC_DATA_AFTER_CLOSE_OFFSET, + // Peer violated protocol requirements in a way which does not match a more + // specific error code, or endpoint declines to use the more specific error + // code. + QUIC_STREAM_GENERAL_PROTOCOL_ERROR, + // An internal error has occurred. + QUIC_STREAM_INTERNAL_ERROR, + // Peer created a stream that will not be accepted. + QUIC_STREAM_STREAM_CREATION_ERROR, + // A stream required by the connection was closed or reset. + QUIC_STREAM_CLOSED_CRITICAL_STREAM, + // A frame was received which was not permitted in the current state or on the + // current stream. + QUIC_STREAM_FRAME_UNEXPECTED, + // A frame that fails to satisfy layout requirements or with an invalid size + // was received. + QUIC_STREAM_FRAME_ERROR, + // Peer exhibits a behavior that might be generating excessive load. + QUIC_STREAM_EXCESSIVE_LOAD, + // A Stream ID or Push ID was used incorrectly, such as exceeding a limit, + // reducing a limit, or being reused. + QUIC_STREAM_ID_ERROR, + // Error in the payload of a SETTINGS frame. + QUIC_STREAM_SETTINGS_ERROR, + // No SETTINGS frame was received at the beginning of the control stream. + QUIC_STREAM_MISSING_SETTINGS, + // A server rejected a request without performing any application processing. + QUIC_STREAM_REQUEST_REJECTED, + // The client's stream terminated without containing a fully-formed request. + QUIC_STREAM_REQUEST_INCOMPLETE, + // The connection established in response to a CONNECT request was reset or + // abnormally closed. + QUIC_STREAM_CONNECT_ERROR, + // The requested operation cannot be served over HTTP/3. + // The peer should retry over HTTP/1.1. + QUIC_STREAM_VERSION_FALLBACK, + // The QPACK decoder failed to interpret a header block and is not able to + // continue decoding that header block. + QUIC_STREAM_DECOMPRESSION_FAILED, + // The QPACK decoder failed to interpret an encoder instruction received on + // the encoder stream. + QUIC_STREAM_ENCODER_STREAM_ERROR, + // The QPACK encoder failed to interpret a decoder instruction received on the + // decoder stream. + QUIC_STREAM_DECODER_STREAM_ERROR, + // IETF RESET_FRAME application error code not matching any HTTP/3 or QPACK + // error codes. + QUIC_STREAM_UNKNOWN_APPLICATION_ERROR_CODE, // No error. Used as bound while iterating. QUIC_STREAM_LAST_ERROR, }; @@ -379,6 +426,11 @@ enum QuicErrorCode { QUIC_HTTP_MISSING_SETTINGS_FRAME = 157, // The received SETTINGS frame contains duplicate setting identifiers. QUIC_HTTP_DUPLICATE_SETTING_IDENTIFIER = 158, + // MAX_PUSH_ID frame received with push ID value smaller than a previously + // received value. + QUIC_HTTP_INVALID_MAX_PUSH_ID = 159, + // Received unidirectional stream limit is lower than required by HTTP/3. + QUIC_HTTP_STREAM_LIMIT_TOO_LOW = 160, // HPACK header block decoding errors. // Index varint beyond implementation limit. @@ -415,7 +467,7 @@ enum QuicErrorCode { QUIC_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT = 150, // No error. Used as bound while iterating. - QUIC_LAST_ERROR = 159, + QUIC_LAST_ERROR = 161, }; // QuicErrorCodes is encoded as four octets on-the-wire when doing Google QUIC, // or a varint62 when doing IETF QUIC. Ensure that its value does not exceed @@ -431,35 +483,85 @@ QUIC_EXPORT_PRIVATE const char* QuicRstStreamErrorCodeToString( // Returns the name of the QuicErrorCode as a char* QUIC_EXPORT_PRIVATE const char* QuicErrorCodeToString(QuicErrorCode error); +// Wire values for QUIC transport errors. +// https://quicwg.org/base-drafts/draft-ietf-quic-transport.html#name-transport-error-codes +enum QuicIetfTransportErrorCodes : uint64_t { + NO_IETF_QUIC_ERROR = 0x0, + INTERNAL_ERROR = 0x1, + SERVER_BUSY_ERROR = 0x2, + FLOW_CONTROL_ERROR = 0x3, + STREAM_LIMIT_ERROR = 0x4, + STREAM_STATE_ERROR = 0x5, + FINAL_SIZE_ERROR = 0x6, + FRAME_ENCODING_ERROR = 0x7, + TRANSPORT_PARAMETER_ERROR = 0x8, + CONNECTION_ID_LIMIT_ERROR = 0x9, + PROTOCOL_VIOLATION = 0xA, + INVALID_TOKEN = 0xB, + CRYPTO_BUFFER_EXCEEDED = 0xD, + CRYPTO_ERROR_FIRST = 0x100, + CRYPTO_ERROR_LAST = 0x1FF, +}; + +QUIC_EXPORT_PRIVATE std::string QuicIetfTransportErrorCodeString( + QuicIetfTransportErrorCodes c); + +QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const QuicIetfTransportErrorCodes& c); + +// A transport error code (if is_transport_close is true) or application error +// code (if is_transport_close is false) to be used in CONNECTION_CLOSE frames. +struct QUIC_EXPORT_PRIVATE QuicErrorCodeToIetfMapping { + bool is_transport_close; + uint64_t error_code; +}; + +// Convert QuicErrorCode to transport or application IETF error code +// to be used in CONNECTION_CLOSE frames. +QUIC_EXPORT_PRIVATE QuicErrorCodeToIetfMapping +QuicErrorCodeToTransportErrorCode(QuicErrorCode error); + // Wire values for HTTP/3 errors. // https://quicwg.org/base-drafts/draft-ietf-quic-http.html#http-error-codes enum class QuicHttp3ErrorCode { - IETF_QUIC_HTTP3_NO_ERROR = 0x100, - IETF_QUIC_HTTP3_GENERAL_PROTOCOL_ERROR = 0x101, - IETF_QUIC_HTTP3_INTERNAL_ERROR = 0x102, - IETF_QUIC_HTTP3_STREAM_CREATION_ERROR = 0x103, - IETF_QUIC_HTTP3_CLOSED_CRITICAL_STREAM = 0x104, - IETF_QUIC_HTTP3_FRAME_UNEXPECTED = 0x105, - IETF_QUIC_HTTP3_FRAME_ERROR = 0x106, - IETF_QUIC_HTTP3_EXCESSIVE_LOAD = 0x107, - IETF_QUIC_HTTP3_ID_ERROR = 0x108, - IETF_QUIC_HTTP3_SETTINGS_ERROR = 0x109, - IETF_QUIC_HTTP3_MISSING_SETTINGS = 0x10A, - IETF_QUIC_HTTP3_REQUEST_REJECTED = 0x10B, - IETF_QUIC_HTTP3_REQUEST_CANCELLED = 0x10C, - IETF_QUIC_HTTP3_REQUEST_INCOMPLETE = 0x10D, - IETF_QUIC_HTTP3_CONNECT_ERROR = 0x10F, - IETF_QUIC_HTTP3_VERSION_FALLBACK = 0x110, + // NO_ERROR is defined as a C preprocessor macro on Windows. + HTTP3_NO_ERROR = 0x100, + GENERAL_PROTOCOL_ERROR = 0x101, + INTERNAL_ERROR = 0x102, + STREAM_CREATION_ERROR = 0x103, + CLOSED_CRITICAL_STREAM = 0x104, + FRAME_UNEXPECTED = 0x105, + FRAME_ERROR = 0x106, + EXCESSIVE_LOAD = 0x107, + ID_ERROR = 0x108, + SETTINGS_ERROR = 0x109, + MISSING_SETTINGS = 0x10A, + REQUEST_REJECTED = 0x10B, + REQUEST_CANCELLED = 0x10C, + REQUEST_INCOMPLETE = 0x10D, + CONNECT_ERROR = 0x10F, + VERSION_FALLBACK = 0x110, }; // Wire values for QPACK errors. // https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#error-code-registration -enum QuicHttpQpackErrorCode { - IETF_QUIC_HTTP_QPACK_DECOMPRESSION_FAILED = 0x200, - IETF_QUIC_HTTP_QPACK_ENCODER_STREAM_ERROR = 0x201, - IETF_QUIC_HTTP_QPACK_DECODER_STREAM_ERROR = 0x202 +enum class QuicHttpQpackErrorCode { + DECOMPRESSION_FAILED = 0x200, + ENCODER_STREAM_ERROR = 0x201, + DECODER_STREAM_ERROR = 0x202 }; +// Convert a QuicRstStreamErrorCode to an application error code to be used in +// an IETF QUIC RESET_STREAM frame +uint64_t RstStreamErrorCodeToIetfResetStreamErrorCode( + QuicRstStreamErrorCode rst_stream_error_code); + +// Convert the application error code of an IETF QUIC RESET_STREAM frame +// to QuicRstStreamErrorCode. +QuicRstStreamErrorCode IetfResetStreamErrorCodeToRstStreamErrorCode( + uint64_t ietf_error_code); + QUIC_EXPORT_PRIVATE inline std::string HistogramEnumString( QuicErrorCode enum_value) { return QuicErrorCodeToString(enum_value); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes_test.cc index f9928bd2b39..e57a3e57cd0 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes_test.cc @@ -4,6 +4,9 @@ #include "net/third_party/quiche/src/quic/core/quic_error_codes.h" +#include <cstdint> + +#include "third_party/boringssl/src/include/openssl/ssl.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" namespace quic { @@ -21,6 +24,76 @@ TEST_F(QuicErrorCodesTest, QuicErrorCodeToString) { EXPECT_STREQ("QUIC_NO_ERROR", QuicErrorCodeToString(QUIC_NO_ERROR)); } +TEST_F(QuicErrorCodesTest, QuicIetfTransportErrorCodeString) { + EXPECT_EQ("Private(65280)", + QuicIetfTransportErrorCodeString( + static_cast<quic::QuicIetfTransportErrorCodes>(0xff00u))); + + EXPECT_EQ("CRYPTO_ERROR(missing extension)", + QuicIetfTransportErrorCodeString( + static_cast<quic::QuicIetfTransportErrorCodes>( + CRYPTO_ERROR_FIRST + SSL_AD_MISSING_EXTENSION))); + + EXPECT_EQ("NO_IETF_QUIC_ERROR", + QuicIetfTransportErrorCodeString(NO_IETF_QUIC_ERROR)); + EXPECT_EQ("INTERNAL_ERROR", QuicIetfTransportErrorCodeString(INTERNAL_ERROR)); + EXPECT_EQ("SERVER_BUSY_ERROR", + QuicIetfTransportErrorCodeString(SERVER_BUSY_ERROR)); + EXPECT_EQ("FLOW_CONTROL_ERROR", + QuicIetfTransportErrorCodeString(FLOW_CONTROL_ERROR)); + EXPECT_EQ("STREAM_LIMIT_ERROR", + QuicIetfTransportErrorCodeString(STREAM_LIMIT_ERROR)); + EXPECT_EQ("STREAM_STATE_ERROR", + QuicIetfTransportErrorCodeString(STREAM_STATE_ERROR)); + EXPECT_EQ("FINAL_SIZE_ERROR", + QuicIetfTransportErrorCodeString(FINAL_SIZE_ERROR)); + EXPECT_EQ("FRAME_ENCODING_ERROR", + QuicIetfTransportErrorCodeString(FRAME_ENCODING_ERROR)); + EXPECT_EQ("TRANSPORT_PARAMETER_ERROR", + QuicIetfTransportErrorCodeString(TRANSPORT_PARAMETER_ERROR)); + EXPECT_EQ("CONNECTION_ID_LIMIT_ERROR", + QuicIetfTransportErrorCodeString(CONNECTION_ID_LIMIT_ERROR)); + EXPECT_EQ("PROTOCOL_VIOLATION", + QuicIetfTransportErrorCodeString(PROTOCOL_VIOLATION)); + EXPECT_EQ("INVALID_TOKEN", QuicIetfTransportErrorCodeString(INVALID_TOKEN)); + EXPECT_EQ("CRYPTO_BUFFER_EXCEEDED", + QuicIetfTransportErrorCodeString(CRYPTO_BUFFER_EXCEEDED)); + + EXPECT_EQ("Unknown(1024)", + QuicIetfTransportErrorCodeString( + static_cast<quic::QuicIetfTransportErrorCodes>(0x400))); +} + +TEST_F(QuicErrorCodesTest, QuicErrorCodeToTransportErrorCode) { + for (int internal_error_code = 0; internal_error_code < QUIC_LAST_ERROR; + ++internal_error_code) { + std::string internal_error_code_string = + QuicErrorCodeToString(static_cast<QuicErrorCode>(internal_error_code)); + if (internal_error_code_string == "INVALID_ERROR_CODE") { + // Not a valid QuicErrorCode. + continue; + } + QuicErrorCodeToIetfMapping ietf_error_code = + QuicErrorCodeToTransportErrorCode( + static_cast<QuicErrorCode>(internal_error_code)); + if (ietf_error_code.is_transport_close) { + QuicIetfTransportErrorCodes transport_error_code = + static_cast<QuicIetfTransportErrorCodes>(ietf_error_code.error_code); + bool is_valid_transport_error_code = transport_error_code <= 0x0d; + EXPECT_TRUE(is_valid_transport_error_code) << internal_error_code_string; + } else { + // Non-transport errors are application errors, either HTTP/3 or QPACK. + uint64_t application_error_code = ietf_error_code.error_code; + bool is_valid_http3_error_code = + application_error_code >= 0x100 && application_error_code <= 0x110; + bool is_valid_qpack_error_code = + application_error_code >= 0x200 && application_error_code <= 0x202; + EXPECT_TRUE(is_valid_http3_error_code || is_valid_qpack_error_code) + << internal_error_code_string; + } + } +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_flow_controller.h b/chromium/net/third_party/quiche/src/quic/core/quic_flow_controller.h index e627c8c4d31..29c3c02d1a3 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_flow_controller.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_flow_controller.h @@ -91,6 +91,8 @@ class QUIC_EXPORT_PRIVATE QuicFlowController QuicByteCount bytes_consumed() const { return bytes_consumed_; } + QuicStreamOffset send_window_offset() const { return send_window_offset_; } + QuicStreamOffset highest_received_byte_offset() const { return highest_received_byte_offset_; } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_flow_controller_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_flow_controller_test.cc index 8f4cdf7849e..29a9ba37649 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_flow_controller_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_flow_controller_test.cc @@ -31,7 +31,7 @@ class MockFlowController : public QuicFlowControllerInterface { MockFlowController& operator=(const MockFlowController&) = delete; ~MockFlowController() override {} - MOCK_METHOD1(EnsureWindowAtLeast, void(QuicByteCount)); + MOCK_METHOD(void, EnsureWindowAtLeast, (QuicByteCount), (override)); }; class QuicFlowControllerTest : public QuicTest { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_framer.cc b/chromium/net/third_party/quiche/src/quic/core/quic_framer.cc index f90019176aa..b05b4576d8e 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_framer.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_framer.cc @@ -466,11 +466,9 @@ size_t QuicFramer::GetMessageFrameSize(QuicTransportVersion version, } // static -size_t QuicFramer::GetMinAckFrameSize( - QuicTransportVersion version, - const QuicAckFrame& ack_frame, - uint32_t local_ack_delay_exponent, - QuicPacketNumberLength largest_observed_length) { +size_t QuicFramer::GetMinAckFrameSize(QuicTransportVersion version, + const QuicAckFrame& ack_frame, + uint32_t local_ack_delay_exponent) { if (VersionHasIetfQuicFrames(version)) { // The minimal ack frame consists of the following fields: Largest // Acknowledged, ACK Delay, 0 ACK Block Count, First ACK Block and ECN @@ -498,13 +496,9 @@ size_t QuicFramer::GetMinAckFrameSize( } return min_size; } - if (GetQuicReloadableFlag(quic_use_ack_frame_to_get_min_size)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_use_ack_frame_to_get_min_size); - largest_observed_length = GetMinPacketNumberLength(LargestAcked(ack_frame)); - } - size_t min_size = kQuicFrameTypeSize + largest_observed_length + - kQuicDeltaTimeLargestObservedSize; - return min_size + kQuicNumTimestampsSize; + return kQuicFrameTypeSize + + GetMinPacketNumberLength(LargestAcked(ack_frame)) + + kQuicDeltaTimeLargestObservedSize + kQuicNumTimestampsSize; } // static @@ -541,16 +535,13 @@ size_t QuicFramer::GetConnectionCloseFrameSize( // Prepend the extra error information to the string and get the result's // length. const size_t truncated_error_string_size = TruncatedErrorStringSize( - GenerateErrorString(frame.error_details, frame.extracted_error_code)); + GenerateErrorString(frame.error_details, frame.quic_error_code)); const size_t frame_size = truncated_error_string_size + QuicDataWriter::GetVarInt62Len(truncated_error_string_size) + kQuicFrameTypeSize + - QuicDataWriter::GetVarInt62Len( - (frame.close_type == IETF_QUIC_TRANSPORT_CONNECTION_CLOSE) - ? frame.transport_error_code - : frame.application_error_code); + QuicDataWriter::GetVarInt62Len(frame.wire_error_code); if (frame.close_type == IETF_QUIC_APPLICATION_CONNECTION_CLOSE) { return frame_size; } @@ -819,9 +810,9 @@ size_t QuicFramer::GetSerializedFrameLength( } bool can_truncate = frame.type == ACK_FRAME && - free_bytes >= GetMinAckFrameSize( - version_.transport_version, *frame.ack_frame, - local_ack_delay_exponent_, PACKET_6BYTE_PACKET_NUMBER); + free_bytes >= GetMinAckFrameSize(version_.transport_version, + *frame.ack_frame, + local_ack_delay_exponent_); if (can_truncate) { // Truncate the frame so the packet will not exceed kMaxOutgoingPacketSize. // Note that we may not use every byte of the writer in this case. @@ -1621,26 +1612,14 @@ void QuicFramer::MaybeProcessCoalescedPacket( return; } - if (GetQuicReloadableFlag(quic_minimum_validation_of_coalesced_packets)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_minimum_validation_of_coalesced_packets); - if (coalesced_header.destination_connection_id != - header.destination_connection_id) { - // Drop coalesced packets with mismatched connection IDs. - QUIC_DLOG(INFO) << ENDPOINT << "Received mismatched coalesced header " - << coalesced_header << " previous header was " << header; - QUIC_CODE_COUNT( - quic_received_coalesced_packets_with_mismatched_connection_id); - return; - } - } else { - if (coalesced_header.destination_connection_id != - header.destination_connection_id || - (coalesced_header.form != IETF_QUIC_SHORT_HEADER_PACKET && - coalesced_header.version != header.version)) { - QUIC_PEER_BUG << ENDPOINT << "Received mismatched coalesced header " + if (coalesced_header.destination_connection_id != + header.destination_connection_id) { + // Drop coalesced packets with mismatched connection IDs. + QUIC_DLOG(INFO) << ENDPOINT << "Received mismatched coalesced header " << coalesced_header << " previous header was " << header; - return; - } + QUIC_CODE_COUNT( + quic_received_coalesced_packets_with_mismatched_connection_id); + return; } QuicEncryptedPacket coalesced_packet(coalesced_data, coalesced_data_length, @@ -1758,6 +1737,7 @@ bool QuicFramer::ProcessIetfDataPacket(QuicDataReader* encrypted_reader, visitor_->OnUndecryptablePacket( QuicEncryptedPacket(encrypted_reader->FullPayload()), decryption_level, has_decryption_key); + RecordDroppedPacketReason(DroppedPacketReason::DECRYPTION_FAILURE); set_detailed_error(quiche::QuicheStrCat( "Unable to decrypt ", EncryptionLevelToString(decryption_level), " header protection", has_decryption_key ? "" : " (missing key)", @@ -3469,12 +3449,12 @@ bool QuicFramer::ProcessIetfStreamFrame(QuicDataReader* reader, // If we have a data length, read it. If not, set to 0. if (frame_type & IETF_STREAM_FRAME_LEN_BIT) { - QuicIetfStreamDataLength length; + uint64_t length; if (!reader->ReadVarInt62(&length)) { set_detailed_error("Unable to read stream data length."); return false; } - if (length > 0xffff) { + if (length > std::numeric_limits<decltype(frame->data_length)>::max()) { set_detailed_error("Stream data length is too large."); return false; } @@ -3498,7 +3478,7 @@ bool QuicFramer::ProcessIetfStreamFrame(QuicDataReader* reader, return false; } frame->data_buffer = data.data(); - frame->data_length = static_cast<QuicIetfStreamDataLength>(data.length()); + DCHECK_EQ(frame->data_length, data.length()); return true; } @@ -3975,13 +3955,11 @@ bool QuicFramer::ProcessConnectionCloseFrame(QuicDataReader* reader, error_code = QUIC_LAST_ERROR; } + // For Google QUIC connection closes, |wire_error_code| and |quic_error_code| + // must have the same value. + frame->wire_error_code = error_code; frame->quic_error_code = static_cast<QuicErrorCode>(error_code); - // For Google QUIC connection closes, copy the Google QUIC error code to - // the extracted error code field so that the Google QUIC error code is always - // available in extracted_error_code. - frame->extracted_error_code = frame->quic_error_code; - quiche::QuicheStringPiece error_details; if (!reader->ReadStringPiece16(&error_details)) { set_detailed_error("Unable to read connection close error details."); @@ -4680,14 +4658,11 @@ size_t QuicFramer::GetAckFrameSize( return GetIetfAckFrameSize(ack); } AckFrameInfo ack_info = GetAckFrameInfo(ack); - QuicPacketNumberLength largest_acked_length = - GetMinPacketNumberLength(LargestAcked(ack)); QuicPacketNumberLength ack_block_length = GetMinPacketNumberLength(QuicPacketNumber(ack_info.max_block_length)); - ack_size = - GetMinAckFrameSize(version_.transport_version, ack, - local_ack_delay_exponent_, largest_acked_length); + ack_size = GetMinAckFrameSize(version_.transport_version, ack, + local_ack_delay_exponent_); // First ack block length. ack_size += ack_block_length; if (ack_info.num_ack_blocks != 0) { @@ -5153,7 +5128,7 @@ bool QuicFramer::AppendAckFrameAndTypeByte(const QuicAckFrame& frame, int32_t available_timestamp_and_ack_block_bytes = writer->capacity() - writer->length() - ack_block_length - GetMinAckFrameSize(version_.transport_version, frame, - local_ack_delay_exponent_, largest_acked_length) - + local_ack_delay_exponent_) - (new_ack_info.num_ack_blocks != 0 ? kNumberOfAckBlocksSize : 0); DCHECK_LE(0, available_timestamp_and_ack_block_bytes); @@ -5441,7 +5416,7 @@ bool QuicFramer::AppendIetfAckFrameAndTypeByte(const QuicAckFrame& frame, const uint64_t ack_range = iter->Length() - 1; if (writer->remaining() < ecn_size || - writer->remaining() - ecn_size < + static_cast<size_t>(writer->remaining() - ecn_size) < QuicDataWriter::GetVarInt62Len(gap) + QuicDataWriter::GetVarInt62Len(ack_range)) { // ACK range does not fit, truncate it. @@ -5517,7 +5492,7 @@ bool QuicFramer::AppendConnectionCloseFrame( if (VersionHasIetfQuicFrames(version_.transport_version)) { return AppendIetfConnectionCloseFrame(frame, writer); } - uint32_t error_code = static_cast<uint32_t>(frame.quic_error_code); + uint32_t error_code = static_cast<uint32_t>(frame.wire_error_code); if (!writer->WriteUInt32(error_code)) { return false; } @@ -5642,10 +5617,7 @@ bool QuicFramer::AppendIetfConnectionCloseFrame( return false; } - if (!writer->WriteVarInt62( - (frame.close_type == IETF_QUIC_TRANSPORT_CONNECTION_CLOSE) - ? frame.transport_error_code - : frame.application_error_code)) { + if (!writer->WriteVarInt62(frame.wire_error_code)) { set_detailed_error("Can not write connection close frame error code"); return false; } @@ -5663,7 +5635,7 @@ bool QuicFramer::AppendIetfConnectionCloseFrame( // code. Encode the error information in the reason phrase and serialize the // result. std::string final_error_string = - GenerateErrorString(frame.error_details, frame.extracted_error_code); + GenerateErrorString(frame.error_details, frame.quic_error_code); if (!writer->WriteStringPieceVarInt62( TruncateErrorString(final_error_string))) { set_detailed_error("Can not write connection close phrase"); @@ -5684,12 +5656,7 @@ bool QuicFramer::ProcessIetfConnectionCloseFrame( return false; } - if (frame->close_type == IETF_QUIC_TRANSPORT_CONNECTION_CLOSE) { - frame->transport_error_code = - static_cast<QuicIetfTransportErrorCodes>(error_code); - } else if (frame->close_type == IETF_QUIC_APPLICATION_CONNECTION_CLOSE) { - frame->application_error_code = error_code; - } + frame->wire_error_code = error_code; if (type == IETF_QUIC_TRANSPORT_CONNECTION_CLOSE) { // The frame-type of the frame causing the error is present only @@ -5790,18 +5757,13 @@ bool QuicFramer::ProcessIetfResetStreamFrame(QuicDataReader* reader, return false; } - uint64_t error_code; - if (!reader->ReadVarInt62(&error_code)) { + if (!reader->ReadVarInt62(&frame->ietf_error_code)) { set_detailed_error("Unable to read rst stream error code."); return false; } - if (error_code > 0xffff) { - frame->ietf_error_code = 0xffff; - QUIC_DLOG(ERROR) << "Reset stream error code (" << error_code - << ") > 0xffff"; - } else { - frame->ietf_error_code = static_cast<uint16_t>(error_code); - } + + frame->error_code = + IetfResetStreamErrorCodeToRstStreamErrorCode(frame->ietf_error_code); if (!reader->ReadVarInt62(&frame->byte_offset)) { set_detailed_error("Unable to read rst stream sent byte offset."); @@ -6626,10 +6588,10 @@ void MaybeExtractQuicErrorCode(QuicConnectionCloseFrame* frame) { if (ed.size() < 2 || !quiche::QuicheTextUtils::IsAllDigits(ed[0]) || !quiche::QuicheTextUtils::StringToUint64(ed[0], &extracted_error_code)) { if (frame->close_type == IETF_QUIC_TRANSPORT_CONNECTION_CLOSE && - frame->transport_error_code == NO_IETF_QUIC_ERROR) { - frame->extracted_error_code = QUIC_NO_ERROR; + frame->wire_error_code == NO_IETF_QUIC_ERROR) { + frame->quic_error_code = QUIC_NO_ERROR; } else { - frame->extracted_error_code = QUIC_IETF_GQUIC_ERROR_MISSING; + frame->quic_error_code = QUIC_IETF_GQUIC_ERROR_MISSING; } return; } @@ -6641,8 +6603,7 @@ void MaybeExtractQuicErrorCode(QuicConnectionCloseFrame* frame) { quiche::QuicheStringPiece x = quiche::QuicheStringPiece(frame->error_details); x.remove_prefix(ed[0].length() + 1); frame->error_details = std::string(x); - frame->extracted_error_code = - static_cast<QuicErrorCode>(extracted_error_code); + frame->quic_error_code = static_cast<QuicErrorCode>(extracted_error_code); } #undef ENDPOINT // undef for jumbo builds diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_framer.h b/chromium/net/third_party/quiche/src/quic/core/quic_framer.h index 746e6a1dacc..8ace715d285 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_framer.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_framer.h @@ -312,13 +312,9 @@ class QUIC_EXPORT_PRIVATE QuicFramer { QuicByteCount length); // Size in bytes of all ack frame fields without the missing packets or ack // blocks. - // TODO(fayang): Remove |largest_observed_length| when deprecating - // quic_use_ack_frame_to_get_min_size. - static size_t GetMinAckFrameSize( - QuicTransportVersion version, - const QuicAckFrame& ack_frame, - uint32_t local_ack_delay_exponent, - QuicPacketNumberLength largest_observed_length); + static size_t GetMinAckFrameSize(QuicTransportVersion version, + const QuicAckFrame& ack_frame, + uint32_t local_ack_delay_exponent); // Size in bytes of a stop waiting frame. static size_t GetStopWaitingFrameSize( QuicPacketNumberLength packet_number_length); @@ -1097,9 +1093,10 @@ class QUIC_EXPORT_PRIVATE QuicFramer { // This text, inserted by the peer if it's using Google's QUIC implementation, // contains additional error information that narrows down the exact error. The // extracted error code and (possibly updated) error_details string are returned -// in |*frame|. If an error code is not found in the error details then the -// extracted_error_code is set to QuicErrorCode::QUIC_IETF_GQUIC_ERROR_MISSING. -// If there is an error code in the string then it is removed from the string. +// in |*frame|. If an error code is not found in the error details, then +// frame->quic_error_code is set to +// QuicErrorCode::QUIC_IETF_GQUIC_ERROR_MISSING. If there is an error code in +// the string then it is removed from the string. QUIC_EXPORT_PRIVATE void MaybeExtractQuicErrorCode( QuicConnectionCloseFrame* frame); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc index 813d4f6c270..fb9c2eb87bc 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc @@ -4259,9 +4259,9 @@ TEST_P(QuicFramerTest, RstStreamFrame) { {"Unable to read rst stream sent byte offset.", {0x3A, 0x98, 0xFE, 0xDC, 0x32, 0x10, 0x76, 0x54}}, - // error code + // error code QUIC_STREAM_CANCELLED {"Unable to read rst stream error code.", - {0x00, 0x00, 0x00, 0x01}} + {0x00, 0x00, 0x00, 0x06}} }; PacketFragments packet46 = { @@ -4284,9 +4284,9 @@ TEST_P(QuicFramerTest, RstStreamFrame) { {"Unable to read rst stream sent byte offset.", {0x3A, 0x98, 0xFE, 0xDC, 0x32, 0x10, 0x76, 0x54}}, - // error code + // error code QUIC_STREAM_CANCELLED {"Unable to read rst stream error code.", - {0x00, 0x00, 0x00, 0x01}} + {0x00, 0x00, 0x00, 0x06}} }; PacketFragments packet99 = { @@ -4305,9 +4305,10 @@ TEST_P(QuicFramerTest, RstStreamFrame) { // stream id {"Unable to read IETF_RST_STREAM frame stream id/count.", {kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04}}, - // application error code + // application error code H3_REQUEST_CANCELLED gets translated to + // QuicRstStreamErrorCode::QUIC_STREAM_CANCELLED. {"Unable to read rst stream error code.", - {kVarInt62OneByte + 0x01}}, + {kVarInt62TwoBytes + 0x01, 0x0c}}, // Final Offset {"Unable to read rst stream sent byte offset.", {kVarInt62EightBytes + 0x3a, 0x98, 0xFE, 0xDC, 0x32, 0x10, 0x76, 0x54}} @@ -4330,7 +4331,7 @@ TEST_P(QuicFramerTest, RstStreamFrame) { PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); EXPECT_EQ(kStreamId, visitor_.rst_stream_frame_.stream_id); - EXPECT_EQ(0x01, visitor_.rst_stream_frame_.error_code); + EXPECT_EQ(QUIC_STREAM_CANCELLED, visitor_.rst_stream_frame_.error_code); EXPECT_EQ(kStreamOffset, visitor_.rst_stream_frame_.byte_offset); CheckFramingBoundaries(fragments, QUIC_INVALID_RST_STREAM_DATA); } @@ -4442,19 +4443,18 @@ TEST_P(QuicFramerTest, ConnectionCloseFrame) { EXPECT_EQ(0u, visitor_.stream_frames_.size()); EXPECT_EQ(0x11u, static_cast<unsigned>( - visitor_.connection_close_frame_.quic_error_code)); + visitor_.connection_close_frame_.wire_error_code)); EXPECT_EQ("because I can", visitor_.connection_close_frame_.error_details); if (VersionHasIetfQuicFrames(framer_.transport_version())) { EXPECT_EQ(0x1234u, visitor_.connection_close_frame_.transport_close_frame_type); - EXPECT_THAT(visitor_.connection_close_frame_.extracted_error_code, + EXPECT_THAT(visitor_.connection_close_frame_.quic_error_code, IsError(QUIC_IETF_GQUIC_ERROR_MISSING)); } else { - // For Google QUIC closes, the error code is copied into - // extracted_error_code. - EXPECT_EQ(0x11u, - static_cast<unsigned>( - visitor_.connection_close_frame_.extracted_error_code)); + // For Google QUIC frame, |quic_error_code| and |wire_error_code| has the + // same value. + EXPECT_EQ(0x11u, static_cast<unsigned>( + visitor_.connection_close_frame_.quic_error_code)); } ASSERT_EQ(0u, visitor_.ack_frames_.size()); @@ -4576,15 +4576,15 @@ TEST_P(QuicFramerTest, ConnectionCloseFrameWithExtractedInfoIgnoreGCuic) { EXPECT_EQ(0u, visitor_.stream_frames_.size()); EXPECT_EQ(0x11u, static_cast<unsigned>( - visitor_.connection_close_frame_.quic_error_code)); + visitor_.connection_close_frame_.wire_error_code)); if (VersionHasIetfQuicFrames(framer_.transport_version())) { EXPECT_EQ(0x1234u, visitor_.connection_close_frame_.transport_close_frame_type); - EXPECT_EQ(17767u, visitor_.connection_close_frame_.extracted_error_code); + EXPECT_EQ(17767u, visitor_.connection_close_frame_.quic_error_code); EXPECT_EQ("because I can", visitor_.connection_close_frame_.error_details); } else { - EXPECT_EQ(0x11u, visitor_.connection_close_frame_.extracted_error_code); + EXPECT_EQ(0x11u, visitor_.connection_close_frame_.quic_error_code); // Error code is not prepended in GQUIC, so it is not removed and should // remain in the reason phrase. EXPECT_EQ("17767:because I can", @@ -4648,8 +4648,8 @@ TEST_P(QuicFramerTest, ApplicationCloseFrame) { EXPECT_EQ(IETF_QUIC_APPLICATION_CONNECTION_CLOSE, visitor_.connection_close_frame_.close_type); - EXPECT_EQ(122u, visitor_.connection_close_frame_.extracted_error_code); - EXPECT_EQ(0x11u, visitor_.connection_close_frame_.quic_error_code); + EXPECT_EQ(122u, visitor_.connection_close_frame_.quic_error_code); + EXPECT_EQ(0x11u, visitor_.connection_close_frame_.wire_error_code); EXPECT_EQ("because I can", visitor_.connection_close_frame_.error_details); ASSERT_EQ(0u, visitor_.ack_frames_.size()); @@ -4710,8 +4710,8 @@ TEST_P(QuicFramerTest, ApplicationCloseFrameExtract) { EXPECT_EQ(IETF_QUIC_APPLICATION_CONNECTION_CLOSE, visitor_.connection_close_frame_.close_type); - EXPECT_EQ(17767u, visitor_.connection_close_frame_.extracted_error_code); - EXPECT_EQ(0x11u, visitor_.connection_close_frame_.quic_error_code); + EXPECT_EQ(17767u, visitor_.connection_close_frame_.quic_error_code); + EXPECT_EQ(0x11u, visitor_.connection_close_frame_.wire_error_code); EXPECT_EQ("because I can", visitor_.connection_close_frame_.error_details); ASSERT_EQ(0u, visitor_.ack_frames_.size()); @@ -7528,12 +7528,7 @@ TEST_P(QuicFramerTest, BuildCloseFramePacket) { header.packet_number = kPacketNumber; QuicConnectionCloseFrame close_frame( - framer_.transport_version(), - static_cast<QuicErrorCode>( - VersionHasIetfQuicFrames(framer_.transport_version()) ? 0x11 - : 0x05060708), - "because I can", 0x05); - close_frame.extracted_error_code = QUIC_IETF_GQUIC_ERROR_MISSING; + framer_.transport_version(), QUIC_INTERNAL_ERROR, "because I can", 0x05); QuicFrames frames = {QuicFrame(&close_frame)}; // clang-format off @@ -7548,7 +7543,7 @@ TEST_P(QuicFramerTest, BuildCloseFramePacket) { // frame type (connection close frame) 0x02, // error code - 0x05, 0x06, 0x07, 0x08, + 0x00, 0x00, 0x00, 0x01, // error details length 0x00, 0x0d, // error details @@ -7569,7 +7564,7 @@ TEST_P(QuicFramerTest, BuildCloseFramePacket) { // frame type (connection close frame) 0x02, // error code - 0x05, 0x06, 0x07, 0x08, + 0x00, 0x00, 0x00, 0x01, // error details length 0x00, 0x0d, // error details @@ -7590,16 +7585,16 @@ TEST_P(QuicFramerTest, BuildCloseFramePacket) { // frame type (IETF_CONNECTION_CLOSE frame) 0x1c, // error code - kVarInt62OneByte + 0x11, + kVarInt62OneByte + 0x01, // Frame type within the CONNECTION_CLOSE frame kVarInt62OneByte + 0x05, // error details length - kVarInt62OneByte + 0x0d, + kVarInt62OneByte + 0x0f, // error details - 'b', 'e', 'c', 'a', - 'u', 's', 'e', ' ', - 'I', ' ', 'c', 'a', - 'n', + '1', ':', 'b', 'e', + 'c', 'a', 'u', 's', + 'e', ' ', 'I', ' ', + 'c', 'a', 'n', }; // clang-format on @@ -7631,12 +7626,12 @@ TEST_P(QuicFramerTest, BuildCloseFramePacketExtendedInfo) { QuicConnectionCloseFrame close_frame( framer_.transport_version(), static_cast<QuicErrorCode>( - VersionHasIetfQuicFrames(framer_.transport_version()) ? 0x11 + VersionHasIetfQuicFrames(framer_.transport_version()) ? 0x01 : 0x05060708), "because I can", 0x05); // Set this so that it is "there" for both Google QUIC and IETF QUIC // framing. It better not show up for Google QUIC! - close_frame.extracted_error_code = static_cast<QuicErrorCode>(0x4567); + close_frame.quic_error_code = static_cast<QuicErrorCode>(0x4567); QuicFrames frames = {QuicFrame(&close_frame)}; @@ -7693,8 +7688,9 @@ TEST_P(QuicFramerTest, BuildCloseFramePacketExtendedInfo) { // frame type (IETF_CONNECTION_CLOSE frame) 0x1c, - // error code - kVarInt62OneByte + 0x11, + // IETF error code INTERNAL_ERROR = 0x01 corresponding to + // QuicErrorCode::QUIC_INTERNAL_ERROR = 0x01. + kVarInt62OneByte + 0x01, // Frame type within the CONNECTION_CLOSE frame kVarInt62OneByte + 0x05, // error details length @@ -7733,13 +7729,9 @@ TEST_P(QuicFramerTest, BuildTruncatedCloseFramePacket) { header.version_flag = false; header.packet_number = kPacketNumber; - QuicConnectionCloseFrame close_frame( - framer_.transport_version(), - static_cast<QuicErrorCode>( - VersionHasIetfQuicFrames(framer_.transport_version()) ? 0xa - : 0x05060708), - std::string(2048, 'A'), 0x05); - close_frame.extracted_error_code = QUIC_IETF_GQUIC_ERROR_MISSING; + QuicConnectionCloseFrame close_frame(framer_.transport_version(), + QUIC_INTERNAL_ERROR, + std::string(2048, 'A'), 0x05); QuicFrames frames = {QuicFrame(&close_frame)}; // clang-format off @@ -7754,7 +7746,7 @@ TEST_P(QuicFramerTest, BuildTruncatedCloseFramePacket) { // frame type (connection close frame) 0x02, // error code - 0x05, 0x06, 0x07, 0x08, + 0x00, 0x00, 0x00, 0x01, // error details length 0x01, 0x00, // error details (truncated to 256 bytes) @@ -7803,7 +7795,7 @@ TEST_P(QuicFramerTest, BuildTruncatedCloseFramePacket) { // frame type (connection close frame) 0x02, // error code - 0x05, 0x06, 0x07, 0x08, + 0x00, 0x00, 0x00, 0x01, // error details length 0x01, 0x00, // error details (truncated to 256 bytes) @@ -7852,13 +7844,13 @@ TEST_P(QuicFramerTest, BuildTruncatedCloseFramePacket) { // frame type (IETF_CONNECTION_CLOSE frame) 0x1c, // error code - kVarInt62OneByte + 0x0a, + kVarInt62OneByte + 0x01, // Frame type within the CONNECTION_CLOSE frame kVarInt62OneByte + 0x05, // error details length kVarInt62TwoBytes + 0x01, 0x00, // error details (truncated to 256 bytes) - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', + '1', ':', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', @@ -7923,8 +7915,7 @@ TEST_P(QuicFramerTest, BuildApplicationCloseFramePacket) { header.packet_number = kPacketNumber; QuicConnectionCloseFrame app_close_frame; - app_close_frame.application_error_code = - static_cast<uint64_t>(QUIC_INVALID_STREAM_ID); + app_close_frame.wire_error_code = 0x11; app_close_frame.error_details = "because I can"; app_close_frame.close_type = IETF_QUIC_APPLICATION_CONNECTION_CLOSE; @@ -7975,13 +7966,12 @@ TEST_P(QuicFramerTest, BuildTruncatedApplicationCloseFramePacket) { header.packet_number = kPacketNumber; QuicConnectionCloseFrame app_close_frame; - app_close_frame.application_error_code = - static_cast<uint64_t>(QUIC_INVALID_STREAM_ID); + app_close_frame.wire_error_code = 0x11; app_close_frame.error_details = std::string(2048, 'A'); app_close_frame.close_type = IETF_QUIC_APPLICATION_CONNECTION_CLOSE; // Setting to missing ensures that if it is missing, the extended // code is not added to the text message. - app_close_frame.extracted_error_code = QUIC_IETF_GQUIC_ERROR_MISSING; + app_close_frame.quic_error_code = QUIC_IETF_GQUIC_ERROR_MISSING; QuicFrames frames = {QuicFrame(&app_close_frame)}; @@ -12451,7 +12441,6 @@ TEST_P(QuicFramerTest, CoalescedPacketWithDifferentVersion) { if (!QuicVersionHasLongHeaderLengths(framer_.transport_version())) { return; } - SetQuicReloadableFlag(quic_minimum_validation_of_coalesced_packets, true); SetDecrypterLevel(ENCRYPTION_ZERO_RTT); // clang-format off unsigned char packet[] = { @@ -13123,12 +13112,7 @@ TEST_P(QuicFramerTest, MismatchedCoalescedPacket) { QuicEncryptedPacket encrypted(AsChars(p), p_length, false); - if (GetQuicReloadableFlag(quic_minimum_validation_of_coalesced_packets)) { - EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - } else { - EXPECT_QUIC_PEER_BUG(EXPECT_TRUE(framer_.ProcessPacket(encrypted)), - "Server: Received mismatched coalesced header.*"); - } + EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); @@ -14254,84 +14238,77 @@ TEST_P(QuicFramerTest, TestExtendedErrorCodeParser) { frame.error_details = "this has no error code info in it"; MaybeExtractQuicErrorCode(&frame); - EXPECT_THAT(frame.extracted_error_code, - IsError(QUIC_IETF_GQUIC_ERROR_MISSING)); + EXPECT_THAT(frame.quic_error_code, IsError(QUIC_IETF_GQUIC_ERROR_MISSING)); EXPECT_EQ("this has no error code info in it", frame.error_details); frame.error_details = "1234this does not have the colon in it"; MaybeExtractQuicErrorCode(&frame); - EXPECT_THAT(frame.extracted_error_code, - IsError(QUIC_IETF_GQUIC_ERROR_MISSING)); + EXPECT_THAT(frame.quic_error_code, IsError(QUIC_IETF_GQUIC_ERROR_MISSING)); EXPECT_EQ("1234this does not have the colon in it", frame.error_details); frame.error_details = "1a234:this has a colon, but a malformed error number"; MaybeExtractQuicErrorCode(&frame); - EXPECT_THAT(frame.extracted_error_code, - IsError(QUIC_IETF_GQUIC_ERROR_MISSING)); + EXPECT_THAT(frame.quic_error_code, IsError(QUIC_IETF_GQUIC_ERROR_MISSING)); EXPECT_EQ("1a234:this has a colon, but a malformed error number", frame.error_details); frame.error_details = "1234:this is good"; MaybeExtractQuicErrorCode(&frame); - EXPECT_EQ(1234u, frame.extracted_error_code); + EXPECT_EQ(1234u, frame.quic_error_code); EXPECT_EQ("this is good", frame.error_details); frame.error_details = "1234 :this is not good, space between last digit and colon"; MaybeExtractQuicErrorCode(&frame); - EXPECT_THAT(frame.extracted_error_code, - IsError(QUIC_IETF_GQUIC_ERROR_MISSING)); + EXPECT_THAT(frame.quic_error_code, IsError(QUIC_IETF_GQUIC_ERROR_MISSING)); EXPECT_EQ("1234 :this is not good, space between last digit and colon", frame.error_details); frame.error_details = "123456789"; MaybeExtractQuicErrorCode(&frame); EXPECT_THAT( - frame.extracted_error_code, + frame.quic_error_code, IsError(QUIC_IETF_GQUIC_ERROR_MISSING)); // Not good, all numbers, no : EXPECT_EQ("123456789", frame.error_details); frame.error_details = "1234:"; MaybeExtractQuicErrorCode(&frame); EXPECT_EQ(1234u, - frame.extracted_error_code); // corner case. + frame.quic_error_code); // corner case. EXPECT_EQ("", frame.error_details); frame.error_details = "1234:5678"; MaybeExtractQuicErrorCode(&frame); EXPECT_EQ(1234u, - frame.extracted_error_code); // another corner case. + frame.quic_error_code); // another corner case. EXPECT_EQ("5678", frame.error_details); frame.error_details = "12345 6789:"; MaybeExtractQuicErrorCode(&frame); - EXPECT_THAT(frame.extracted_error_code, + EXPECT_THAT(frame.quic_error_code, IsError(QUIC_IETF_GQUIC_ERROR_MISSING)); // Not good EXPECT_EQ("12345 6789:", frame.error_details); frame.error_details = ":no numbers, is not good"; MaybeExtractQuicErrorCode(&frame); - EXPECT_THAT(frame.extracted_error_code, - IsError(QUIC_IETF_GQUIC_ERROR_MISSING)); + EXPECT_THAT(frame.quic_error_code, IsError(QUIC_IETF_GQUIC_ERROR_MISSING)); EXPECT_EQ(":no numbers, is not good", frame.error_details); frame.error_details = "qwer:also no numbers, is not good"; MaybeExtractQuicErrorCode(&frame); - EXPECT_THAT(frame.extracted_error_code, - IsError(QUIC_IETF_GQUIC_ERROR_MISSING)); + EXPECT_THAT(frame.quic_error_code, IsError(QUIC_IETF_GQUIC_ERROR_MISSING)); EXPECT_EQ("qwer:also no numbers, is not good", frame.error_details); frame.error_details = " 1234:this is not good, space before first digit"; MaybeExtractQuicErrorCode(&frame); - EXPECT_THAT(frame.extracted_error_code, - IsError(QUIC_IETF_GQUIC_ERROR_MISSING)); + EXPECT_THAT(frame.quic_error_code, IsError(QUIC_IETF_GQUIC_ERROR_MISSING)); EXPECT_EQ(" 1234:this is not good, space before first digit", frame.error_details); frame.error_details = "1234:"; MaybeExtractQuicErrorCode(&frame); EXPECT_EQ(1234u, - frame.extracted_error_code); // this is good + frame.quic_error_code); // this is good EXPECT_EQ("", frame.error_details); } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_idle_network_detector_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_idle_network_detector_test.cc index 16941ef7a82..0d40d640417 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_idle_network_detector_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_idle_network_detector_test.cc @@ -22,8 +22,8 @@ namespace { class MockDelegate : public QuicIdleNetworkDetector::Delegate { public: - MOCK_METHOD0(OnHandshakeTimeout, void()); - MOCK_METHOD0(OnIdleNetworkDetected, void()); + MOCK_METHOD(void, OnHandshakeTimeout, (), (override)); + MOCK_METHOD(void, OnIdleNetworkDetected, (), (override)); }; class QuicIdleNetworkDetectorTest : public QuicTest { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector_test.cc index eca50e3c1f3..0178887c2f8 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector_test.cc @@ -21,8 +21,8 @@ class QuicNetworkBlackholeDetectorPeer { namespace { class MockDelegate : public QuicNetworkBlackholeDetector::Delegate { public: - MOCK_METHOD0(OnPathDegradingDetected, void()); - MOCK_METHOD0(OnBlackholeDetected, void()); + MOCK_METHOD(void, OnPathDegradingDetected, (), (override)); + MOCK_METHOD(void, OnBlackholeDetected, (), (override)); }; const size_t kPathDegradingDelayInSeconds = 5; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_one_block_arena.h b/chromium/net/third_party/quiche/src/quic/core/quic_one_block_arena.h index d6b7ee99b55..41842f35963 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_one_block_arena.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_one_block_arena.h @@ -75,10 +75,7 @@ QuicArenaScopedPtr<T> QuicOneBlockArena<ArenaSize>::New(Args&&... args) { // QuicConnections currently use around 1KB of polymorphic types which would // ordinarily be on the heap. Instead, store them inline in an arena. -// TODO(fayang): Switch this and 1200 used in quic_arena_scoped_ptr_test and -// quic_one_block_arena_test back to 1024 when deprecating -// quic_use_blackhole_detector or quic_use_idle_network_detector. -using QuicConnectionArena = QuicOneBlockArena<1200>; +using QuicConnectionArena = QuicOneBlockArena<1024>; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_one_block_arena_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_one_block_arena_test.cc index 11b12de410a..3175ac54abf 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_one_block_arena_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_one_block_arena_test.cc @@ -23,14 +23,14 @@ struct TestObject { class QuicOneBlockArenaTest : public QuicTest {}; TEST_F(QuicOneBlockArenaTest, AllocateSuccess) { - QuicOneBlockArena<1200> arena; + QuicOneBlockArena<1024> arena; QuicArenaScopedPtr<TestObject> ptr = arena.New<TestObject>(); EXPECT_TRUE(ptr.is_from_arena()); } TEST_F(QuicOneBlockArenaTest, Exhaust) { - QuicOneBlockArena<1200> arena; - for (size_t i = 0; i < 1200 / kMaxAlign; ++i) { + QuicOneBlockArena<1024> arena; + for (size_t i = 0; i < 1024 / kMaxAlign; ++i) { QuicArenaScopedPtr<TestObject> ptr = arena.New<TestObject>(); EXPECT_TRUE(ptr.is_from_arena()); } @@ -41,10 +41,10 @@ TEST_F(QuicOneBlockArenaTest, Exhaust) { } TEST_F(QuicOneBlockArenaTest, NoOverlaps) { - QuicOneBlockArena<1200> arena; + QuicOneBlockArena<1024> arena; std::vector<QuicArenaScopedPtr<TestObject>> objects; QuicIntervalSet<uintptr_t> used; - for (size_t i = 0; i < 1200 / kMaxAlign; ++i) { + for (size_t i = 0; i < 1024 / kMaxAlign; ++i) { QuicArenaScopedPtr<TestObject> ptr = arena.New<TestObject>(); EXPECT_TRUE(ptr.is_from_arena()); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.cc index cea1a1be9cf..0ae78d22fa6 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.cc @@ -7,6 +7,7 @@ #include <algorithm> #include <cstddef> #include <cstdint> +#include <limits> #include <string> #include <utility> @@ -130,8 +131,15 @@ QuicPacketCreator::QuicPacketCreator(QuicConnectionId server_connection_id, next_transmission_type_(NOT_RETRANSMISSION), flusher_attached_(false), fully_pad_crypto_handshake_packets_(true), - latched_hard_max_packet_length_(0) { + latched_hard_max_packet_length_(0), + max_datagram_frame_size_(0) { SetMaxPacketLength(kDefaultMaxPacketSize); + if (!framer_->version().UsesTls()) { + // QUIC+TLS negotiates the maximum datagram frame size via the + // IETF QUIC max_datagram_frame_size transport parameter. + // QUIC_CRYPTO however does not negotiate this so we set its value here. + SetMaxDatagramFrameSize(kMaxAcceptedDatagramFrameSize); + } } QuicPacketCreator::~QuicPacketCreator() { @@ -165,6 +173,21 @@ void QuicPacketCreator::SetMaxPacketLength(QuicByteCount length) { << "Attempted to set max packet length too small"; } +void QuicPacketCreator::SetMaxDatagramFrameSize( + QuicByteCount max_datagram_frame_size) { + constexpr QuicByteCount upper_bound = + std::min<QuicByteCount>(std::numeric_limits<QuicPacketLength>::max(), + std::numeric_limits<size_t>::max()); + if (max_datagram_frame_size > upper_bound) { + // A value of |max_datagram_frame_size| that is equal or greater than + // 2^16-1 is effectively infinite because QUIC packets cannot be that large. + // We therefore clamp the value here to allow us to safely cast + // |max_datagram_frame_size_| to QuicPacketLength or size_t. + max_datagram_frame_size = upper_bound; + } + max_datagram_frame_size_ = max_datagram_frame_size; +} + void QuicPacketCreator::SetSoftMaxPacketLength(QuicByteCount length) { DCHECK(CanSetMaxPacketLength()); if (length > max_packet_length_) { @@ -326,6 +349,10 @@ bool QuicPacketCreator::HasRoomForStreamFrame(QuicStreamId id, bool QuicPacketCreator::HasRoomForMessageFrame(QuicByteCount length) { const size_t message_frame_size = QuicFramer::GetMessageFrameSize( framer_->transport_version(), /*last_frame_in_packet=*/true, length); + if (static_cast<QuicByteCount>(message_frame_size) > + max_datagram_frame_size_) { + return false; + } if (BytesFree() >= message_frame_size) { return true; } @@ -433,7 +460,7 @@ void QuicPacketCreator::OnSerializedPacket() { SerializedPacket packet(std::move(packet_)); ClearPacket(); RemoveSoftMaxPacketLength(); - delegate_->OnSerializedPacket(&packet); + delegate_->OnSerializedPacket(std::move(packet)); } void QuicPacketCreator::ClearPacket() { @@ -741,7 +768,7 @@ QuicPacketCreator::SerializeVersionNegotiationPacket( return encrypted; } -OwningSerializedPacketPointer +std::unique_ptr<SerializedPacket> QuicPacketCreator::SerializeConnectivityProbingPacket() { QUIC_BUG_IF(VersionHasIetfQuicFrames(framer_->transport_version())) << "Must not be version 99 to serialize padded ping connectivity probe"; @@ -764,17 +791,20 @@ QuicPacketCreator::SerializeConnectivityProbingPacket() { kMaxOutgoingPacketSize, buffer.get()); DCHECK(encrypted_length); - OwningSerializedPacketPointer serialize_packet(new SerializedPacket( + std::unique_ptr<SerializedPacket> serialize_packet(new SerializedPacket( header.packet_number, header.packet_number_length, buffer.release(), encrypted_length, /*has_ack=*/false, /*has_stop_waiting=*/false)); + serialize_packet->release_encrypted_buffer = [](const char* p) { + delete[] p; + }; serialize_packet->encryption_level = packet_.encryption_level; serialize_packet->transmission_type = NOT_RETRANSMISSION; return serialize_packet; } -OwningSerializedPacketPointer +std::unique_ptr<SerializedPacket> QuicPacketCreator::SerializePathChallengeConnectivityProbingPacket( QuicPathFrameBuffer* payload) { QUIC_BUG_IF(!VersionHasIetfQuicFrames(framer_->transport_version())) @@ -800,17 +830,21 @@ QuicPacketCreator::SerializePathChallengeConnectivityProbingPacket( kMaxOutgoingPacketSize, buffer.get()); DCHECK(encrypted_length); - OwningSerializedPacketPointer serialize_packet(new SerializedPacket( - header.packet_number, header.packet_number_length, buffer.release(), - encrypted_length, /*has_ack=*/false, /*has_stop_waiting=*/false)); + std::unique_ptr<SerializedPacket> serialize_packet( + new SerializedPacket(header.packet_number, header.packet_number_length, + buffer.release(), encrypted_length, + /*has_ack=*/false, /*has_stop_waiting=*/false)); + serialize_packet->release_encrypted_buffer = [](const char* p) { + delete[] p; + }; serialize_packet->encryption_level = packet_.encryption_level; serialize_packet->transmission_type = NOT_RETRANSMISSION; return serialize_packet; } -OwningSerializedPacketPointer +std::unique_ptr<SerializedPacket> QuicPacketCreator::SerializePathResponseConnectivityProbingPacket( const QuicCircularDeque<QuicPathFrameBuffer>& payloads, const bool is_padded) { @@ -837,10 +871,14 @@ QuicPacketCreator::SerializePathResponseConnectivityProbingPacket( kMaxOutgoingPacketSize, buffer.get()); DCHECK(encrypted_length); - OwningSerializedPacketPointer serialize_packet(new SerializedPacket( - header.packet_number, header.packet_number_length, buffer.release(), - encrypted_length, /*has_ack=*/false, /*has_stop_waiting=*/false)); + std::unique_ptr<SerializedPacket> serialize_packet( + new SerializedPacket(header.packet_number, header.packet_number_length, + buffer.release(), encrypted_length, + /*has_ack=*/false, /*has_stop_waiting=*/false)); + serialize_packet->release_encrypted_buffer = [](const char* p) { + delete[] p; + }; serialize_packet->encryption_level = packet_.encryption_level; serialize_packet->transmission_type = NOT_RETRANSMISSION; @@ -1705,8 +1743,12 @@ QuicPacketLength QuicPacketCreator::GetCurrentLargestMessagePayload() const { latched_hard_max_packet_length_ == 0 ? max_plaintext_size_ : framer_->GetMaxPlaintextSize(latched_hard_max_packet_length_); - return max_plaintext_size - - std::min(max_plaintext_size, packet_header_size + kQuicFrameTypeSize); + size_t largest_frame = + max_plaintext_size - std::min(max_plaintext_size, packet_header_size); + if (static_cast<QuicByteCount>(largest_frame) > max_datagram_frame_size_) { + largest_frame = static_cast<size_t>(max_datagram_frame_size_); + } + return largest_frame - std::min(largest_frame, kQuicFrameTypeSize); } QuicPacketLength QuicPacketCreator::GetGuaranteedLargestMessagePayload() const { @@ -1739,9 +1781,13 @@ QuicPacketLength QuicPacketCreator::GetGuaranteedLargestMessagePayload() const { latched_hard_max_packet_length_ == 0 ? max_plaintext_size_ : framer_->GetMaxPlaintextSize(latched_hard_max_packet_length_); + size_t largest_frame = + max_plaintext_size - std::min(max_plaintext_size, packet_header_size); + if (static_cast<QuicByteCount>(largest_frame) > max_datagram_frame_size_) { + largest_frame = static_cast<size_t>(max_datagram_frame_size_); + } const QuicPacketLength largest_payload = - max_plaintext_size - - std::min(max_plaintext_size, packet_header_size + kQuicFrameTypeSize); + largest_frame - std::min(largest_frame, kQuicFrameTypeSize); // This must always be less than or equal to GetCurrentLargestMessagePayload. DCHECK_LE(largest_payload, GetCurrentLargestMessagePayload()); return largest_payload; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h index 508cd56256f..7695587f9f5 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h @@ -44,10 +44,9 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // packet. If return nullptr, QuicPacketCreator will serialize on a stack // buffer. virtual char* GetPacketBuffer() = 0; - // Called when a packet is serialized. Delegate does not take the ownership - // of |serialized_packet|, but takes ownership of any frames it removes - // from |packet.retransmittable_frames|. - virtual void OnSerializedPacket(SerializedPacket* serialized_packet) = 0; + // Called when a packet is serialized. Delegate take the ownership of + // |serialized_packet|. + virtual void OnSerializedPacket(SerializedPacket serialized_packet) = 0; // Called when an unrecoverable error is encountered. virtual void OnUnrecoverableError(QuicErrorCode error, @@ -210,19 +209,20 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { const ParsedQuicVersionVector& supported_versions); // Creates a connectivity probing packet for versions prior to version 99. - OwningSerializedPacketPointer SerializeConnectivityProbingPacket(); + std::unique_ptr<SerializedPacket> SerializeConnectivityProbingPacket(); // Create connectivity probing request and response packets using PATH // CHALLENGE and PATH RESPONSE frames, respectively, for version 99/IETF QUIC. // SerializePathChallengeConnectivityProbingPacket will pad the packet to be // MTU bytes long. - OwningSerializedPacketPointer SerializePathChallengeConnectivityProbingPacket( - QuicPathFrameBuffer* payload); + std::unique_ptr<SerializedPacket> + SerializePathChallengeConnectivityProbingPacket(QuicPathFrameBuffer* payload); // If |is_padded| is true then SerializePathResponseConnectivityProbingPacket // will pad the packet to be MTU bytes long, else it will not pad the packet. // |payloads| is cleared. - OwningSerializedPacketPointer SerializePathResponseConnectivityProbingPacket( + std::unique_ptr<SerializedPacket> + SerializePathResponseConnectivityProbingPacket( const QuicCircularDeque<QuicPathFrameBuffer>& payloads, const bool is_padded); @@ -278,6 +278,9 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // Sets the maximum packet length. void SetMaxPacketLength(QuicByteCount length); + // Sets the maximum DATAGRAM/MESSAGE frame size we can send. + void SetMaxDatagramFrameSize(QuicByteCount max_datagram_frame_size); + // Set a soft maximum packet length in the creator. If a packet cannot be // successfully created, creator will remove the soft limit and use the actual // max packet length. @@ -455,8 +458,8 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // Serializes all frames which have been added and adds any which should be // retransmitted to packet_.retransmittable_frames. All frames must fit into // a single packet. - // Fails if |buffer_len| isn't long enough for the encrypted packet. - void SerializePacket(char* encrypted_buffer, size_t buffer_len); + // Fails if |encrypted_buffer_len| isn't long enough for the encrypted packet. + void SerializePacket(char* encrypted_buffer, size_t encrypted_buffer_len); // Called after a new SerialiedPacket is created to call the delegate's // OnSerializedPacket and reset state. @@ -589,6 +592,11 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // SetSoftMaxPacketLength is called and max_packet_length_ gets // set to a soft value. QuicByteCount latched_hard_max_packet_length_; + + // The maximum length of a MESSAGE/DATAGRAM frame that our peer is willing to + // accept. There is no limit for QUIC_CRYPTO connections, but QUIC+TLS + // negotiates this during the handshake. + QuicByteCount max_datagram_frame_size_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc index 1507ae5f34d..d1beea7c01d 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc @@ -86,9 +86,12 @@ class MockDebugDelegate : public QuicPacketCreator::DebugDelegate { public: ~MockDebugDelegate() override = default; - MOCK_METHOD1(OnFrameAddedToPacket, void(const QuicFrame& frame)); + MOCK_METHOD(void, OnFrameAddedToPacket, (const QuicFrame& frame), (override)); - MOCK_METHOD1(OnStreamFrameCoalesced, void(const QuicStreamFrame& frame)); + MOCK_METHOD(void, + OnStreamFrameCoalesced, + (const QuicStreamFrame& frame), + (override)); }; class TestPacketCreator : public QuicPacketCreator { @@ -135,28 +138,16 @@ class TestPacketCreator : public QuicPacketCreator { class QuicPacketCreatorTest : public QuicTestWithParam<TestParams> { public: - void ClearSerializedPacketForTests(SerializedPacket* serialized_packet) { - if (serialized_packet == nullptr) { - return; - } - ClearSerializedPacket(serialized_packet); + void ClearSerializedPacketForTests(SerializedPacket /*serialized_packet*/) { + // serialized packet self-clears on destruction. } - void SaveSerializedPacket(SerializedPacket* serialized_packet) { - if (serialized_packet == nullptr) { - return; - } - delete[] serialized_packet_.encrypted_buffer; - serialized_packet_ = *serialized_packet; - serialized_packet_.encrypted_buffer = CopyBuffer(*serialized_packet); - serialized_packet->retransmittable_frames.clear(); + void SaveSerializedPacket(SerializedPacket serialized_packet) { + serialized_packet_.reset(CopySerializedPacket( + serialized_packet, &allocator_, /*copy_buffer=*/true)); } - void DeleteSerializedPacket() { - delete[] serialized_packet_.encrypted_buffer; - serialized_packet_.encrypted_buffer = nullptr; - ClearSerializedPacket(&serialized_packet_); - } + void DeleteSerializedPacket() { serialized_packet_ = nullptr; } protected: QuicPacketCreatorTest() @@ -170,8 +161,7 @@ class QuicPacketCreatorTest : public QuicTestWithParam<TestParams> { Perspective::IS_CLIENT, connection_id_.length()), data_("foo"), - creator_(connection_id_, &client_framer_, &delegate_, &producer_), - serialized_packet_(creator_.NoPacket()) { + creator_(connection_id_, &client_framer_, &delegate_, &producer_) { EXPECT_CALL(delegate_, GetPacketBuffer()).WillRepeatedly(Return(nullptr)); creator_.SetEncrypter(ENCRYPTION_INITIAL, std::make_unique<NullEncrypter>( Perspective::IS_CLIENT)); @@ -205,10 +195,7 @@ class QuicPacketCreatorTest : public QuicTestWithParam<TestParams> { } } - ~QuicPacketCreatorTest() override { - delete[] serialized_packet_.encrypted_buffer; - ClearSerializedPacket(&serialized_packet_); - } + ~QuicPacketCreatorTest() override {} SerializedPacket SerializeAllFrames(const QuicFrames& frames) { SerializedPacket packet = QuicPacketCreatorPeer::SerializeAllFrames( @@ -282,7 +269,7 @@ class QuicPacketCreatorTest : public QuicTestWithParam<TestParams> { n * 2; } - static const QuicStreamOffset kOffset = 0u; + static constexpr QuicStreamOffset kOffset = 0u; char buffer_[kMaxOutgoingPacketSize]; QuicConnectionId connection_id_; @@ -294,7 +281,7 @@ class QuicPacketCreatorTest : public QuicTestWithParam<TestParams> { std::string data_; struct iovec iov_; TestPacketCreator creator_; - SerializedPacket serialized_packet_; + std::unique_ptr<SerializedPacket> serialized_packet_; SimpleDataProducer producer_; SimpleBufferAllocator allocator_; }; @@ -351,12 +338,12 @@ TEST_P(QuicPacketCreatorTest, SerializeFrames) { } TEST_P(QuicPacketCreatorTest, SerializeConnectionClose) { - QuicConnectionCloseFrame frame(creator_.transport_version(), QUIC_NO_ERROR, - "error", - /*transport_close_frame_type=*/0); + QuicConnectionCloseFrame* frame = new QuicConnectionCloseFrame( + creator_.transport_version(), QUIC_NO_ERROR, "error", + /*transport_close_frame_type=*/0); QuicFrames frames; - frames.push_back(QuicFrame(&frame)); + frames.push_back(QuicFrame(frame)); SerializedPacket serialized = SerializeAllFrames(frames); EXPECT_EQ(ENCRYPTION_INITIAL, serialized.encryption_level); ASSERT_EQ(QuicPacketNumber(1u), serialized.packet_number); @@ -486,7 +473,7 @@ TEST_P(QuicPacketCreatorTest, StreamFrameConsumption) { EXPECT_CALL(delegate_, OnSerializedPacket(_)) .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket)); creator_.FlushCurrentPacket(); - ASSERT_TRUE(serialized_packet_.encrypted_buffer); + ASSERT_TRUE(serialized_packet_->encrypted_buffer); DeleteSerializedPacket(); } } @@ -534,7 +521,7 @@ TEST_P(QuicPacketCreatorTest, CryptoStreamFramePacketPadding) { EXPECT_LT(0u, bytes_consumed); } creator_.FlushCurrentPacket(); - ASSERT_TRUE(serialized_packet_.encrypted_buffer); + ASSERT_TRUE(serialized_packet_->encrypted_buffer); // If there is not enough space in the packet to fit a padding frame // (1 byte) and to expand the stream frame (another 2 bytes) the packet // will not be padded. @@ -543,9 +530,9 @@ TEST_P(QuicPacketCreatorTest, CryptoStreamFramePacketPadding) { !QuicVersionUsesCryptoFrames(client_framer_.transport_version())) || client_framer_.version().CanSendCoalescedPackets()) { EXPECT_EQ(kDefaultMaxPacketSize - bytes_free, - serialized_packet_.encrypted_length); + serialized_packet_->encrypted_length); } else { - EXPECT_EQ(kDefaultMaxPacketSize, serialized_packet_.encrypted_length); + EXPECT_EQ(kDefaultMaxPacketSize, serialized_packet_->encrypted_length); } DeleteSerializedPacket(); } @@ -575,12 +562,12 @@ TEST_P(QuicPacketCreatorTest, NonCryptoStreamFramePacketNonPadding) { size_t bytes_consumed = frame.stream_frame.data_length; EXPECT_LT(0u, bytes_consumed); creator_.FlushCurrentPacket(); - ASSERT_TRUE(serialized_packet_.encrypted_buffer); + ASSERT_TRUE(serialized_packet_->encrypted_buffer); if (bytes_free > 0) { EXPECT_EQ(kDefaultMaxPacketSize - bytes_free, - serialized_packet_.encrypted_length); + serialized_packet_->encrypted_length); } else { - EXPECT_EQ(kDefaultMaxPacketSize, serialized_packet_.encrypted_length); + EXPECT_EQ(kDefaultMaxPacketSize, serialized_packet_->encrypted_length); } DeleteSerializedPacket(); } @@ -948,7 +935,7 @@ TEST_P(QuicPacketCreatorTest, SerializeConnectivityProbingPacket) { creator_.set_encryption_level(level); - OwningSerializedPacketPointer encrypted; + std::unique_ptr<SerializedPacket> encrypted; if (VersionHasIetfQuicFrames(creator_.transport_version())) { QuicPathFrameBuffer payload = { {0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xfe}}; @@ -991,7 +978,7 @@ TEST_P(QuicPacketCreatorTest, SerializePathChallengeProbePacket) { creator_.set_encryption_level(level); - OwningSerializedPacketPointer encrypted( + std::unique_ptr<SerializedPacket> encrypted( creator_.SerializePathChallengeConnectivityProbingPacket(&payload)); { InSequence s; @@ -1024,7 +1011,7 @@ TEST_P(QuicPacketCreatorTest, SerializePathResponseProbePacket1PayloadPadded) { QuicCircularDeque<QuicPathFrameBuffer> payloads; payloads.push_back(payload0); - OwningSerializedPacketPointer encrypted( + std::unique_ptr<SerializedPacket> encrypted( creator_.SerializePathResponseConnectivityProbingPacket(payloads, true)); { @@ -1058,7 +1045,7 @@ TEST_P(QuicPacketCreatorTest, QuicCircularDeque<QuicPathFrameBuffer> payloads; payloads.push_back(payload0); - OwningSerializedPacketPointer encrypted( + std::unique_ptr<SerializedPacket> encrypted( creator_.SerializePathResponseConnectivityProbingPacket(payloads, false)); { @@ -1093,7 +1080,7 @@ TEST_P(QuicPacketCreatorTest, SerializePathResponseProbePacket2PayloadsPadded) { payloads.push_back(payload0); payloads.push_back(payload1); - OwningSerializedPacketPointer encrypted( + std::unique_ptr<SerializedPacket> encrypted( creator_.SerializePathResponseConnectivityProbingPacket(payloads, true)); { @@ -1130,7 +1117,7 @@ TEST_P(QuicPacketCreatorTest, payloads.push_back(payload0); payloads.push_back(payload1); - OwningSerializedPacketPointer encrypted( + std::unique_ptr<SerializedPacket> encrypted( creator_.SerializePathResponseConnectivityProbingPacket(payloads, false)); { @@ -1168,7 +1155,7 @@ TEST_P(QuicPacketCreatorTest, SerializePathResponseProbePacket3PayloadsPadded) { payloads.push_back(payload1); payloads.push_back(payload2); - OwningSerializedPacketPointer encrypted( + std::unique_ptr<SerializedPacket> encrypted( creator_.SerializePathResponseConnectivityProbingPacket(payloads, true)); { @@ -1208,7 +1195,7 @@ TEST_P(QuicPacketCreatorTest, payloads.push_back(payload1); payloads.push_back(payload2); - OwningSerializedPacketPointer encrypted( + std::unique_ptr<SerializedPacket> encrypted( creator_.SerializePathResponseConnectivityProbingPacket(payloads, false)); InSequence s; @@ -1361,7 +1348,6 @@ TEST_P(QuicPacketCreatorTest, SerializeFrame) { } ProcessPacket(serialized); EXPECT_EQ(GetParam().version_serialization, header.version_flag); - DeleteFrames(&frames_); } TEST_P(QuicPacketCreatorTest, SerializeFrameShortData) { @@ -1402,7 +1388,6 @@ TEST_P(QuicPacketCreatorTest, SerializeFrameShortData) { } ProcessPacket(serialized); EXPECT_EQ(GetParam().version_serialization, header.version_flag); - DeleteFrames(&frames_); } TEST_P(QuicPacketCreatorTest, ConsumeDataLargerThanOneStreamFrame) { @@ -1488,13 +1473,14 @@ TEST_P(QuicPacketCreatorTest, AddFrameAndFlush) { EXPECT_FALSE(creator_.AddFrame(QuicFrame(&ack_frame), NOT_RETRANSMISSION)); // Ensure the packet is successfully created. - ASSERT_TRUE(serialized_packet_.encrypted_buffer); - ASSERT_FALSE(serialized_packet_.retransmittable_frames.empty()); - const QuicFrames& retransmittable = serialized_packet_.retransmittable_frames; + ASSERT_TRUE(serialized_packet_->encrypted_buffer); + ASSERT_FALSE(serialized_packet_->retransmittable_frames.empty()); + const QuicFrames& retransmittable = + serialized_packet_->retransmittable_frames; ASSERT_EQ(1u, retransmittable.size()); EXPECT_EQ(STREAM_FRAME, retransmittable[0].type); - EXPECT_TRUE(serialized_packet_.has_ack); - EXPECT_EQ(QuicPacketNumber(10u), serialized_packet_.largest_acked); + EXPECT_TRUE(serialized_packet_->has_ack); + EXPECT_EQ(QuicPacketNumber(10u), serialized_packet_->largest_acked); DeleteSerializedPacket(); EXPECT_FALSE(creator_.HasPendingFrames()); @@ -1533,9 +1519,10 @@ TEST_P(QuicPacketCreatorTest, SerializeAndSendStreamFrame) { EXPECT_EQ(4u, num_bytes_consumed); // Ensure the packet is successfully created. - ASSERT_TRUE(serialized_packet_.encrypted_buffer); - ASSERT_FALSE(serialized_packet_.retransmittable_frames.empty()); - const QuicFrames& retransmittable = serialized_packet_.retransmittable_frames; + ASSERT_TRUE(serialized_packet_->encrypted_buffer); + ASSERT_FALSE(serialized_packet_->retransmittable_frames.empty()); + const QuicFrames& retransmittable = + serialized_packet_->retransmittable_frames; ASSERT_EQ(1u, retransmittable.size()); EXPECT_EQ(STREAM_FRAME, retransmittable[0].type); DeleteSerializedPacket(); @@ -1565,8 +1552,8 @@ TEST_P(QuicPacketCreatorTest, SerializeStreamFrameWithPadding) { EXPECT_EQ(1u, num_bytes_consumed); // Check that a packet is created. - ASSERT_TRUE(serialized_packet_.encrypted_buffer); - ASSERT_FALSE(serialized_packet_.retransmittable_frames.empty()); + ASSERT_TRUE(serialized_packet_->encrypted_buffer); + ASSERT_FALSE(serialized_packet_->retransmittable_frames.empty()); { InSequence s; EXPECT_CALL(framer_visitor_, OnPacket()); @@ -1580,7 +1567,7 @@ TEST_P(QuicPacketCreatorTest, SerializeStreamFrameWithPadding) { } EXPECT_CALL(framer_visitor_, OnPacketComplete()); } - ProcessPacket(serialized_packet_); + ProcessPacket(*serialized_packet_); } TEST_P(QuicPacketCreatorTest, AddUnencryptedStreamDataClosesConnection) { @@ -1669,7 +1656,7 @@ TEST_P(QuicPacketCreatorTest, PendingPadding) { EXPECT_CALL(framer_visitor_, OnPacketComplete()); } // Packet only contains padding. - ProcessPacket(serialized_packet_); + ProcessPacket(*serialized_packet_); } EXPECT_EQ(0u, creator_.pending_padding_bytes()); } @@ -1751,9 +1738,8 @@ TEST_P(QuicPacketCreatorTest, FlushWithExternalBuffer) { /*needs_full_padding=*/true, NOT_RETRANSMISSION, &frame)); EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke([expected_buffer](SerializedPacket* serialized_packet) { - EXPECT_EQ(expected_buffer, serialized_packet->encrypted_buffer); - ClearSerializedPacket(serialized_packet); + .WillOnce(Invoke([expected_buffer](SerializedPacket serialized_packet) { + EXPECT_EQ(expected_buffer, serialized_packet.encrypted_buffer); })); creator_.FlushCurrentPacket(); } @@ -1775,6 +1761,9 @@ TEST_P(QuicPacketCreatorTest, AddMessageFrame) { if (!VersionSupportsMessageFrames(client_framer_.transport_version())) { return; } + if (client_framer_.version().UsesTls()) { + creator_.SetMaxDatagramFrameSize(kMaxAcceptedDatagramFrameSize); + } creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); EXPECT_CALL(delegate_, OnSerializedPacket(_)) .Times(3) @@ -1827,6 +1816,9 @@ TEST_P(QuicPacketCreatorTest, MessageFrameConsumption) { if (!VersionSupportsMessageFrames(client_framer_.transport_version())) { return; } + if (client_framer_.version().UsesTls()) { + creator_.SetMaxDatagramFrameSize(kMaxAcceptedDatagramFrameSize); + } std::string message_data(kDefaultMaxPacketSize, 'a'); quiche::QuicheStringPiece message_buffer(message_data); QuicMemSliceStorage storage(nullptr, 0, nullptr, 0); @@ -1862,27 +1854,99 @@ TEST_P(QuicPacketCreatorTest, MessageFrameConsumption) { EXPECT_CALL(delegate_, OnSerializedPacket(_)) .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket)); creator_.FlushCurrentPacket(); - ASSERT_TRUE(serialized_packet_.encrypted_buffer); + ASSERT_TRUE(serialized_packet_->encrypted_buffer); DeleteSerializedPacket(); } } } -// Regression test for bugfix of GetPacketHeaderSize. TEST_P(QuicPacketCreatorTest, GetGuaranteedLargestMessagePayload) { - QuicTransportVersion version = creator_.transport_version(); - if (!VersionSupportsMessageFrames(version)) { + ParsedQuicVersion version = GetParam().version; + if (!version.SupportsMessageFrames()) { return; } + if (version.UsesTls()) { + creator_.SetMaxDatagramFrameSize(kMaxAcceptedDatagramFrameSize); + } QuicPacketLength expected_largest_payload = 1319; - if (QuicVersionHasLongHeaderLengths(version)) { + if (version.HasLongHeaderLengths()) { expected_largest_payload -= 2; } - if (GetParam().version.HasLengthPrefixedConnectionIds()) { + if (version.HasLengthPrefixedConnectionIds()) { expected_largest_payload -= 1; } EXPECT_EQ(expected_largest_payload, creator_.GetGuaranteedLargestMessagePayload()); + EXPECT_TRUE(creator_.HasRoomForMessageFrame( + creator_.GetGuaranteedLargestMessagePayload())); + + // Now test whether SetMaxDatagramFrameSize works. + creator_.SetMaxDatagramFrameSize(expected_largest_payload + 1 + + kQuicFrameTypeSize); + EXPECT_EQ(expected_largest_payload, + creator_.GetGuaranteedLargestMessagePayload()); + EXPECT_TRUE(creator_.HasRoomForMessageFrame( + creator_.GetGuaranteedLargestMessagePayload())); + + creator_.SetMaxDatagramFrameSize(expected_largest_payload + + kQuicFrameTypeSize); + EXPECT_EQ(expected_largest_payload, + creator_.GetGuaranteedLargestMessagePayload()); + EXPECT_TRUE(creator_.HasRoomForMessageFrame( + creator_.GetGuaranteedLargestMessagePayload())); + + creator_.SetMaxDatagramFrameSize(expected_largest_payload - 1 + + kQuicFrameTypeSize); + EXPECT_EQ(expected_largest_payload - 1, + creator_.GetGuaranteedLargestMessagePayload()); + EXPECT_TRUE(creator_.HasRoomForMessageFrame( + creator_.GetGuaranteedLargestMessagePayload())); + + constexpr QuicPacketLength kFrameSizeLimit = 1000; + constexpr QuicPacketLength kPayloadSizeLimit = + kFrameSizeLimit - kQuicFrameTypeSize; + creator_.SetMaxDatagramFrameSize(kFrameSizeLimit); + EXPECT_EQ(creator_.GetGuaranteedLargestMessagePayload(), kPayloadSizeLimit); + EXPECT_TRUE(creator_.HasRoomForMessageFrame(kPayloadSizeLimit)); + EXPECT_FALSE(creator_.HasRoomForMessageFrame(kPayloadSizeLimit + 1)); +} + +TEST_P(QuicPacketCreatorTest, GetCurrentLargestMessagePayload) { + ParsedQuicVersion version = GetParam().version; + if (!version.SupportsMessageFrames()) { + return; + } + if (version.UsesTls()) { + creator_.SetMaxDatagramFrameSize(kMaxAcceptedDatagramFrameSize); + } + QuicPacketLength expected_largest_payload = 1319; + if (version.SendsVariableLengthPacketNumberInLongHeader()) { + expected_largest_payload += 3; + } + if (version.HasLongHeaderLengths()) { + expected_largest_payload -= 2; + } + if (version.HasLengthPrefixedConnectionIds()) { + expected_largest_payload -= 1; + } + EXPECT_EQ(expected_largest_payload, + creator_.GetCurrentLargestMessagePayload()); + + // Now test whether SetMaxDatagramFrameSize works. + creator_.SetMaxDatagramFrameSize(expected_largest_payload + 1 + + kQuicFrameTypeSize); + EXPECT_EQ(expected_largest_payload, + creator_.GetCurrentLargestMessagePayload()); + + creator_.SetMaxDatagramFrameSize(expected_largest_payload + + kQuicFrameTypeSize); + EXPECT_EQ(expected_largest_payload, + creator_.GetCurrentLargestMessagePayload()); + + creator_.SetMaxDatagramFrameSize(expected_largest_payload - 1 + + kQuicFrameTypeSize); + EXPECT_EQ(expected_largest_payload - 1, + creator_.GetCurrentLargestMessagePayload()); } TEST_P(QuicPacketCreatorTest, PacketTransmissionType) { @@ -1906,18 +1970,18 @@ TEST_P(QuicPacketCreatorTest, PacketTransmissionType) { .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket)); EXPECT_TRUE(creator_.AddFrame(ack_frame, LOSS_RETRANSMISSION)); - ASSERT_FALSE(serialized_packet_.encrypted_buffer); + ASSERT_EQ(serialized_packet_, nullptr); EXPECT_TRUE(creator_.AddFrame(stream_frame, RTO_RETRANSMISSION)); - ASSERT_FALSE(serialized_packet_.encrypted_buffer); + ASSERT_EQ(serialized_packet_, nullptr); EXPECT_TRUE(creator_.AddFrame(padding_frame, TLP_RETRANSMISSION)); creator_.FlushCurrentPacket(); - ASSERT_TRUE(serialized_packet_.encrypted_buffer); + ASSERT_TRUE(serialized_packet_->encrypted_buffer); // The last retransmittable frame on packet is a stream frame, the packet's // transmission type should be the same as the stream frame's. - EXPECT_EQ(serialized_packet_.transmission_type, RTO_RETRANSMISSION); + EXPECT_EQ(serialized_packet_->transmission_type, RTO_RETRANSMISSION); DeleteSerializedPacket(); } @@ -1972,7 +2036,6 @@ TEST_P(QuicPacketCreatorTest, RetryToken) { quiche::test::CompareCharArraysWithHexError( "retry token", header.retry_token.data(), header.retry_token.length(), retry_token_bytes, sizeof(retry_token_bytes)); - DeleteFrames(&frames_); } TEST_P(QuicPacketCreatorTest, GetConnectionId) { @@ -2068,7 +2131,7 @@ TEST_P(QuicPacketCreatorTest, CoalesceStreamFrames) { EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); EXPECT_CALL(framer_visitor_, OnPacketComplete()); - ProcessPacket(serialized_packet_); + ProcessPacket(*serialized_packet_); } TEST_P(QuicPacketCreatorTest, SaveNonRetransmittableFrames) { @@ -2186,6 +2249,9 @@ TEST_P(QuicPacketCreatorTest, SoftMaxPacketLength) { // Same for message frame. if (VersionSupportsMessageFrames(client_framer_.transport_version())) { creator_.SetSoftMaxPacketLength(overhead); + if (client_framer_.version().UsesTls()) { + creator_.SetMaxDatagramFrameSize(kMaxAcceptedDatagramFrameSize); + } // Verify GetCurrentLargestMessagePayload is based on the actual // max_packet_length. EXPECT_LT(1u, creator_.GetCurrentLargestMessagePayload()); @@ -2237,13 +2303,20 @@ class MockDelegate : public QuicPacketCreator::DelegateInterface { MockDelegate& operator=(const MockDelegate&) = delete; ~MockDelegate() override {} - MOCK_METHOD2(ShouldGeneratePacket, - bool(HasRetransmittableData retransmittable, - IsHandshake handshake)); - MOCK_METHOD0(MaybeBundleAckOpportunistically, const QuicFrames()); - MOCK_METHOD0(GetPacketBuffer, char*()); - MOCK_METHOD1(OnSerializedPacket, void(SerializedPacket* packet)); - MOCK_METHOD2(OnUnrecoverableError, void(QuicErrorCode, const std::string&)); + MOCK_METHOD(bool, + ShouldGeneratePacket, + (HasRetransmittableData retransmittable, IsHandshake handshake), + (override)); + MOCK_METHOD(const QuicFrames, + MaybeBundleAckOpportunistically, + (), + (override)); + MOCK_METHOD(char*, GetPacketBuffer, (), (override)); + MOCK_METHOD(void, OnSerializedPacket, (SerializedPacket), (override)); + MOCK_METHOD(void, + OnUnrecoverableError, + (QuicErrorCode, const std::string&), + (override)); void SetCanWriteAnything() { EXPECT_CALL(*this, ShouldGeneratePacket(_, _)).WillRepeatedly(Return(true)); @@ -2407,18 +2480,13 @@ class QuicPacketCreatorMultiplePacketsTest : public QuicTest { creator_.AttachPacketFlusher(); } - ~QuicPacketCreatorMultiplePacketsTest() override { - for (SerializedPacket& packet : packets_) { - delete[] packet.encrypted_buffer; - ClearSerializedPacket(&packet); - } - } + ~QuicPacketCreatorMultiplePacketsTest() override {} - void SavePacket(SerializedPacket* packet) { - packet->encrypted_buffer = CopyBuffer(*packet); - packets_.push_back(*packet); - packet->encrypted_buffer = nullptr; - packet->retransmittable_frames.clear(); + void SavePacket(SerializedPacket packet) { + DCHECK(packet.release_encrypted_buffer == nullptr); + packet.encrypted_buffer = CopyBuffer(packet); + packet.release_encrypted_buffer = [](const char* p) { delete[] p; }; + packets_.push_back(std::move(packet)); } protected: @@ -2903,7 +2971,7 @@ TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeDataFastPath) { contents.num_stream_frames = 1; CheckPacketContains(contents, 0); EXPECT_FALSE(packets_.empty()); - SerializedPacket packet = packets_.back(); + SerializedPacket& packet = packets_.back(); EXPECT_TRUE(!packet.retransmittable_frames.empty()); EXPECT_EQ(LOSS_RETRANSMISSION, packet.transmission_type); EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type); @@ -2933,7 +3001,7 @@ TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeDataLarge) { contents.num_stream_frames = 1; CheckPacketContains(contents, 0); EXPECT_FALSE(packets_.empty()); - SerializedPacket packet = packets_.back(); + SerializedPacket& packet = packets_.back(); EXPECT_TRUE(!packet.retransmittable_frames.empty()); EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type); const QuicStreamFrame& stream_frame = @@ -2976,7 +3044,7 @@ TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeDataLargeSendAckFalse) { EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); EXPECT_FALSE(packets_.empty()); - SerializedPacket packet = packets_.back(); + SerializedPacket& packet = packets_.back(); EXPECT_TRUE(!packet.retransmittable_frames.empty()); EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type); const QuicStreamFrame& stream_frame = @@ -3005,7 +3073,7 @@ TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeDataLargeSendAckTrue) { EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); EXPECT_FALSE(packets_.empty()); - SerializedPacket packet = packets_.back(); + SerializedPacket& packet = packets_.back(); EXPECT_TRUE(!packet.retransmittable_frames.empty()); EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type); const QuicStreamFrame& stream_frame = @@ -3352,7 +3420,7 @@ TEST_F(QuicPacketCreatorMultiplePacketsTest, GenerateConnectivityProbingPacket) { delegate_.SetCanWriteAnything(); - OwningSerializedPacketPointer probing_packet; + std::unique_ptr<SerializedPacket> probing_packet; if (VersionHasIetfQuicFrames(framer_.transport_version())) { QuicPathFrameBuffer payload = { {0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xfe}}; @@ -3667,6 +3735,9 @@ TEST_F(QuicPacketCreatorMultiplePacketsTest, AddMessageFrame) { if (!VersionSupportsMessageFrames(framer_.transport_version())) { return; } + if (framer_.version().UsesTls()) { + creator_.SetMaxDatagramFrameSize(kMaxAcceptedDatagramFrameSize); + } quic::QuicMemSliceStorage storage(nullptr, 0, nullptr, 0); delegate_.SetCanWriteAnything(); EXPECT_CALL(delegate_, OnSerializedPacket(_)) diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer.h b/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer.h index bd10523e16a..ab29e15aa88 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer.h @@ -28,8 +28,10 @@ struct QUIC_EXPORT_PRIVATE PerPacketOptions { // would not forget to override it. virtual std::unique_ptr<PerPacketOptions> Clone() const = 0; - // Specifies release time delay for this packet. + // Specifies ideal release time delay for this packet. QuicTime::Delta release_time_delay = QuicTime::Delta::Zero(); + // Whether it is allowed to send this packet without |release_time_delay|. + bool allow_burst = false; }; // An interface between writers and the entity managing the diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packets.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packets.cc index 4123c27f94c..69575b99935 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packets.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packets.cc @@ -465,15 +465,8 @@ SerializedPacket::SerializedPacket(QuicPacketNumber packet_number, transmission_type(NOT_RETRANSMISSION), has_ack_frame_copy(false) {} -SerializedPacket::SerializedPacket(const SerializedPacket& other) = default; - -SerializedPacket& SerializedPacket::operator=(const SerializedPacket& other) = - default; - SerializedPacket::SerializedPacket(SerializedPacket&& other) - : encrypted_buffer(other.encrypted_buffer), - encrypted_length(other.encrypted_length), - has_crypto_handshake(other.has_crypto_handshake), + : has_crypto_handshake(other.has_crypto_handshake), num_padding_bytes(other.num_padding_bytes), packet_number(other.packet_number), packet_number_length(other.packet_number_length), @@ -483,23 +476,58 @@ SerializedPacket::SerializedPacket(SerializedPacket&& other) transmission_type(other.transmission_type), largest_acked(other.largest_acked), has_ack_frame_copy(other.has_ack_frame_copy) { - retransmittable_frames.swap(other.retransmittable_frames); - nonretransmittable_frames.swap(other.nonretransmittable_frames); + if (this != &other) { + if (release_encrypted_buffer && encrypted_buffer != nullptr) { + release_encrypted_buffer(encrypted_buffer); + } + encrypted_buffer = other.encrypted_buffer; + encrypted_length = other.encrypted_length; + release_encrypted_buffer = std::move(other.release_encrypted_buffer); + other.release_encrypted_buffer = nullptr; + + retransmittable_frames.swap(other.retransmittable_frames); + nonretransmittable_frames.swap(other.nonretransmittable_frames); + } } -SerializedPacket::~SerializedPacket() {} +SerializedPacket::~SerializedPacket() { + if (release_encrypted_buffer && encrypted_buffer != nullptr) { + release_encrypted_buffer(encrypted_buffer); + } + + if (!retransmittable_frames.empty()) { + DeleteFrames(&retransmittable_frames); + } + for (auto& frame : nonretransmittable_frames) { + if (!has_ack_frame_copy && frame.type == ACK_FRAME) { + // Do not delete ack frame if the packet does not own a copy of it. + continue; + } + DeleteFrame(&frame); + } +} SerializedPacket* CopySerializedPacket(const SerializedPacket& serialized, QuicBufferAllocator* allocator, bool copy_buffer) { - SerializedPacket* copy = new SerializedPacket(serialized); + SerializedPacket* copy = new SerializedPacket( + serialized.packet_number, serialized.packet_number_length, + serialized.encrypted_buffer, serialized.encrypted_length, + serialized.has_ack, serialized.has_stop_waiting); + copy->has_crypto_handshake = serialized.has_crypto_handshake; + copy->num_padding_bytes = serialized.num_padding_bytes; + copy->encryption_level = serialized.encryption_level; + copy->transmission_type = serialized.transmission_type; + copy->largest_acked = serialized.largest_acked; + if (copy_buffer) { copy->encrypted_buffer = CopyBuffer(serialized); + copy->release_encrypted_buffer = [](const char* p) { delete[] p; }; } // Copy underlying frames. copy->retransmittable_frames = CopyQuicFrames(allocator, serialized.retransmittable_frames); - copy->nonretransmittable_frames.clear(); + DCHECK(copy->nonretransmittable_frames.empty()); for (const auto& frame : serialized.nonretransmittable_frames) { if (frame.type == ACK_FRAME) { copy->has_ack_frame_copy = true; @@ -509,27 +537,8 @@ SerializedPacket* CopySerializedPacket(const SerializedPacket& serialized, return copy; } -void ClearSerializedPacket(SerializedPacket* serialized_packet) { - if (!serialized_packet->retransmittable_frames.empty()) { - DeleteFrames(&serialized_packet->retransmittable_frames); - } - for (auto& frame : serialized_packet->nonretransmittable_frames) { - if (!serialized_packet->has_ack_frame_copy && frame.type == ACK_FRAME) { - // Do not delete ack frame if the packet does not own a copy of it. - continue; - } - DeleteFrame(&frame); - } - serialized_packet->nonretransmittable_frames.clear(); - serialized_packet->encrypted_buffer = nullptr; - serialized_packet->encrypted_length = 0; - serialized_packet->largest_acked.Clear(); -} - char* CopyBuffer(const SerializedPacket& packet) { - char* dst_buffer = new char[packet.encrypted_length]; - memcpy(dst_buffer, packet.encrypted_buffer, packet.encrypted_length); - return dst_buffer; + return CopyBuffer(packet.encrypted_buffer, packet.encrypted_length); } char* CopyBuffer(const char* encrypted_buffer, diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packets.h b/chromium/net/third_party/quiche/src/quic/core/quic_packets.h index e8e1931b975..04522e8538b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packets.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packets.h @@ -357,6 +357,13 @@ class QUIC_EXPORT_PRIVATE QuicReceivedPacket : public QuicEncryptedPacket { bool owns_header_buffer_; }; +// SerializedPacket contains information of a serialized(encrypted) packet. +// +// WARNING: +// +// If you add a member field to this class, please make sure it is properly +// copied in |CopySerializedPacket|. +// struct QUIC_EXPORT_PRIVATE SerializedPacket { SerializedPacket(QuicPacketNumber packet_number, QuicPacketNumberLength packet_number_length, @@ -364,14 +371,20 @@ struct QUIC_EXPORT_PRIVATE SerializedPacket { QuicPacketLength encrypted_length, bool has_ack, bool has_stop_waiting); - SerializedPacket(const SerializedPacket& other); - SerializedPacket& operator=(const SerializedPacket& other); + + // Copy constructor & assignment are deleted. Use |CopySerializedPacket| to + // make a copy. + SerializedPacket(const SerializedPacket& other) = delete; + SerializedPacket& operator=(const SerializedPacket& other) = delete; SerializedPacket(SerializedPacket&& other); ~SerializedPacket(); - // Not owned. + // Not owned if |release_encrypted_buffer| is nullptr. Otherwise it is + // released by |release_encrypted_buffer| on destruction. const char* encrypted_buffer; QuicPacketLength encrypted_length; + std::function<void(const char*)> release_encrypted_buffer; + QuicFrames retransmittable_frames; QuicFrames nonretransmittable_frames; IsHandshake has_crypto_handshake; @@ -401,10 +414,6 @@ QUIC_EXPORT_PRIVATE SerializedPacket* CopySerializedPacket( QuicBufferAllocator* allocator, bool copy_buffer); -// Deletes and clears all the frames and the packet from serialized packet. -QUIC_EXPORT_PRIVATE void ClearSerializedPacket( - SerializedPacket* serialized_packet); - // Allocates a new char[] of size |packet.encrypted_length| and copies in // |packet.encrypted_buffer|. QUIC_EXPORT_PRIVATE char* CopyBuffer(const SerializedPacket& packet); @@ -413,21 +422,6 @@ QUIC_EXPORT_PRIVATE char* CopyBuffer(const SerializedPacket& packet); QUIC_EXPORT_PRIVATE char* CopyBuffer(const char* encrypted_buffer, QuicPacketLength encrypted_length); -struct QUIC_EXPORT_PRIVATE SerializedPacketDeleter { - void operator()(SerializedPacket* packet) { - if (packet->encrypted_buffer != nullptr) { - delete[] packet->encrypted_buffer; - } - delete packet; - } -}; - -// On destruction, OwningSerializedPacketPointer deletes a packet's (on-heap) -// encrypted_buffer before deleting the (also on-heap) packet itself. -// TODO(wub): Maybe delete retransmittable_frames too? -typedef std::unique_ptr<SerializedPacket, SerializedPacketDeleter> - OwningSerializedPacketPointer; - // Context for an incoming packet. struct QUIC_EXPORT_PRIVATE QuicPerPacketContext { virtual ~QuicPerPacketContext() {} diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packets_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packets_test.cc index 1ccaabc0a32..b2bccbeeb72 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packets_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packets_test.cc @@ -106,10 +106,6 @@ TEST_F(QuicPacketsTest, CopySerializedPacket) { CopySerializedPacket(packet, &allocator, /*copy_buffer=*/false)); EXPECT_EQ(packet.encrypted_buffer, copy2->encrypted_buffer); EXPECT_EQ(1000u, copy2->encrypted_length); - ClearSerializedPacket(&packet); - delete[] copy->encrypted_buffer; - ClearSerializedPacket(copy.get()); - ClearSerializedPacket(copy2.get()); } } // namespace diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.cc index 0de1dadf17c..92401b0db72 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.cc @@ -77,7 +77,7 @@ QuicSentPacketManager::QuicSentPacketManager( debug_delegate_(nullptr), network_change_visitor_(nullptr), initial_congestion_window_(kInitialCongestionWindow), - loss_algorithm_(GetInitialLossAlgorithm()), + loss_algorithm_(&uber_loss_algorithm_), consecutive_rto_count_(0), consecutive_tlp_count_(0), consecutive_crypto_retransmission_count_(0), @@ -98,7 +98,7 @@ QuicSentPacketManager::QuicSentPacketManager( QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs)), rtt_updated_(false), acked_packets_iter_(last_ack_frame_.packets.rbegin()), - pto_enabled_(false), + pto_enabled_(GetQuicReloadableFlag(quic_default_on_pto)), max_probe_packets_per_pto_(2), consecutive_pto_count_(0), handshake_mode_disabled_(false), @@ -112,10 +112,13 @@ QuicSentPacketManager::QuicSentPacketManager( first_pto_srtt_multiplier_(0), use_standard_deviation_for_pto_(false) { SetSendAlgorithm(congestion_control_type); -} - -LossDetectionInterface* QuicSentPacketManager::GetInitialLossAlgorithm() { - return &uber_loss_algorithm_; + if (pto_enabled_) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_default_on_pto, 1, 2); + // TODO(fayang): change the default values when deprecating + // quic_default_on_pto. + first_pto_srtt_multiplier_ = 1.5; + pto_rttvar_multiplier_ = 2; + } } QuicSentPacketManager::~QuicSentPacketManager() {} @@ -191,21 +194,13 @@ void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) { QUIC_CODE_COUNT(two_aggressive_ptos); num_tlp_timeout_ptos_ = 2; } - if (GetQuicReloadableFlag(quic_arm_pto_with_earliest_sent_time)) { - if (config.HasClientSentConnectionOption(kPLE1, perspective) || - config.HasClientSentConnectionOption(kTLPR, perspective)) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_arm_pto_with_earliest_sent_time, 1, - 2); - first_pto_srtt_multiplier_ = 0.5; - } else if (config.HasClientSentConnectionOption(kPLE2, perspective)) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_arm_pto_with_earliest_sent_time, 2, - 2); - first_pto_srtt_multiplier_ = 1.5; - } + if (config.HasClientSentConnectionOption(kPLE1, perspective) || + config.HasClientSentConnectionOption(kTLPR, perspective)) { + first_pto_srtt_multiplier_ = 0.5; + } else if (config.HasClientSentConnectionOption(kPLE2, perspective)) { + first_pto_srtt_multiplier_ = 1.5; } - if (GetQuicReloadableFlag(quic_use_standard_deviation_for_pto) && - config.HasClientSentConnectionOption(kPSDA, perspective)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_use_standard_deviation_for_pto); + if (config.HasClientSentConnectionOption(kPSDA, perspective)) { use_standard_deviation_for_pto_ = true; rtt_stats_.EnableStandardDeviationCalculation(); } @@ -227,9 +222,6 @@ void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) { (GetQuicReloadableFlag(quic_default_to_bbr) && config.HasClientRequestedIndependentOption(kQBIC, perspective))) { SetSendAlgorithm(kCubicBytes); - } else if (GetQuicReloadableFlag(quic_enable_pcc3) && - config.HasClientRequestedIndependentOption(kTPCC, perspective)) { - SetSendAlgorithm(kPCC); } // Initial window. @@ -296,23 +288,25 @@ void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) { uber_loss_algorithm_.EnableAdaptiveReorderingThreshold(); uber_loss_algorithm_.EnableAdaptiveTimeThreshold(); } - if (GetQuicReloadableFlag( - quic_skip_packet_threshold_loss_detection_with_runt) && - config.HasClientRequestedIndependentOption(kRUNT, perspective)) { - QUIC_RELOADABLE_FLAG_COUNT_N( - quic_skip_packet_threshold_loss_detection_with_runt, 1, 2); + if (config.HasClientRequestedIndependentOption(kRUNT, perspective)) { uber_loss_algorithm_.DisablePacketThresholdForRuntPackets(); } if (config.HasClientSentConnectionOption(kCONH, perspective)) { conservative_handshake_retransmits_ = true; } send_algorithm_->SetFromConfig(config, perspective); + loss_algorithm_->SetFromConfig(config, perspective); if (network_change_visitor_ != nullptr) { network_change_visitor_->OnCongestionChange(); } } +void QuicSentPacketManager::ApplyConnectionOptions( + const QuicTagVector& connection_options) { + send_algorithm_->ApplyConnectionOptions(connection_options); +} + void QuicSentPacketManager::ResumeConnectionState( const CachedNetworkParameters& cached_network_params, bool max_bandwidth_resumption) { @@ -345,8 +339,8 @@ void QuicSentPacketManager::AdjustNetworkParameters( send_algorithm_->AdjustNetworkParameters(params); if (debug_delegate_ != nullptr) { debug_delegate_->OnAdjustNetworkParameters( - bandwidth, rtt.IsZero() ? rtt_stats_.SmoothedOrInitialRtt() : rtt, - old_cwnd, send_algorithm_->GetCongestionWindow()); + bandwidth, rtt.IsZero() ? rtt_stats_.MinOrInitialRtt() : rtt, old_cwnd, + send_algorithm_->GetCongestionWindow()); } } @@ -862,8 +856,9 @@ void QuicSentPacketManager::MaybeSendProbePackets() { // Find out the packet number space to send probe packets. if (!GetEarliestPacketSentTimeForPto(&packet_number_space) .IsInitialized()) { - QUIC_BUG << "earlist_sent_time not initialized when trying to send PTO " - "retransmissions"; + QUIC_BUG_IF(unacked_packets_.perspective() == Perspective::IS_SERVER) + << "earlist_sent_time not initialized when trying to send PTO " + "retransmissions"; return; } } @@ -903,6 +898,12 @@ void QuicSentPacketManager::AdjustPendingTimerTransmissions() { } void QuicSentPacketManager::EnableIetfPtoAndLossDetection() { + if (pto_enabled_) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_default_on_pto, 2, 2); + // Disable handshake mode. + handshake_mode_disabled_ = true; + return; + } pto_enabled_ = true; handshake_mode_disabled_ = true; // Default to 1 packet per PTO and skip a packet number. Arm the 1st PTO with @@ -946,9 +947,17 @@ void QuicSentPacketManager::InvokeLossDetection(QuicTime time) { packets_acked_.back().packet_number); largest_newly_acked_ = packets_acked_.back().packet_number; } - loss_algorithm_->DetectLosses(unacked_packets_, time, rtt_stats_, - largest_newly_acked_, packets_acked_, - &packets_lost_); + LossDetectionInterface::DetectionStats detection_stats = + loss_algorithm_->DetectLosses(unacked_packets_, time, rtt_stats_, + largest_newly_acked_, packets_acked_, + &packets_lost_); + + if (detection_stats.sent_packets_max_sequence_reordering > + stats_->sent_packets_max_sequence_reordering) { + stats_->sent_packets_max_sequence_reordering = + detection_stats.sent_packets_max_sequence_reordering; + } + for (const LostPacket& packet : packets_lost_) { QuicTransmissionInfo* info = unacked_packets_.GetMutableTransmissionInfo(packet.packet_number); @@ -1085,8 +1094,12 @@ const QuicTime QuicSentPacketManager::GetRetransmissionTime() const { PacketNumberSpace packet_number_space = NUM_PACKET_NUMBER_SPACES; // earliest_right_edge is the earliest sent time of the last in flight // packet of all packet number spaces. - const QuicTime earliest_right_edge = + QuicTime earliest_right_edge = GetEarliestPacketSentTimeForPto(&packet_number_space); + if (!earliest_right_edge.IsInitialized()) { + // Arm PTO from now if there is no in flight packets. + earliest_right_edge = clock_->ApproximateNow(); + } if (first_pto_srtt_multiplier_ > 0 && packet_number_space == APPLICATION_DATA && consecutive_pto_count_ == 0) { @@ -1187,10 +1200,11 @@ const QuicTime::Delta QuicSentPacketManager::GetRetransmissionDelay() const { const QuicTime::Delta QuicSentPacketManager::GetProbeTimeoutDelay() const { DCHECK(pto_enabled_); if (rtt_stats_.smoothed_rtt().IsZero()) { - if (rtt_stats_.initial_rtt().IsZero()) { - return QuicTime::Delta::FromSeconds(1); - } - return 2 * rtt_stats_.initial_rtt(); + // Respect kMinHandshakeTimeoutMs to avoid a potential amplification attack. + QUIC_BUG_IF(rtt_stats_.initial_rtt().IsZero()); + return std::max(3 * rtt_stats_.initial_rtt(), + QuicTime::Delta::FromMilliseconds(kMinHandshakeTimeoutMs)) * + (1 << consecutive_pto_count_); } const QuicTime::Delta rtt_var = use_standard_deviation_for_pto_ ? rtt_stats_.GetStandardOrMeanDeviation() @@ -1411,9 +1425,12 @@ void QuicSentPacketManager::OnApplicationLimited() { } } -QuicTime QuicSentPacketManager::GetNextReleaseTime() const { - return using_pacing_ ? pacing_sender_.ideal_next_packet_send_time() - : QuicTime::Zero(); +NextReleaseTimeResult QuicSentPacketManager::GetNextReleaseTime() const { + if (!using_pacing_) { + return {QuicTime::Zero(), false}; + } + + return pacing_sender_.GetNextReleaseTime(); } void QuicSentPacketManager::SetInitialRtt(QuicTime::Delta rtt) { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h index 5f1de705bb3..371fa814537 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h @@ -120,6 +120,8 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { virtual void SetFromConfig(const QuicConfig& config); + void ApplyConnectionOptions(const QuicTagVector& connection_options); + // Pass the CachedNetworkParameters to the send algorithm. void ResumeConnectionState( const CachedNetworkParameters& cached_network_params, @@ -339,7 +341,7 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { unacked_packets_.SetSessionNotifier(session_notifier); } - QuicTime GetNextReleaseTime() const; + NextReleaseTimeResult GetNextReleaseTime() const; QuicPacketCount initial_congestion_window() const { return initial_congestion_window_; @@ -366,6 +368,10 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { return unacked_packets_; } + const UberLossAlgorithm* uber_loss_algorithm() const { + return &uber_loss_algorithm_; + } + // Sets the send algorithm to the given congestion control type and points the // pacing sender at |send_algorithm_|. Can be called any number of times. void SetSendAlgorithm(CongestionControlType congestion_control_type); @@ -490,9 +496,6 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { // Sets the initial RTT of the connection. void SetInitialRtt(QuicTime::Delta rtt); - // Should only be called from constructor. - LossDetectionInterface* GetInitialLossAlgorithm(); - // Called when handshake is confirmed to remove the retransmittable frames // from all packets of HANDSHAKE_DATA packet number space to ensure they don't // get retransmitted and will eventually be removed from unacked packets map. diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc index 98e6af0cfea..79fc798568b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc @@ -43,14 +43,17 @@ MATCHER(PacketNumberEq, "") { class MockDebugDelegate : public QuicSentPacketManager::DebugDelegate { public: - MOCK_METHOD2(OnSpuriousPacketRetransmission, - void(TransmissionType transmission_type, - QuicByteCount byte_size)); - MOCK_METHOD4(OnPacketLoss, - void(QuicPacketNumber lost_packet_number, - EncryptionLevel encryption_level, - TransmissionType transmission_type, - QuicTime detection_time)); + MOCK_METHOD(void, + OnSpuriousPacketRetransmission, + (TransmissionType transmission_type, QuicByteCount byte_size), + (override)); + MOCK_METHOD(void, + OnPacketLoss, + (QuicPacketNumber lost_packet_number, + EncryptionLevel encryption_level, + TransmissionType transmission_type, + QuicTime detection_time), + (override)); }; class QuicSentPacketManagerTest : public QuicTest { @@ -105,8 +108,6 @@ class QuicSentPacketManagerTest : public QuicTest { EXPECT_CALL(*send_algorithm_, GetCongestionControlType()) .WillRepeatedly(Return(kInitialCongestionControlType)); - EXPECT_CALL(*send_algorithm_, HasReliableBandwidthEstimate()) - .Times(AnyNumber()); EXPECT_CALL(*send_algorithm_, BandwidthEstimate()) .Times(AnyNumber()) .WillRepeatedly(Return(QuicBandwidth::Zero())); @@ -526,7 +527,6 @@ TEST_F(QuicSentPacketManagerTest, // Since 1 has been retransmitted, it has already been lost, and so the // send algorithm is not informed that it has been ACK'd. ExpectUpdatedRtt(1); - EXPECT_CALL(*send_algorithm_, RevertRetransmissionTimeout()); manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(), clock_.Now()); manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2)); @@ -622,6 +622,7 @@ TEST_F(QuicSentPacketManagerTest, RetransmitTwiceThenAckFirst) { EXPECT_EQ(1u, stats_.packets_spuriously_retransmitted); EXPECT_EQ(1u, stats_.packets_lost); EXPECT_LT(QuicTime::Delta::Zero(), stats_.total_loss_detection_time); + EXPECT_LE(1u, stats_.sent_packets_max_sequence_reordering); } TEST_F(QuicSentPacketManagerTest, AckOriginalTransmission) { @@ -826,6 +827,9 @@ TEST_F(QuicSentPacketManagerTest, RttZeroDelta) { } TEST_F(QuicSentPacketManagerTest, TailLossProbeTimeout) { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return; + } QuicSentPacketManagerPeer::SetMaxTailLossProbes(&manager_, 2); // Send 1 packet. @@ -886,6 +890,9 @@ TEST_F(QuicSentPacketManagerTest, TailLossProbeTimeout) { } TEST_F(QuicSentPacketManagerTest, TailLossProbeThenRTO) { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return; + } QuicSentPacketManagerPeer::SetMaxTailLossProbes(&manager_, 2); // Send 100 packets. @@ -1178,6 +1185,9 @@ TEST_F(QuicSentPacketManagerTest, } TEST_F(QuicSentPacketManagerTest, RetransmissionTimeout) { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return; + } StrictMock<MockDebugDelegate> debug_delegate; manager_.SetDebugDelegate(&debug_delegate); @@ -1225,6 +1235,9 @@ TEST_F(QuicSentPacketManagerTest, RetransmissionTimeout) { } TEST_F(QuicSentPacketManagerTest, RetransmissionTimeoutOnePacket) { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return; + } // Set the 1RTO connection option. QuicConfig client_config; QuicTagVector options; @@ -1259,6 +1272,9 @@ TEST_F(QuicSentPacketManagerTest, RetransmissionTimeoutOnePacket) { } TEST_F(QuicSentPacketManagerTest, NewRetransmissionTimeout) { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return; + } QuicConfig client_config; QuicTagVector options; options.push_back(kNRTO); @@ -1311,6 +1327,9 @@ TEST_F(QuicSentPacketManagerTest, NewRetransmissionTimeout) { } TEST_F(QuicSentPacketManagerTest, TwoRetransmissionTimeoutsAckSecond) { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return; + } // Send 1 packet. SendDataPacket(1); @@ -1342,6 +1361,9 @@ TEST_F(QuicSentPacketManagerTest, TwoRetransmissionTimeoutsAckSecond) { } TEST_F(QuicSentPacketManagerTest, TwoRetransmissionTimeoutsAckFirst) { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return; + } // Send 1 packet. SendDataPacket(1); @@ -1462,6 +1484,9 @@ TEST_F(QuicSentPacketManagerTest, } TEST_F(QuicSentPacketManagerTest, GetTransmissionTimeTailLossProbe) { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return; + } QuicSentPacketManagerPeer::SetMaxTailLossProbes(&manager_, 2); SendDataPacket(1); SendDataPacket(2); @@ -1495,6 +1520,9 @@ TEST_F(QuicSentPacketManagerTest, GetTransmissionTimeTailLossProbe) { } TEST_F(QuicSentPacketManagerTest, TLPRWithPendingStreamData) { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return; + } QuicConfig config; QuicTagVector options; @@ -1545,6 +1573,9 @@ TEST_F(QuicSentPacketManagerTest, TLPRWithPendingStreamData) { } TEST_F(QuicSentPacketManagerTest, TLPRWithoutPendingStreamData) { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return; + } QuicConfig config; QuicTagVector options; @@ -1593,6 +1624,9 @@ TEST_F(QuicSentPacketManagerTest, TLPRWithoutPendingStreamData) { } TEST_F(QuicSentPacketManagerTest, GetTransmissionTimeSpuriousRTO) { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return; + } RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats()); rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(100), QuicTime::Delta::Zero(), QuicTime::Zero()); @@ -1648,6 +1682,9 @@ TEST_F(QuicSentPacketManagerTest, GetTransmissionTimeSpuriousRTO) { } TEST_F(QuicSentPacketManagerTest, GetTransmissionDelayMin) { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return; + } SendDataPacket(1); // Provide a 1ms RTT sample. const_cast<RttStats*>(manager_.GetRttStats()) @@ -1670,6 +1707,9 @@ TEST_F(QuicSentPacketManagerTest, GetTransmissionDelayMin) { } TEST_F(QuicSentPacketManagerTest, GetTransmissionDelayMax) { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return; + } SendDataPacket(1); // Provide a 60s RTT sample. const_cast<RttStats*>(manager_.GetRttStats()) @@ -1681,6 +1721,9 @@ TEST_F(QuicSentPacketManagerTest, GetTransmissionDelayMax) { } TEST_F(QuicSentPacketManagerTest, GetTransmissionDelayExponentialBackoff) { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return; + } SendDataPacket(1); QuicTime::Delta delay = QuicTime::Delta::FromMilliseconds(500); @@ -1698,6 +1741,9 @@ TEST_F(QuicSentPacketManagerTest, GetTransmissionDelayExponentialBackoff) { } TEST_F(QuicSentPacketManagerTest, RetransmissionDelay) { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return; + } RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats()); const int64_t kRttMs = 250; const int64_t kDeviationMs = 5; @@ -1959,6 +2005,9 @@ TEST_F(QuicSentPacketManagerTest, NegotiateClientCongestionControlFromOptions) { } TEST_F(QuicSentPacketManagerTest, NegotiateNoMinTLPFromOptionsAtServer) { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return; + } QuicConfig config; QuicTagVector options; @@ -1987,6 +2036,9 @@ TEST_F(QuicSentPacketManagerTest, NegotiateNoMinTLPFromOptionsAtServer) { } TEST_F(QuicSentPacketManagerTest, NegotiateNoMinTLPFromOptionsAtClient) { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return; + } QuicConfig client_config; QuicTagVector options; @@ -2015,6 +2067,9 @@ TEST_F(QuicSentPacketManagerTest, NegotiateNoMinTLPFromOptionsAtClient) { } TEST_F(QuicSentPacketManagerTest, NegotiateNoMinRTOFromOptionsAtServer) { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return; + } QuicConfig config; QuicTagVector options; @@ -2037,6 +2092,9 @@ TEST_F(QuicSentPacketManagerTest, NegotiateNoMinRTOFromOptionsAtServer) { } TEST_F(QuicSentPacketManagerTest, NegotiateNoMinRTOFromOptionsAtClient) { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return; + } QuicConfig client_config; QuicTagVector options; @@ -2060,6 +2118,9 @@ TEST_F(QuicSentPacketManagerTest, NegotiateNoMinRTOFromOptionsAtClient) { } TEST_F(QuicSentPacketManagerTest, NegotiateNoTLPFromOptionsAtServer) { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return; + } QuicConfig config; QuicTagVector options; @@ -2072,6 +2133,9 @@ TEST_F(QuicSentPacketManagerTest, NegotiateNoTLPFromOptionsAtServer) { } TEST_F(QuicSentPacketManagerTest, NegotiateNoTLPFromOptionsAtClient) { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return; + } QuicConfig client_config; QuicTagVector options; @@ -2085,6 +2149,9 @@ TEST_F(QuicSentPacketManagerTest, NegotiateNoTLPFromOptionsAtClient) { } TEST_F(QuicSentPacketManagerTest, Negotiate1TLPFromOptionsAtServer) { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return; + } QuicConfig config; QuicTagVector options; @@ -2097,6 +2164,9 @@ TEST_F(QuicSentPacketManagerTest, Negotiate1TLPFromOptionsAtServer) { } TEST_F(QuicSentPacketManagerTest, Negotiate1TLPFromOptionsAtClient) { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return; + } QuicConfig client_config; QuicTagVector options; @@ -2110,6 +2180,9 @@ TEST_F(QuicSentPacketManagerTest, Negotiate1TLPFromOptionsAtClient) { } TEST_F(QuicSentPacketManagerTest, NegotiateTLPRttFromOptionsAtServer) { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return; + } QuicConfig config; QuicTagVector options; @@ -2123,6 +2196,9 @@ TEST_F(QuicSentPacketManagerTest, NegotiateTLPRttFromOptionsAtServer) { } TEST_F(QuicSentPacketManagerTest, NegotiateTLPRttFromOptionsAtClient) { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return; + } QuicConfig client_config; QuicTagVector options; @@ -2137,6 +2213,9 @@ TEST_F(QuicSentPacketManagerTest, NegotiateTLPRttFromOptionsAtClient) { } TEST_F(QuicSentPacketManagerTest, NegotiateNewRTOFromOptionsAtServer) { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return; + } EXPECT_FALSE(QuicSentPacketManagerPeer::GetUseNewRto(&manager_)); QuicConfig config; QuicTagVector options; @@ -2150,6 +2229,9 @@ TEST_F(QuicSentPacketManagerTest, NegotiateNewRTOFromOptionsAtServer) { } TEST_F(QuicSentPacketManagerTest, NegotiateNewRTOFromOptionsAtClient) { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return; + } EXPECT_FALSE(QuicSentPacketManagerPeer::GetUseNewRto(&manager_)); QuicConfig client_config; QuicTagVector options; @@ -2531,6 +2613,9 @@ TEST_F(QuicSentPacketManagerTest, // Regression test for b/133771183. TEST_F(QuicSentPacketManagerTest, PacketInLimbo) { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return; + } QuicSentPacketManagerPeer::SetMaxTailLossProbes(&manager_, 2); // Send SHLO. SendCryptoPacket(1); @@ -2583,6 +2668,9 @@ TEST_F(QuicSentPacketManagerTest, PacketInLimbo) { } TEST_F(QuicSentPacketManagerTest, RtoFiresNoPacketToRetransmit) { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return; + } // Send 10 packets. for (size_t i = 1; i <= 10; ++i) { SendDataPacket(i); @@ -2619,21 +2707,28 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeout) { SendDataPacket(1, ENCRYPTION_FORWARD_SECURE); // Verify PTO is correctly set. + int pto_rttvar_multiplier = + GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; QuicTime::Delta expected_pto_delay = - srtt + 4 * rtt_stats->mean_deviation() + + srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); + QuicTime packet1_sent_time = clock_.Now(); EXPECT_EQ(clock_.Now() + expected_pto_delay, manager_.GetRetransmissionTime()); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10)); SendDataPacket(2, ENCRYPTION_FORWARD_SECURE); // Verify PTO is correctly set based on sent time of packet 2. - EXPECT_EQ(clock_.Now() + expected_pto_delay, - manager_.GetRetransmissionTime()); + QuicTime deadline = clock_.Now() + expected_pto_delay; + if (GetQuicReloadableFlag(quic_default_on_pto)) { + // Verify PTO is set based on left edge. + deadline = packet1_sent_time + expected_pto_delay; + } + EXPECT_EQ(deadline, manager_.GetRetransmissionTime()); EXPECT_EQ(0u, stats_.pto_count); // Invoke PTO. - clock_.AdvanceTime(expected_pto_delay); + clock_.AdvanceTime(deadline - clock_.Now()); manager_.OnRetransmissionTimeout(); EXPECT_EQ(QuicTime::Delta::Zero(), manager_.TimeUntilSend(clock_.Now())); EXPECT_EQ(1u, stats_.pto_count); @@ -2664,7 +2759,7 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeout) { ENCRYPTION_FORWARD_SECURE)); expected_pto_delay = rtt_stats->SmoothedOrInitialRtt() + - std::max(4 * rtt_stats->mean_deviation(), + std::max(pto_rttvar_multiplier * rtt_stats->mean_deviation(), QuicTime::Delta::FromMilliseconds(1)) + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); @@ -2680,6 +2775,7 @@ TEST_F(QuicSentPacketManagerTest, SendOneProbePacket) { .WillRepeatedly(Return(10 * kDefaultTCPMSS)); SendDataPacket(1, ENCRYPTION_FORWARD_SECURE); + QuicTime packet1_sent_time = clock_.Now(); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10)); SendDataPacket(2, ENCRYPTION_FORWARD_SECURE); @@ -2688,14 +2784,20 @@ TEST_F(QuicSentPacketManagerTest, SendOneProbePacket) { QuicTime::Delta::Zero(), QuicTime::Zero()); QuicTime::Delta srtt = rtt_stats->smoothed_rtt(); // Verify PTO period is correctly set. + int pto_rttvar_multiplier = + GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; QuicTime::Delta expected_pto_delay = - srtt + 4 * rtt_stats->mean_deviation() + + srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); - EXPECT_EQ(clock_.Now() + expected_pto_delay, - manager_.GetRetransmissionTime()); + QuicTime deadline = clock_.Now() + expected_pto_delay; + if (GetQuicReloadableFlag(quic_default_on_pto)) { + // Verify PTO is set based on left edge. + deadline = packet1_sent_time + expected_pto_delay; + } + EXPECT_EQ(deadline, manager_.GetRetransmissionTime()); // Invoke PTO. - clock_.AdvanceTime(expected_pto_delay); + clock_.AdvanceTime(deadline - clock_.Now()); manager_.OnRetransmissionTimeout(); EXPECT_EQ(QuicTime::Delta::Zero(), manager_.TimeUntilSend(clock_.Now())); @@ -2773,9 +2875,12 @@ TEST_F(QuicSentPacketManagerTest, PtoTimeoutIncludesMaxAckDelay) { QuicTime::Delta srtt = rtt_stats->smoothed_rtt(); SendDataPacket(1, ENCRYPTION_FORWARD_SECURE); + QuicTime packet1_sent_time = clock_.Now(); // Verify PTO is correctly set and ack delay is included. + int pto_rttvar_multiplier = + GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; QuicTime::Delta expected_pto_delay = - srtt + 4 * rtt_stats->mean_deviation() + + srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); EXPECT_EQ(clock_.Now() + expected_pto_delay, manager_.GetRetransmissionTime()); @@ -2786,12 +2891,15 @@ TEST_F(QuicSentPacketManagerTest, PtoTimeoutIncludesMaxAckDelay) { // not included as an immediate ACK is expected. expected_pto_delay = expected_pto_delay - QuicTime::Delta::FromMilliseconds( kDefaultDelayedAckTimeMs); - EXPECT_EQ(clock_.Now() + expected_pto_delay, - manager_.GetRetransmissionTime()); + QuicTime deadline = clock_.Now() + expected_pto_delay; + if (GetQuicReloadableFlag(quic_default_on_pto)) { + deadline = packet1_sent_time + expected_pto_delay; + } + EXPECT_EQ(deadline, manager_.GetRetransmissionTime()); EXPECT_EQ(0u, stats_.pto_count); // Invoke PTO. - clock_.AdvanceTime(expected_pto_delay); + clock_.AdvanceTime(deadline - clock_.Now()); manager_.OnRetransmissionTimeout(); EXPECT_EQ(QuicTime::Delta::Zero(), manager_.TimeUntilSend(clock_.Now())); EXPECT_EQ(1u, stats_.pto_count); @@ -2819,7 +2927,7 @@ TEST_F(QuicSentPacketManagerTest, PtoTimeoutIncludesMaxAckDelay) { ENCRYPTION_FORWARD_SECURE)); expected_pto_delay = rtt_stats->SmoothedOrInitialRtt() + - std::max(4 * rtt_stats->mean_deviation(), + std::max(pto_rttvar_multiplier * rtt_stats->mean_deviation(), QuicTime::Delta::FromMilliseconds(1)) + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); @@ -2853,7 +2961,7 @@ TEST_F(QuicSentPacketManagerTest, PtoTimeoutIncludesMaxAckDelay) { expected_pto_delay = rtt_stats->SmoothedOrInitialRtt() + - std::max(4 * rtt_stats->mean_deviation(), + std::max(pto_rttvar_multiplier * rtt_stats->mean_deviation(), QuicTime::Delta::FromMilliseconds(1)) + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); for (size_t i = 101; i < 110; i++) { @@ -2891,22 +2999,29 @@ TEST_F(QuicSentPacketManagerTest, StartExponentialBackoffSince2ndPto) { QuicTime::Delta srtt = rtt_stats->smoothed_rtt(); SendDataPacket(1, ENCRYPTION_FORWARD_SECURE); + QuicTime packet1_sent_time = clock_.Now(); // Verify PTO is correctly set. + int pto_rttvar_multiplier = + GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; QuicTime::Delta expected_pto_delay = - srtt + 4 * rtt_stats->mean_deviation() + + srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); - EXPECT_EQ(clock_.Now() + expected_pto_delay, + EXPECT_EQ(packet1_sent_time + expected_pto_delay, manager_.GetRetransmissionTime()); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10)); SendDataPacket(2, ENCRYPTION_FORWARD_SECURE); // Verify PTO is correctly set based on sent time of packet 2. - EXPECT_EQ(clock_.Now() + expected_pto_delay, - manager_.GetRetransmissionTime()); + QuicTime deadline = clock_.Now() + expected_pto_delay; + if (GetQuicReloadableFlag(quic_default_on_pto)) { + // Verify PTO is set based on left edge. + deadline = packet1_sent_time + expected_pto_delay; + } + EXPECT_EQ(deadline, manager_.GetRetransmissionTime()); EXPECT_EQ(0u, stats_.pto_count); // Invoke PTO. - clock_.AdvanceTime(expected_pto_delay); + clock_.AdvanceTime(deadline - clock_.Now()); manager_.OnRetransmissionTimeout(); EXPECT_EQ(QuicTime::Delta::Zero(), manager_.TimeUntilSend(clock_.Now())); EXPECT_EQ(1u, stats_.pto_count); @@ -3017,6 +3132,9 @@ TEST_F(QuicSentPacketManagerTest, PtoTimeoutRttVarMultiple) { // Regression test for b/143962153 TEST_F(QuicSentPacketManagerTest, RtoNotInFlightPacket) { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return; + } QuicSentPacketManagerPeer::SetMaxTailLossProbes(&manager_, 2); // Send SHLO. QuicStreamFrame crypto_frame(1, false, 0, quiche::QuicheStringPiece()); @@ -3094,8 +3212,10 @@ TEST_F(QuicSentPacketManagerTest, Aggressive1Pto) { // Verify PTO period gets set correctly. QuicTime sent_time = clock_.Now(); + int pto_rttvar_multiplier = + GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; expected_pto_delay = - srtt + 4 * rtt_stats->mean_deviation() + + srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); EXPECT_EQ(sent_time + expected_pto_delay * 2, manager_.GetRetransmissionTime()); @@ -3156,8 +3276,10 @@ TEST_F(QuicSentPacketManagerTest, Aggressive2Ptos) { RetransmitDataPacket(5, type, ENCRYPTION_FORWARD_SECURE); }))); manager_.MaybeSendProbePackets(); + int pto_rttvar_multiplier = + GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; expected_pto_delay = - srtt + 4 * rtt_stats->mean_deviation() + + srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); // Verify PTO period gets set correctly. @@ -3195,8 +3317,10 @@ TEST_F(QuicSentPacketManagerTest, ClientMultiplePacketNumberSpacePtoTimeout) { // Send packet 1. SendDataPacket(1, ENCRYPTION_INITIAL); // Verify PTO is correctly set. + int pto_rttvar_multiplier = + GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; QuicTime::Delta expected_pto_delay = - srtt + 4 * rtt_stats->mean_deviation() + + srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); EXPECT_EQ(clock_.Now() + expected_pto_delay, manager_.GetRetransmissionTime()); @@ -3284,8 +3408,10 @@ TEST_F(QuicSentPacketManagerTest, ServerMultiplePacketNumberSpacePtoTimeout) { SendDataPacket(1, ENCRYPTION_INITIAL); const QuicTime packet1_sent_time = clock_.Now(); // Verify PTO is correctly set. + int pto_rttvar_multiplier = + GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; QuicTime::Delta expected_pto_delay = - srtt + 4 * rtt_stats->mean_deviation() + + srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); EXPECT_EQ(packet1_sent_time + expected_pto_delay, manager_.GetRetransmissionTime()); @@ -3326,7 +3452,6 @@ TEST_F(QuicSentPacketManagerTest, ServerMultiplePacketNumberSpacePtoTimeout) { } TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutByLeftEdge) { - SetQuicReloadableFlag(quic_arm_pto_with_earliest_sent_time, true); EnablePto(k1PTO); // Use PTOS and PLE1. QuicConfig config; @@ -3350,8 +3475,10 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutByLeftEdge) { SendDataPacket(1, ENCRYPTION_FORWARD_SECURE); // Verify PTO is correctly set. + int pto_rttvar_multiplier = + GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; QuicTime::Delta expected_pto_delay = - srtt + 4 * rtt_stats->mean_deviation() + + srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); const QuicTime packet1_sent_time = clock_.Now(); EXPECT_EQ(packet1_sent_time + expected_pto_delay, @@ -3391,7 +3518,7 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutByLeftEdge) { ENCRYPTION_FORWARD_SECURE)); expected_pto_delay = rtt_stats->SmoothedOrInitialRtt() + - std::max(4 * rtt_stats->mean_deviation(), + std::max(pto_rttvar_multiplier * rtt_stats->mean_deviation(), QuicTime::Delta::FromMilliseconds(1)) + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); @@ -3401,7 +3528,6 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutByLeftEdge) { } TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutByLeftEdge2) { - SetQuicReloadableFlag(quic_arm_pto_with_earliest_sent_time, true); EnablePto(k1PTO); // Use PTOS and PLE2. QuicConfig config; @@ -3425,8 +3551,10 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutByLeftEdge2) { SendDataPacket(1, ENCRYPTION_FORWARD_SECURE); // Verify PTO is correctly set. + int pto_rttvar_multiplier = + GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; QuicTime::Delta expected_pto_delay = - srtt + 4 * rtt_stats->mean_deviation() + + srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); const QuicTime packet1_sent_time = clock_.Now(); EXPECT_EQ(packet1_sent_time + expected_pto_delay, @@ -3456,7 +3584,7 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutByLeftEdge2) { // Verify PTO period gets set to twice the expected value and based on // packet3 (right edge). expected_pto_delay = - srtt + 4 * rtt_stats->mean_deviation() + + srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); QuicTime packet3_sent_time = clock_.Now(); EXPECT_EQ(packet3_sent_time + expected_pto_delay * 2, @@ -3473,7 +3601,7 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutByLeftEdge2) { ENCRYPTION_FORWARD_SECURE)); expected_pto_delay = rtt_stats->SmoothedOrInitialRtt() + - std::max(4 * rtt_stats->mean_deviation(), + std::max(pto_rttvar_multiplier * rtt_stats->mean_deviation(), QuicTime::Delta::FromMilliseconds(1)) + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); @@ -3484,7 +3612,6 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutByLeftEdge2) { } TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutUsingStandardDeviation) { - SetQuicReloadableFlag(quic_use_standard_deviation_for_pto, true); EnablePto(k1PTO); // Use PTOS and PSDA. QuicConfig config; @@ -3514,8 +3641,10 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutUsingStandardDeviation) { SendDataPacket(1, ENCRYPTION_FORWARD_SECURE); // Verify PTO is correctly set using standard deviation. + int pto_rttvar_multiplier = + GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; QuicTime::Delta expected_pto_delay = - srtt + 4 * rtt_stats->GetStandardOrMeanDeviation() + + srtt + pto_rttvar_multiplier * rtt_stats->GetStandardOrMeanDeviation() + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); EXPECT_EQ(clock_.Now() + expected_pto_delay, manager_.GetRetransmissionTime()); @@ -3523,7 +3652,6 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutUsingStandardDeviation) { TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutByLeftEdgeMultiplePacketNumberSpaces) { - SetQuicReloadableFlag(quic_arm_pto_with_earliest_sent_time, true); manager_.EnableMultiplePacketNumberSpacesSupport(); EnablePto(k1PTO); // Use PTOS and PLE1. @@ -3550,8 +3678,10 @@ TEST_F(QuicSentPacketManagerTest, SendDataPacket(1, ENCRYPTION_INITIAL); const QuicTime packet1_sent_time = clock_.Now(); // Verify PTO is correctly set. + int pto_rttvar_multiplier = + GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; QuicTime::Delta expected_pto_delay = - srtt + 4 * rtt_stats->mean_deviation() + + srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); EXPECT_EQ(packet1_sent_time + expected_pto_delay, manager_.GetRetransmissionTime()); @@ -3599,7 +3729,6 @@ TEST_F(QuicSentPacketManagerTest, TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutByLeftEdge2MultiplePacketNumberSpaces) { - SetQuicReloadableFlag(quic_arm_pto_with_earliest_sent_time, true); manager_.EnableMultiplePacketNumberSpacesSupport(); EnablePto(k1PTO); // Use PTOS and PLE2. @@ -3626,8 +3755,10 @@ TEST_F(QuicSentPacketManagerTest, SendDataPacket(1, ENCRYPTION_INITIAL); const QuicTime packet1_sent_time = clock_.Now(); // Verify PTO is correctly set. + int pto_rttvar_multiplier = + GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; QuicTime::Delta expected_pto_delay = - srtt + 4 * rtt_stats->mean_deviation() + + srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); EXPECT_EQ(packet1_sent_time + expected_pto_delay, manager_.GetRetransmissionTime()); @@ -3722,8 +3853,6 @@ TEST_F(QuicSentPacketManagerTest, NoPacketThresholdDetectionForRuntPackets) { EXPECT_TRUE( QuicSentPacketManagerPeer::UsePacketThresholdForRuntPackets(&manager_)); - SetQuicReloadableFlag(quic_skip_packet_threshold_loss_detection_with_runt, - true); QuicConfig config; QuicTagVector options; options.push_back(kRUNT); @@ -3779,6 +3908,96 @@ TEST_F(QuicSentPacketManagerTest, GetPathDegradingDelay) { EXPECT_EQ(expected_delay, manager_.GetPathDegradingDelay()); } +// Regression test for b/154050235. +TEST_F(QuicSentPacketManagerTest, ExponentialBackoffWithNoRttMeasurement) { + QuicSentPacketManagerPeer::SetPerspective(&manager_, Perspective::IS_CLIENT); + manager_.EnableIetfPtoAndLossDetection(); + RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(kInitialRttMs), + rtt_stats->initial_rtt()); + EXPECT_TRUE(rtt_stats->smoothed_rtt().IsZero()); + + SendCryptoPacket(1); + QuicTime::Delta expected_pto_delay = + QuicTime::Delta::FromMilliseconds(3 * kInitialRttMs); + EXPECT_EQ(clock_.Now() + expected_pto_delay, + manager_.GetRetransmissionTime()); + + // Invoke PTO. + clock_.AdvanceTime(expected_pto_delay); + manager_.OnRetransmissionTimeout(); + + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .WillOnce(WithArgs<1>(Invoke([this]() { RetransmitCryptoPacket(3); }))); + manager_.MaybeSendProbePackets(); + if (GetQuicReloadableFlag(quic_default_on_pto)) { + manager_.AdjustPendingTimerTransmissions(); + } + // Verify exponential backoff of the PTO timeout. + EXPECT_EQ(clock_.Now() + 2 * expected_pto_delay, + manager_.GetRetransmissionTime()); +} + +TEST_F(QuicSentPacketManagerTest, PtoDelayWithTinyInitialRtt) { + manager_.EnableIetfPtoAndLossDetection(); + RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats()); + // Assume client provided a tiny initial RTT. + rtt_stats->set_initial_rtt(QuicTime::Delta::FromMicroseconds(1)); + EXPECT_EQ(QuicTime::Delta::FromMicroseconds(1), rtt_stats->initial_rtt()); + EXPECT_TRUE(rtt_stats->smoothed_rtt().IsZero()); + + SendCryptoPacket(1); + QuicTime::Delta expected_pto_delay = QuicTime::Delta::FromMilliseconds(10); + // Verify kMinHandshakeTimeoutMs is respected. + EXPECT_EQ(clock_.Now() + expected_pto_delay, + manager_.GetRetransmissionTime()); + + // Invoke PTO. + clock_.AdvanceTime(expected_pto_delay); + manager_.OnRetransmissionTimeout(); + + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .WillOnce(WithArgs<1>(Invoke([this]() { RetransmitCryptoPacket(3); }))); + manager_.MaybeSendProbePackets(); + if (GetQuicReloadableFlag(quic_default_on_pto)) { + manager_.AdjustPendingTimerTransmissions(); + } + // Verify exponential backoff of the PTO timeout. + EXPECT_EQ(clock_.Now() + 2 * expected_pto_delay, + manager_.GetRetransmissionTime()); +} + +TEST_F(QuicSentPacketManagerTest, HandshakeAckCausesInitialKeyDropping) { + manager_.EnableMultiplePacketNumberSpacesSupport(); + QuicSentPacketManagerPeer::SetPerspective(&manager_, Perspective::IS_CLIENT); + // Send INITIAL packet 1. + SendDataPacket(1, ENCRYPTION_INITIAL); + QuicTime::Delta expected_pto_delay = + QuicTime::Delta::FromMilliseconds(3 * kInitialRttMs); + EXPECT_EQ(clock_.Now() + expected_pto_delay, + manager_.GetRetransmissionTime()); + // Send HANDSHAKE ack. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10)); + SendAckPacket(2, /*largest_acked=*/1, ENCRYPTION_HANDSHAKE); + // Sending HANDSHAKE packet causes dropping of INITIAL key. + EXPECT_CALL(notifier_, HasUnackedCryptoData()).WillRepeatedly(Return(false)); + EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); + manager_.NeuterUnencryptedPackets(); + // There is no in flight packets. + EXPECT_FALSE(manager_.HasInFlightPackets()); + // Verify PTO timer gets rearmed from now because of anti-amplification. + EXPECT_EQ(clock_.Now() + expected_pto_delay, + manager_.GetRetransmissionTime()); + + // Invoke PTO. + clock_.AdvanceTime(expected_pto_delay); + manager_.OnRetransmissionTimeout(); + // Verify nothing to probe (and connection will send PING for current + // encryption level). + EXPECT_CALL(notifier_, RetransmitFrames(_, _)).Times(0); + manager_.MaybeSendProbePackets(); +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_session.cc b/chromium/net/third_party/quiche/src/quic/core/quic_session.cc index 5376bfdddde..0f00ff3843d 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_session.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_session.cc @@ -45,24 +45,6 @@ class ClosedStreamsCleanUpDelegate : public QuicAlarm::Delegate { QuicSession* session_; }; -// TODO(renjietang): remove this function once -// gfe2_reloadable_flag_quic_write_with_transmission is deprecated. -void CountTransmissionTypeFlag(TransmissionType type) { - switch (type) { - case NOT_RETRANSMISSION: - QUIC_RELOADABLE_FLAG_COUNT_N(quic_write_with_transmission, 1, 4); - break; - case HANDSHAKE_RETRANSMISSION: - QUIC_RELOADABLE_FLAG_COUNT_N(quic_write_with_transmission, 2, 4); - break; - case LOSS_RETRANSMISSION: - QUIC_RELOADABLE_FLAG_COUNT_N(quic_write_with_transmission, 3, 4); - break; - default: - QUIC_RELOADABLE_FLAG_COUNT_N(quic_write_with_transmission, 4, 4); - } -} - } // namespace #define ENDPOINT \ @@ -93,6 +75,7 @@ QuicSession::QuicSession( num_expected_unidirectional_static_streams), num_dynamic_incoming_streams_(0), num_draining_incoming_streams_(0), + num_draining_outgoing_streams_(0), num_outgoing_static_streams_(0), num_incoming_static_streams_(0), num_locally_closed_incoming_streams_highest_offset_(0), @@ -117,11 +100,11 @@ QuicSession::QuicSession( supported_versions_(supported_versions), use_http2_priority_write_scheduler_(false), is_configured_(false), - num_expected_unidirectional_static_streams_( - num_expected_unidirectional_static_streams), enable_round_robin_scheduling_(false), - write_with_transmission_( - GetQuicReloadableFlag(quic_write_with_transmission)) { + deprecate_draining_streams_( + GetQuicReloadableFlag(quic_deprecate_draining_streams)), + break_close_loop_( + GetQuicReloadableFlag(quic_break_session_stream_close_loop)) { closed_streams_clean_up_alarm_ = QuicWrapUnique<QuicAlarm>(connection_->alarm_factory()->CreateAlarm( new ClosedStreamsCleanUpDelegate(this))); @@ -129,6 +112,14 @@ QuicSession::QuicSession( connection_->version().handshake_protocol == PROTOCOL_TLS1_3) { config_.SetStatelessResetTokenToSend(GetStatelessResetToken()); } + if (VersionHasIetfQuicFrames(transport_version())) { + config_.SetMaxUnidirectionalStreamsToSend( + config_.GetMaxUnidirectionalStreamsToSend() + + num_expected_unidirectional_static_streams); + } + if (break_close_loop_) { + QUIC_RELOADABLE_FLAG_COUNT(quic_break_session_stream_close_loop); + } } void QuicSession::Initialize() { @@ -301,6 +292,10 @@ void QuicSession::OnOneRttPacketAcknowledged() { GetMutableCryptoStream()->OnOneRttPacketAcknowledged(); } +void QuicSession::OnHandshakePacketSent() { + GetMutableCryptoStream()->OnHandshakePacketSent(); +} + void QuicSession::PendingStreamOnRstStream(const QuicRstStreamFrame& frame) { DCHECK(VersionUsesHttp3(transport_version())); QuicStreamId stream_id = frame.stream_id; @@ -398,11 +393,16 @@ void QuicSession::OnConnectionClosed(const QuicConnectionCloseFrame& frame, RecordConnectionCloseAtServer(frame.quic_error_code, source); } - if (on_closed_frame_.extracted_error_code == QUIC_NO_ERROR) { + if (on_closed_frame_.quic_error_code == QUIC_NO_ERROR) { // Save all of the connection close information on_closed_frame_ = frame; } + if (GetQuicReloadableFlag(quic_notify_handshaker_on_connection_close)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_notify_handshaker_on_connection_close); + GetMutableCryptoStream()->OnConnectionClosed(frame.quic_error_code, source); + } + // Copy all non static streams in a new map for the ease of deleting. QuicSmallMap<QuicStreamId, QuicStream*, 10> non_static_streams; for (const auto& it : stream_map_) { @@ -431,8 +431,8 @@ void QuicSession::OnConnectionClosed(const QuicConnectionCloseFrame& frame, if (visitor_) { visitor_->OnConnectionClosed(connection_->connection_id(), - frame.extracted_error_code, - frame.error_details, source); + frame.quic_error_code, frame.error_details, + source); } } @@ -558,9 +558,6 @@ void QuicSession::OnCanWrite() { "write blocked."; return; } - if (!write_with_transmission_) { - SetTransmissionType(NOT_RETRANSMISSION); - } // We limit the number of writes to the number of pending streams. If more // streams become pending, WillingAndAbleToWrite will be true, which will // cause the connection to request resumption before yielding to other @@ -685,7 +682,7 @@ bool QuicSession::HasPendingHandshake() const { } uint64_t QuicSession::GetNumOpenDynamicStreams() const { - return stream_map_.size() - draining_streams_.size() + + return stream_map_.size() - GetNumDrainingStreams() + locally_closed_streams_highest_offset_.size() - num_incoming_static_streams_ - num_outgoing_static_streams_; } @@ -714,10 +711,7 @@ QuicConsumedData QuicSession::WritevData( return QuicConsumedData(0, false); } - if (write_with_transmission_) { - SetTransmissionType(type); - CountTransmissionTypeFlag(type); - } + SetTransmissionType(type); const auto current_level = connection()->encryption_level(); if (level.has_value()) { connection()->SetDefaultEncryptionLevel(level.value()); @@ -743,10 +737,7 @@ size_t QuicSession::SendCryptoData(EncryptionLevel level, QuicStreamOffset offset, TransmissionType type) { DCHECK(QuicVersionUsesCryptoFrames(transport_version())); - if (write_with_transmission_) { - SetTransmissionType(type); - CountTransmissionTypeFlag(type); - } + SetTransmissionType(type); const auto current_level = connection()->encryption_level(); connection_->SetDefaultEncryptionLevel(level); const auto bytes_consumed = @@ -758,10 +749,7 @@ size_t QuicSession::SendCryptoData(EncryptionLevel level, bool QuicSession::WriteControlFrame(const QuicFrame& frame, TransmissionType type) { - if (write_with_transmission_) { - SetTransmissionType(type); - CountTransmissionTypeFlag(type); - } + SetTransmissionType(type); return connection_->SendControlFrame(frame); } @@ -776,6 +764,10 @@ void QuicSession::SendRstStream(QuicStreamId id, connection_->OnStreamReset(id, error); } + if (break_close_loop_) { + return; + } + if (error != QUIC_STREAM_NO_ERROR && QuicContainsKey(zombie_streams_, id)) { OnStreamDoneWaitingForAcks(id); return; @@ -783,6 +775,26 @@ void QuicSession::SendRstStream(QuicStreamId id, CloseStreamInner(id, true); } +void QuicSession::ResetStream(QuicStreamId id, + QuicRstStreamErrorCode error, + QuicStreamOffset bytes_written) { + DCHECK(break_close_loop_); + QuicStream* stream = GetStream(id); + if (stream != nullptr && stream->is_static()) { + connection()->CloseConnection( + QUIC_INVALID_STREAM_ID, "Try to reset a static stream", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return; + } + + if (stream != nullptr) { + stream->Reset(error); + return; + } + + SendRstStream(id, error, bytes_written); +} + void QuicSession::MaybeSendRstStreamFrame(QuicStreamId id, QuicRstStreamErrorCode error, QuicStreamOffset bytes_written) { @@ -875,6 +887,11 @@ void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool rst_sent) { ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); return; } + if (break_close_loop_) { + stream->CloseReadSide(); + stream->CloseWriteSide(); + return; + } StreamType type = stream->type(); // Tell the stream that a RST has been sent. @@ -904,16 +921,27 @@ void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool rst_sent) { InsertLocallyClosedStreamsHighestOffset( stream_id, stream->flow_controller()->highest_received_byte_offset()); } + bool stream_was_draining = false; + if (deprecate_draining_streams_) { + stream_was_draining = stream->was_draining(); + QUIC_DVLOG_IF(1, stream_was_draining) + << ENDPOINT << "Stream " << stream_id << " was draining"; + } stream_map_.erase(it); if (IsIncomingStream(stream_id)) { --num_dynamic_incoming_streams_; } - - const bool stream_was_draining = - draining_streams_.find(stream_id) != draining_streams_.end(); + if (!deprecate_draining_streams_) { + stream_was_draining = + draining_streams_.find(stream_id) != draining_streams_.end(); + } if (stream_was_draining) { if (IsIncomingStream(stream_id)) { + QUIC_BUG_IF(num_draining_incoming_streams_ == 0); --num_draining_incoming_streams_; + } else if (deprecate_draining_streams_) { + QUIC_BUG_IF(num_draining_outgoing_streams_ == 0); + --num_draining_outgoing_streams_; } draining_streams_.erase(stream_id); } else if (VersionHasIetfQuicFrames(transport_version())) { @@ -923,6 +951,10 @@ void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool rst_sent) { // Do not bother informing stream ID manager if connection is closed. v99_streamid_manager_.OnStreamClosed(stream_id); } + } else if (stream_id_manager_.handles_accounting() && had_fin_or_rst && + connection_->connected()) { + stream_id_manager_.OnStreamClosed( + /*is_incoming=*/IsIncomingStream(stream_id)); } stream->OnClose(); @@ -935,12 +967,100 @@ void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool rst_sent) { } } +void QuicSession::OnStreamClosed(QuicStreamId stream_id) { + QUIC_DVLOG(1) << ENDPOINT << "Closing stream: " << stream_id; + DCHECK(break_close_loop_); + StreamMap::iterator it = stream_map_.find(stream_id); + if (it == stream_map_.end()) { + QUIC_DVLOG(1) << ENDPOINT << "Stream is already closed: " << stream_id; + return; + } + QuicStream* stream = it->second.get(); + StreamType type = stream->type(); + + if (stream->IsWaitingForAcks()) { + zombie_streams_[stream->id()] = std::move(it->second); + } else { + // Clean up the stream since it is no longer waiting for acks. + streams_waiting_for_acks_.erase(stream->id()); + closed_streams_.push_back(std::move(it->second)); + // Do not retransmit data of a closed stream. + streams_with_pending_retransmission_.erase(stream_id); + if (!closed_streams_clean_up_alarm_->IsSet()) { + closed_streams_clean_up_alarm_->Set( + connection_->clock()->ApproximateNow()); + } + } + + if (!stream->HasReceivedFinalOffset()) { + // If we haven't received a FIN or RST for this stream, we need to keep + // track of the how many bytes the stream's flow controller believes it has + // received, for accurate connection level flow control accounting. + // If this is an outgoing stream, it is technically open from peer's + // perspective. Do not inform stream Id manager yet. + DCHECK(!stream->was_draining()); + InsertLocallyClosedStreamsHighestOffset( + stream_id, stream->flow_controller()->highest_received_byte_offset()); + stream_map_.erase(it); + if (IsIncomingStream(stream_id)) { + --num_dynamic_incoming_streams_; + } + return; + } + + bool stream_was_draining = false; + if (deprecate_draining_streams_) { + stream_was_draining = stream->was_draining(); + QUIC_DVLOG_IF(1, stream_was_draining) + << ENDPOINT << "Stream " << stream_id << " was draining"; + } + stream_map_.erase(it); + if (IsIncomingStream(stream_id)) { + --num_dynamic_incoming_streams_; + } + if (!deprecate_draining_streams_) { + stream_was_draining = + draining_streams_.find(stream_id) != draining_streams_.end(); + } + if (stream_was_draining) { + if (IsIncomingStream(stream_id)) { + QUIC_BUG_IF(num_draining_incoming_streams_ == 0); + --num_draining_incoming_streams_; + } else if (deprecate_draining_streams_) { + QUIC_BUG_IF(num_draining_outgoing_streams_ == 0); + --num_draining_outgoing_streams_; + } + draining_streams_.erase(stream_id); + // Stream Id manager has been informed with draining streams. + return; + } + if (!connection_->connected()) { + // Do not bother informing stream ID manager if connection has been + // disconnected. + return; + } + if (stream_id_manager_.handles_accounting() && + !VersionHasIetfQuicFrames(transport_version())) { + stream_id_manager_.OnStreamClosed( + /*is_incoming=*/IsIncomingStream(stream_id)); + } + if (IsIncomingStream(stream_id)) { + // Stream Id manager is only interested in peer initiated stream IDs. + if (VersionHasIetfQuicFrames(transport_version())) { + v99_streamid_manager_.OnStreamClosed(stream_id); + } + return; + } + if (!VersionHasIetfQuicFrames(transport_version())) { + OnCanCreateNewOutgoingStream(type != BIDIRECTIONAL); + } +} + void QuicSession::ClosePendingStream(QuicStreamId stream_id) { QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << stream_id; - + DCHECK(VersionHasIetfQuicFrames(transport_version())); pending_stream_map_.erase(stream_id); - if (VersionHasIetfQuicFrames(transport_version()) && - connection_->connected()) { + if (connection_->connected()) { v99_streamid_manager_.OnStreamClosed(stream_id); } } @@ -970,6 +1090,11 @@ void QuicSession::OnFinalByteOffsetReceived( flow_controller_.AddBytesConsumed(offset_diff); locally_closed_streams_highest_offset_.erase(it); + if (stream_id_manager_.handles_accounting() && + !VersionHasIetfQuicFrames(transport_version())) { + stream_id_manager_.OnStreamClosed( + /*is_incoming=*/IsIncomingStream(stream_id)); + } if (IsIncomingStream(stream_id)) { --num_locally_closed_incoming_streams_highest_offset_; if (VersionHasIetfQuicFrames(transport_version())) { @@ -1006,6 +1131,18 @@ void QuicSession::OnConfigNegotiated() { QUIC_DVLOG(1) << ENDPOINT << "Setting Bidirectional outgoing_max_streams_ to " << max_streams; + if (perspective_ == Perspective::IS_CLIENT && + max_streams < + v99_streamid_manager_.max_outgoing_bidirectional_streams()) { + connection_->CloseConnection( + QUIC_MAX_STREAMS_ERROR, + quiche::QuicheStrCat( + "new bidirectional limit ", max_streams, + " decreases the current limit: ", + v99_streamid_manager_.max_outgoing_bidirectional_streams()), + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return; + } if (v99_streamid_manager_.MaybeAllowNewOutgoingBidirectionalStreams( max_streams)) { OnCanCreateNewOutgoingStream(/*unidirectional = */ false); @@ -1015,14 +1152,16 @@ void QuicSession::OnConfigNegotiated() { if (config_.HasReceivedMaxUnidirectionalStreams()) { max_streams = config_.ReceivedMaxUnidirectionalStreams(); } - if (max_streams < num_expected_unidirectional_static_streams_) { - // TODO(ianswett): Change this to an application error for HTTP/3. - QUIC_DLOG(ERROR) << "Received unidirectional stream limit of " - << max_streams << " < " - << num_expected_unidirectional_static_streams_; + if (max_streams < + v99_streamid_manager_.max_outgoing_unidirectional_streams()) { connection_->CloseConnection( - QUIC_MAX_STREAMS_ERROR, "New unidirectional stream limit is too low.", + QUIC_MAX_STREAMS_ERROR, + quiche::QuicheStrCat( + "new unidirectional limit ", max_streams, + " decreases the current limit: ", + v99_streamid_manager_.max_outgoing_unidirectional_streams()), ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return; } QUIC_DVLOG(1) << ENDPOINT << "Setting Unidirectional outgoing_max_streams_ to " @@ -1196,6 +1335,7 @@ void QuicSession::HandleRstOnValidNonexistentStream( } void QuicSession::OnNewStreamFlowControlWindow(QuicStreamOffset new_window) { + DCHECK_EQ(connection_->version().handshake_protocol, PROTOCOL_QUIC_CRYPTO); QUIC_DVLOG(1) << ENDPOINT << "OnNewStreamFlowControlWindow " << new_window; if (new_window < kMinimumFlowControlSendWindow && !connection_->version().AllowsLowFlowControlLimits()) { @@ -1212,19 +1352,22 @@ void QuicSession::OnNewStreamFlowControlWindow(QuicStreamOffset new_window) { for (auto const& kv : stream_map_) { QUIC_DVLOG(1) << ENDPOINT << "Informing stream " << kv.first << " of new stream flow control window " << new_window; - kv.second->UpdateSendWindowOffset(new_window); + if (!kv.second->ConfigSendWindowOffset(new_window)) { + return; + } } if (!QuicVersionUsesCryptoFrames(transport_version())) { QUIC_DVLOG(1) << ENDPOINT << "Informing crypto stream of new stream flow control window " << new_window; - GetMutableCryptoStream()->UpdateSendWindowOffset(new_window); + GetMutableCryptoStream()->ConfigSendWindowOffset(new_window); } } void QuicSession::OnNewStreamUnidirectionalFlowControlWindow( QuicStreamOffset new_window) { + DCHECK_EQ(connection_->version().handshake_protocol, PROTOCOL_TLS1_3); QUIC_DVLOG(1) << ENDPOINT << "OnNewStreamUnidirectionalFlowControlWindow " << new_window; // Inform all existing outgoing unidirectional streams about the new window. @@ -1239,12 +1382,15 @@ void QuicSession::OnNewStreamUnidirectionalFlowControlWindow( } QUIC_DVLOG(1) << ENDPOINT << "Informing unidirectional stream " << id << " of new stream flow control window " << new_window; - kv.second->UpdateSendWindowOffset(new_window); + if (!kv.second->ConfigSendWindowOffset(new_window)) { + return; + } } } void QuicSession::OnNewStreamOutgoingBidirectionalFlowControlWindow( QuicStreamOffset new_window) { + DCHECK_EQ(connection_->version().handshake_protocol, PROTOCOL_TLS1_3); QUIC_DVLOG(1) << ENDPOINT << "OnNewStreamOutgoingBidirectionalFlowControlWindow " << new_window; @@ -1260,12 +1406,15 @@ void QuicSession::OnNewStreamOutgoingBidirectionalFlowControlWindow( } QUIC_DVLOG(1) << ENDPOINT << "Informing outgoing bidirectional stream " << id << " of new stream flow control window " << new_window; - kv.second->UpdateSendWindowOffset(new_window); + if (!kv.second->ConfigSendWindowOffset(new_window)) { + return; + } } } void QuicSession::OnNewStreamIncomingBidirectionalFlowControlWindow( QuicStreamOffset new_window) { + DCHECK_EQ(connection_->version().handshake_protocol, PROTOCOL_TLS1_3); QUIC_DVLOG(1) << ENDPOINT << "OnNewStreamIncomingBidirectionalFlowControlWindow " << new_window; @@ -1281,19 +1430,36 @@ void QuicSession::OnNewStreamIncomingBidirectionalFlowControlWindow( } QUIC_DVLOG(1) << ENDPOINT << "Informing incoming bidirectional stream " << id << " of new stream flow control window " << new_window; - kv.second->UpdateSendWindowOffset(new_window); + if (!kv.second->ConfigSendWindowOffset(new_window)) { + return; + } } } void QuicSession::OnNewSessionFlowControlWindow(QuicStreamOffset new_window) { QUIC_DVLOG(1) << ENDPOINT << "OnNewSessionFlowControlWindow " << new_window; - if (new_window < kMinimumFlowControlSendWindow && - !connection_->version().AllowsLowFlowControlLimits()) { + bool close_connection = false; + if (!connection_->version().AllowsLowFlowControlLimits()) { + if (new_window < kMinimumFlowControlSendWindow) { + close_connection = true; + QUIC_LOG_FIRST_N(ERROR, 1) + << "Peer sent us an invalid session flow control send window: " + << new_window << ", below default: " << kMinimumFlowControlSendWindow; + } + } else if (perspective_ == Perspective::IS_CLIENT && + new_window < flow_controller_.send_window_offset()) { + // The client receives a lower limit than remembered, violating + // https://tools.ietf.org/html/draft-ietf-quic-transport-27#section-7.3.1 QUIC_LOG_FIRST_N(ERROR, 1) << "Peer sent us an invalid session flow control send window: " - << new_window << ", below default: " << kMinimumFlowControlSendWindow; + << new_window + << ", below current: " << flow_controller_.send_window_offset(); + close_connection = true; + } + if (close_connection) { connection_->CloseConnection( - QUIC_FLOW_CONTROL_INVALID_WINDOW, "New connection window too low", + QUIC_FLOW_CONTROL_INVALID_WINDOW, + quiche::QuicheStrCat("New connection window too low: ", new_window), ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); return; } @@ -1332,12 +1498,20 @@ void QuicSession::OnNewEncryptionKeyAvailable( std::unique_ptr<QuicEncrypter> encrypter) { connection()->SetEncrypter(level, std::move(encrypter)); - if (GetQuicRestartFlag(quic_send_settings_on_write_key_available) && - connection_->version().handshake_protocol == PROTOCOL_TLS1_3 && + if (connection_->version().handshake_protocol == PROTOCOL_TLS1_3 && + (perspective() == Perspective::IS_CLIENT || + GetQuicReloadableFlag(quic_change_default_encryption_level))) { + QUIC_DVLOG(1) << ENDPOINT << "Set default encryption level to " + << EncryptionLevelToString(level); + QUIC_RELOADABLE_FLAG_COUNT(quic_change_default_encryption_level); + connection()->SetDefaultEncryptionLevel(level); + return; + } + + if (connection_->version().handshake_protocol == PROTOCOL_TLS1_3 && level == ENCRYPTION_FORWARD_SECURE) { // Set connection's default encryption level once 1-RTT write key is // available. - QUIC_RESTART_FLAG_COUNT_N(quic_send_settings_on_write_key_available, 1, 2); QUIC_DVLOG(1) << ENDPOINT << "Set default encryption level to " << EncryptionLevelToString(level); connection()->SetDefaultEncryptionLevel(level); @@ -1379,12 +1553,6 @@ void QuicSession::SetDefaultEncryptionLevel(EncryptionLevel level) { void QuicSession::OnOneRttKeysAvailable() { DCHECK_EQ(PROTOCOL_TLS1_3, connection_->version().handshake_protocol); - if (!GetQuicRestartFlag(quic_send_settings_on_write_key_available)) { - QUIC_DVLOG(1) << ENDPOINT << "Set default encryption level to " - << EncryptionLevelToString(ENCRYPTION_FORWARD_SECURE); - connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); - } - QUIC_BUG_IF(!GetCryptoStream()->crypto_negotiated_params().cipher_suite) << ENDPOINT << "Handshake completes without cipher suite negotiation."; QUIC_BUG_IF(!config_.negotiated()) @@ -1477,7 +1645,7 @@ void QuicSession::ActivateStream(std::unique_ptr<QuicStream> stream) { QuicStreamId stream_id = stream->id(); bool is_static = stream->is_static(); QUIC_DVLOG(1) << ENDPOINT << "num_streams: " << stream_map_.size() - << ". activating " << stream_id; + << ". activating stream " << stream_id; DCHECK(!QuicContainsKey(stream_map_, stream_id)); stream_map_[stream_id] = std::move(stream); if (IsIncomingStream(stream_id)) { @@ -1486,13 +1654,11 @@ void QuicSession::ActivateStream(std::unique_ptr<QuicStream> stream) { } else if (is_static) { ++num_outgoing_static_streams_; } - - if (VersionHasIetfQuicFrames(transport_version()) && - !QuicUtils::IsBidirectionalStreamId(stream_id) && is_static) { - DCHECK_LE(num_incoming_static_streams_, - num_expected_unidirectional_static_streams_); - DCHECK_LE(num_outgoing_static_streams_, - num_expected_unidirectional_static_streams_); + if (stream_id_manager_.handles_accounting() && !is_static && + !VersionHasIetfQuicFrames(transport_version())) { + // Do not inform stream ID manager of static streams. + stream_id_manager_.ActivateStream( + /*is_incoming=*/IsIncomingStream(stream_id)); } } @@ -1585,7 +1751,11 @@ QuicStream* QuicSession::GetOrCreateStream(const QuicStreamId stream_id) { if (!stream_id_manager_.CanOpenIncomingStream( GetNumOpenIncomingStreams())) { // Refuse to open the stream. - SendRstStream(stream_id, QUIC_REFUSED_STREAM, 0); + if (break_close_loop_) { + ResetStream(stream_id, QUIC_REFUSED_STREAM, 0); + } else { + SendRstStream(stream_id, QUIC_REFUSED_STREAM, 0); + } return nullptr; } } @@ -1593,8 +1763,25 @@ QuicStream* QuicSession::GetOrCreateStream(const QuicStreamId stream_id) { return CreateIncomingStream(stream_id); } -void QuicSession::StreamDraining(QuicStreamId stream_id) { +void QuicSession::StreamDraining(QuicStreamId stream_id, bool unidirectional) { DCHECK(QuicContainsKey(stream_map_, stream_id)); + if (deprecate_draining_streams_) { + QUIC_RELOADABLE_FLAG_COUNT(quic_deprecate_draining_streams); + QUIC_DVLOG(1) << ENDPOINT << "Stream " << stream_id << " is draining"; + if (VersionHasIetfQuicFrames(transport_version())) { + v99_streamid_manager_.OnStreamClosed(stream_id); + } else if (stream_id_manager_.handles_accounting()) { + stream_id_manager_.OnStreamClosed( + /*is_incoming=*/IsIncomingStream(stream_id)); + } + if (IsIncomingStream(stream_id)) { + ++num_draining_incoming_streams_; + return; + } + ++num_draining_outgoing_streams_; + OnCanCreateNewOutgoingStream(unidirectional); + return; + } if (!QuicContainsKey(draining_streams_, stream_id)) { draining_streams_.insert(stream_id); if (IsIncomingStream(stream_id)) { @@ -1602,6 +1789,9 @@ void QuicSession::StreamDraining(QuicStreamId stream_id) { } if (VersionHasIetfQuicFrames(transport_version())) { v99_streamid_manager_.OnStreamClosed(stream_id); + } else if (stream_id_manager_.handles_accounting()) { + stream_id_manager_.OnStreamClosed( + /*is_incoming=*/IsIncomingStream(stream_id)); } } if (!IsIncomingStream(stream_id)) { @@ -1735,11 +1925,19 @@ bool QuicSession::IsStaticStream(QuicStreamId id) const { } size_t QuicSession::GetNumOpenIncomingStreams() const { + DCHECK(!VersionHasIetfQuicFrames(transport_version())); + if (stream_id_manager_.handles_accounting()) { + return stream_id_manager_.num_open_incoming_streams(); + } return num_dynamic_incoming_streams_ - num_draining_incoming_streams_ + num_locally_closed_incoming_streams_highest_offset_; } size_t QuicSession::GetNumOpenOutgoingStreams() const { + DCHECK(!VersionHasIetfQuicFrames(transport_version())); + if (stream_id_manager_.handles_accounting()) { + return stream_id_manager_.num_open_outgoing_streams(); + } DCHECK_GE(GetNumDynamicOutgoingStreams() + GetNumLocallyClosedOutgoingStreamsHighestOffset(), GetNumDrainingOutgoingStreams()); @@ -1749,11 +1947,22 @@ size_t QuicSession::GetNumOpenOutgoingStreams() const { } size_t QuicSession::GetNumActiveStreams() const { - return stream_map_.size() - draining_streams_.size() - + if (!VersionHasIetfQuicFrames(transport_version()) && + stream_id_manager_.handles_accounting()) { + // Exclude locally_closed_streams when determine whether to keep connection + // alive. + return stream_id_manager_.num_open_incoming_streams() + + stream_id_manager_.num_open_outgoing_streams() - + locally_closed_streams_highest_offset_.size(); + } + return stream_map_.size() - GetNumDrainingStreams() - num_incoming_static_streams_ - num_outgoing_static_streams_; } size_t QuicSession::GetNumDrainingStreams() const { + if (deprecate_draining_streams_) { + return num_draining_incoming_streams_ + num_draining_outgoing_streams_; + } return draining_streams_.size(); } @@ -1796,6 +2005,9 @@ size_t QuicSession::GetNumDynamicOutgoingStreams() const { } size_t QuicSession::GetNumDrainingOutgoingStreams() const { + if (deprecate_draining_streams_) { + return num_draining_outgoing_streams_; + } DCHECK_GE(draining_streams_.size(), num_draining_incoming_streams_); return draining_streams_.size() - num_draining_incoming_streams_; } @@ -1840,7 +2052,7 @@ size_t QuicSession::MaxAvailableUnidirectionalStreams() const { bool QuicSession::IsIncomingStream(QuicStreamId id) const { if (VersionHasIetfQuicFrames(transport_version())) { - return v99_streamid_manager_.IsIncomingStream(id); + return !QuicUtils::IsOutgoingStreamId(version(), id, perspective_); } return stream_id_manager_.IsIncomingStream(id); } @@ -1974,9 +2186,6 @@ void QuicSession::OnFrameLost(const QuicFrame& frame) { void QuicSession::RetransmitFrames(const QuicFrames& frames, TransmissionType type) { QuicConnection::ScopedPacketFlusher retransmission_flusher(connection_); - if (!write_with_transmission_) { - SetTransmissionType(type); - } for (const QuicFrame& frame : frames) { if (frame.type == MESSAGE_FRAME) { // Do not retransmit MESSAGE frames. @@ -2070,18 +2279,12 @@ bool QuicSession::RetransmitLostData() { bool uses_crypto_frames = QuicVersionUsesCryptoFrames(transport_version()); QuicCryptoStream* crypto_stream = GetMutableCryptoStream(); if (uses_crypto_frames && crypto_stream->HasPendingCryptoRetransmission()) { - if (!write_with_transmission_) { - SetTransmissionType(HANDSHAKE_RETRANSMISSION); - } crypto_stream->WritePendingCryptoRetransmission(); } // Retransmit crypto data in stream 1 frames (version < 47). if (!uses_crypto_frames && QuicContainsKey(streams_with_pending_retransmission_, QuicUtils::GetCryptoStreamId(transport_version()))) { - if (!write_with_transmission_) { - SetTransmissionType(HANDSHAKE_RETRANSMISSION); - } // Retransmit crypto data first. QuicStream* crypto_stream = GetStream(QuicUtils::GetCryptoStreamId(transport_version())); @@ -2096,9 +2299,6 @@ bool QuicSession::RetransmitLostData() { } } if (control_frame_manager_.HasPendingRetransmission()) { - if (!write_with_transmission_) { - SetTransmissionType(LOSS_RETRANSMISSION); - } control_frame_manager_.OnCanWrite(); if (control_frame_manager_.HasPendingRetransmission()) { return false; @@ -2112,9 +2312,6 @@ bool QuicSession::RetransmitLostData() { const QuicStreamId id = streams_with_pending_retransmission_.begin()->first; QuicStream* stream = GetStream(id); if (stream != nullptr) { - if (!write_with_transmission_) { - SetTransmissionType(LOSS_RETRANSMISSION); - } stream->OnCanWrite(); DCHECK(CheckStreamWriteBlocked(stream)); if (stream->HasPendingRetransmission()) { @@ -2260,5 +2457,9 @@ void QuicSession::OnAlpnSelected(quiche::QuicheStringPiece alpn) { << "ALPN selected: " << alpn; } +void QuicSession::NeuterCryptoDataOfEncryptionLevel(EncryptionLevel level) { + GetMutableCryptoStream()->NeuterStreamDataOfEncryptionLevel(level); +} + #undef ENDPOINT // undef for jumbo builds } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_session.h b/chromium/net/third_party/quiche/src/quic/core/quic_session.h index ac99a3f7584..5a1ebbc602c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_session.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_session.h @@ -126,6 +126,7 @@ class QUIC_EXPORT_PRIVATE QuicSession void OnStopSendingFrame(const QuicStopSendingFrame& frame) override; void OnPacketDecrypted(EncryptionLevel level) override; void OnOneRttPacketAcknowledged() override; + void OnHandshakePacketSent() override; // QuicStreamFrameDataProducer WriteStreamDataResult WriteStreamData(QuicStreamId id, @@ -198,13 +199,17 @@ class QUIC_EXPORT_PRIVATE QuicSession // will be sent in specified transmission |type|. bool WriteControlFrame(const QuicFrame& frame, TransmissionType type); - // Close the stream in both directions. - // TODO(renjietang): rename this method as it sends both RST_STREAM and - // STOP_SENDING in IETF QUIC. + // Called by stream to send RST_STREAM (and STOP_SENDING). virtual void SendRstStream(QuicStreamId id, QuicRstStreamErrorCode error, QuicStreamOffset bytes_written); + // Called to send RST_STREAM (and STOP_SENDING) and close stream. If stream + // |id| does not exist, just send RST_STREAM (and STOP_SENDING). + virtual void ResetStream(QuicStreamId id, + QuicRstStreamErrorCode error, + QuicStreamOffset bytes_written); + // Called when the session wants to go away and not accept any new streams. virtual void SendGoAway(QuicErrorCode error_code, const std::string& reason); @@ -217,9 +222,15 @@ class QUIC_EXPORT_PRIVATE QuicSession // Create and transmit a STOP_SENDING frame virtual void SendStopSending(uint16_t code, QuicStreamId stream_id); - // Removes the stream associated with 'stream_id' from the active stream map. + // Close stream |stream_id|. Whether sending RST_STREAM (and STOP_SENDING) + // depends on the sending and receiving states. + // TODO(fayang): Deprecate CloseStream, instead always use ResetStream to + // close a stream from session. virtual void CloseStream(QuicStreamId stream_id); + // Called by stream |stream_id| when it gets closed. + virtual void OnStreamClosed(QuicStreamId stream_id); + // Returns true if outgoing packets will be encrypted, even if the server // hasn't confirmed the handshake yet. virtual bool IsEncryptionEstablished() const; @@ -316,10 +327,16 @@ class QUIC_EXPORT_PRIVATE QuicSession // Returns the number of currently open peer initiated streams, excluding // static streams. + // TODO(fayang): remove this and instead use + // LegacyStreamIdManager::num_open_incoming_streams() in tests when + // deprecating quic_stream_id_manager_handles_accounting. size_t GetNumOpenIncomingStreams() const; // Returns the number of currently open self initiated streams, excluding // static streams. + // TODO(fayang): remove this and instead use + // LegacyStreamIdManager::num_open_outgoing_streams() in tests when + // deprecating quic_stream_id_manager_handles_accounting. size_t GetNumOpenOutgoingStreams() const; // Returns the number of open peer initiated static streams. @@ -365,7 +382,7 @@ class QUIC_EXPORT_PRIVATE QuicSession bool goaway_received() const { return goaway_received_; } // Returns the Google QUIC error code - QuicErrorCode error() const { return on_closed_frame_.extracted_error_code; } + QuicErrorCode error() const { return on_closed_frame_.quic_error_code; } const std::string& error_details() const { return on_closed_frame_.error_details; } @@ -375,12 +392,6 @@ class QUIC_EXPORT_PRIVATE QuicSession QuicConnectionCloseType close_type() const { return on_closed_frame_.close_type; } - QuicIetfTransportErrorCodes transport_error_code() const { - return on_closed_frame_.transport_error_code; - } - uint16_t application_error_code() const { - return on_closed_frame_.application_error_code; - } Perspective perspective() const { return perspective_; } @@ -406,16 +417,11 @@ class QUIC_EXPORT_PRIVATE QuicSession QuicStream* GetOrCreateStream(const QuicStreamId stream_id); // Mark a stream as draining. - virtual void StreamDraining(QuicStreamId id); + void StreamDraining(QuicStreamId id, bool unidirectional); // Returns true if this stream should yield writes to another blocked stream. virtual bool ShouldYield(QuicStreamId stream_id); - // Set transmission type of next sending packets. - // TODO(b/136274541): Remove this method or or make it private after - // gfe2_reloadable_flag_quic_write_with_transmission is deprecated. - void SetTransmissionType(TransmissionType type); - // Clean up closed_streams_. void CleanUpClosedStreams(); @@ -453,16 +459,8 @@ class QUIC_EXPORT_PRIVATE QuicSession bool is_configured() const { return is_configured_; } - QuicStreamCount num_expected_unidirectional_static_streams() const { - return num_expected_unidirectional_static_streams_; - } - - // Set the number of unidirectional stream that the peer is allowed to open to - // be |max_stream| + |num_expected_static_streams_|. - void ConfigureMaxDynamicStreamsToSend(QuicStreamCount max_stream) { - config_.SetMaxUnidirectionalStreamsToSend( - max_stream + num_expected_unidirectional_static_streams_); - } + // Called to neuter crypto data of encryption |level|. + void NeuterCryptoDataOfEncryptionLevel(EncryptionLevel level); // Returns the ALPN values to negotiate on this session. virtual std::vector<std::string> GetAlpnsToOffer() const { @@ -480,7 +478,26 @@ class QUIC_EXPORT_PRIVATE QuicSession // uses TLS handshake. virtual void OnAlpnSelected(quiche::QuicheStringPiece alpn); - bool write_with_transmission() const { return write_with_transmission_; } + bool deprecate_draining_streams() const { + return deprecate_draining_streams_; + } + + bool break_close_loop() const { return break_close_loop_; } + + // Called on clients by the crypto handshaker to provide application state + // necessary for sending application data in 0-RTT. The state provided here is + // the same state that was provided to the crypto handshaker in + // QuicCryptoClientStream::OnApplicationState on a previous connection. + // Application protocols that require state to be carried over from the + // previous connection to support 0-RTT data must implement this method to + // ingest this state. For example, an HTTP/3 QuicSession would implement this + // function to process the remembered server SETTINGS frame and apply those + // SETTINGS to 0-RTT data. This function returns true if the application state + // has been successfully processed, and false if there was an error processing + // the cached state and the connection should be closed. + virtual bool SetApplicationState(ApplicationState* /*cached_state*/) { + return true; + } protected: using StreamMap = QuicSmallMap<QuicStreamId, std::unique_ptr<QuicStream>, 10>; @@ -508,6 +525,9 @@ class QUIC_EXPORT_PRIVATE QuicSession // Adds |stream| to the stream map. virtual void ActivateStream(std::unique_ptr<QuicStream> stream); + // Set transmission type of next sending packets. + void SetTransmissionType(TransmissionType type); + // Returns the stream ID for a new outgoing bidirectional/unidirectional // stream, and increments the underlying counter. QuicStreamId GetNextOutgoingBidirectionalStreamId(); @@ -530,6 +550,7 @@ class QUIC_EXPORT_PRIVATE QuicSession // Performs the work required to close |stream_id|. If |rst_sent| then a // Reset Stream frame has already been sent for this stream. + // TODO(fayang): Remove CloseStreamInner. virtual void CloseStreamInner(QuicStreamId stream_id, bool rst_sent); // When a stream is closed locally, it may not yet know how many bytes the @@ -546,6 +567,10 @@ class QUIC_EXPORT_PRIVATE QuicSession // ProcessPendingStream(). virtual bool UsesPendingStreams() const { return false; } + spdy::SpdyPriority GetSpdyPriorityofStream(QuicStreamId stream_id) const { + return write_blocked_streams_.GetSpdyPriorityofStream(stream_id); + } + StreamMap& stream_map() { return stream_map_; } const StreamMap& stream_map() const { return stream_map_; } @@ -734,10 +759,12 @@ class QUIC_EXPORT_PRIVATE QuicSession // Set of stream ids that are "draining" -- a FIN has been sent and received, // but the stream object still exists because not all the received data has // been consumed. - QuicUnorderedSet<QuicStreamId> draining_streams_; + // TODO(fayang): Remove draining_streams_ when deprecate + // quic_deprecate_draining_streams. + QuicHashSet<QuicStreamId> draining_streams_; // Set of stream ids that are waiting for acks excluding crypto stream id. - QuicUnorderedSet<QuicStreamId> streams_waiting_for_acks_; + QuicHashSet<QuicStreamId> streams_waiting_for_acks_; // TODO(fayang): Consider moving LegacyQuicStreamIdManager into // UberQuicStreamIdManager. @@ -748,11 +775,23 @@ class QUIC_EXPORT_PRIVATE QuicSession UberQuicStreamIdManager v99_streamid_manager_; // A counter for peer initiated dynamic streams which are in the stream_map_. + // TODO(fayang): Remove this when deprecating + // quic_stream_id_manager_handles_accounting. size_t num_dynamic_incoming_streams_; - // A counter for peer initiated streams which are in the draining_streams_. + // A counter for peer initiated streams which have sent and received FIN but + // waiting for application to consume data. + // TODO(fayang): Remove this when deprecating + // quic_stream_id_manager_handles_accounting. size_t num_draining_incoming_streams_; + // A counter for self initiated streams which have sent and received FIN but + // waiting for application to consume data. Only used when + // deprecate_draining_streams_ is true. + // TODO(fayang): Remove this when deprecating + // quic_stream_id_manager_handles_accounting. + size_t num_draining_outgoing_streams_; + // A counter for self initiated static streams which are in // stream_map_. size_t num_outgoing_static_streams_; @@ -763,6 +802,8 @@ class QUIC_EXPORT_PRIVATE QuicSession // A counter for peer initiated streams which are in the // locally_closed_streams_highest_offset_. + // TODO(fayang): Remove this when deprecating + // quic_stream_id_manager_handles_accounting. size_t num_locally_closed_incoming_streams_highest_offset_; // Received information for a connection close. @@ -809,14 +850,14 @@ class QUIC_EXPORT_PRIVATE QuicSession // configured and is ready for general operation. bool is_configured_; - // The number of expected static streams. - QuicStreamCount num_expected_unidirectional_static_streams_; - // If true, enables round robin scheduling. bool enable_round_robin_scheduling_; - // Latched value of gfe2_reloadable_flag_quic_write_with_transmission. - const bool write_with_transmission_; + // Latched value of quic_deprecate_draining_streams. + const bool deprecate_draining_streams_; + + // Latched value of quic_break_session_stream_close_loop. + const bool break_close_loop_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc index 4da502dc422..9d5e977d0a6 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc @@ -83,7 +83,8 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker { EXPECT_TRUE( session()->config()->FillTransportParameters(&transport_parameters)); error = session()->config()->ProcessTransportParameters( - transport_parameters, CLIENT, &error_details); + transport_parameters, CLIENT, /* is_resumption = */ false, + &error_details); } else { CryptoHandshakeMessage msg; session()->config()->ToHandshakeMessage(&msg, transport_version()); @@ -117,15 +118,16 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker { } void OnPacketDecrypted(EncryptionLevel /*level*/) override {} void OnOneRttPacketAcknowledged() override {} + void OnHandshakePacketSent() override {} void OnHandshakeDoneReceived() override {} HandshakeState GetHandshakeState() const override { return one_rtt_keys_available() ? HANDSHAKE_COMPLETE : HANDSHAKE_START; } - MOCK_METHOD0(OnCanWrite, void()); + MOCK_METHOD(void, OnCanWrite, (), (override)); bool HasPendingCryptoRetransmission() const override { return false; } - MOCK_CONST_METHOD0(HasPendingRetransmission, bool()); + MOCK_METHOD(bool, HasPendingRetransmission, (), (const, override)); private: using QuicCryptoStream::session; @@ -155,11 +157,13 @@ class TestStream : public QuicStream { void OnDataAvailable() override {} - MOCK_METHOD0(OnCanWrite, void()); - MOCK_METHOD4(RetransmitStreamData, - bool(QuicStreamOffset, QuicByteCount, bool, TransmissionType)); + MOCK_METHOD(void, OnCanWrite, (), (override)); + MOCK_METHOD(bool, + RetransmitStreamData, + (QuicStreamOffset, QuicByteCount, bool, TransmissionType), + (override)); - MOCK_CONST_METHOD0(HasPendingRetransmission, bool()); + MOCK_METHOD(bool, HasPendingRetransmission, (), (const, override)); }; class TestSession : public QuicSession { @@ -211,9 +215,9 @@ class TestSession : public QuicSession { TestStream* CreateIncomingStream(QuicStreamId id) override { // Enforce the limit on the number of open streams. - if (GetNumOpenIncomingStreams() + 1 > - max_open_incoming_bidirectional_streams() && - !VersionHasIetfQuicFrames(connection()->transport_version())) { + if (!VersionHasIetfQuicFrames(connection()->transport_version()) && + GetNumOpenIncomingStreams() + 1 > + max_open_incoming_bidirectional_streams()) { // No need to do this test for version 99; it's done by // QuicSession::GetOrCreateStream. connection()->CloseConnection( @@ -286,7 +290,10 @@ class TestSession : public QuicSession { return consumed; } - MOCK_METHOD1(OnCanCreateNewOutgoingStream, void(bool unidirectional)); + MOCK_METHOD(void, + OnCanCreateNewOutgoingStream, + (bool unidirectional), + (override)); void set_writev_consumes_all_data(bool val) { writev_consumes_all_data_ = val; @@ -1771,21 +1778,6 @@ TEST_P(QuicSessionTestServer, InvalidStreamFlowControlWindowInHandshake) { session_.OnConfigNegotiated(); } -TEST_P(QuicSessionTestServer, InvalidSessionFlowControlWindowInHandshake) { - // Test that receipt of an invalid (< default) session flow control window - // from the peer results in the connection being torn down. - const uint32_t kInvalidWindow = kMinimumFlowControlSendWindow - 1; - QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow(session_.config(), - kInvalidWindow); - if (!connection_->version().AllowsLowFlowControlLimits()) { - EXPECT_CALL(*connection_, - CloseConnection(QUIC_FLOW_CONTROL_INVALID_WINDOW, _, _)); - } else { - EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); - } - session_.OnConfigNegotiated(); -} - // Test negotiation of custom server initial flow control window. TEST_P(QuicSessionTestServer, CustomFlowControlWindow) { QuicTagVector copt; @@ -1883,7 +1875,7 @@ TEST_P(QuicSessionTestServer, DrainingStreamsDoNotCountAsOpenedOutgoing) { QuicStreamFrame data1(stream_id, true, 0, quiche::QuicheStringPiece("HT")); session_.OnStreamFrame(data1); EXPECT_CALL(session_, OnCanCreateNewOutgoingStream(false)).Times(1); - session_.StreamDraining(stream_id); + session_.StreamDraining(stream_id, /*unidirectional=*/false); } TEST_P(QuicSessionTestServer, NoPendingStreams) { @@ -1931,20 +1923,20 @@ TEST_P(QuicSessionTestServer, RstPendingStreams) { session_.OnStreamFrame(data1); EXPECT_TRUE(QuicSessionPeer::GetPendingStream(&session_, stream_id)); EXPECT_EQ(0, session_.num_incoming_streams_created()); - EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams()); + EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_)); QuicRstStreamFrame rst1(kInvalidControlFrameId, stream_id, QUIC_ERROR_PROCESSING_STREAM, 12); session_.OnRstStream(rst1); EXPECT_FALSE(QuicSessionPeer::GetPendingStream(&session_, stream_id)); EXPECT_EQ(0, session_.num_incoming_streams_created()); - EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams()); + EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_)); QuicStreamFrame data2(stream_id, false, 0, quiche::QuicheStringPiece("HT")); session_.OnStreamFrame(data2); EXPECT_FALSE(QuicSessionPeer::GetPendingStream(&session_, stream_id)); EXPECT_EQ(0, session_.num_incoming_streams_created()); - EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams()); + EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_)); } TEST_P(QuicSessionTestServer, OnFinPendingStreams) { @@ -1960,7 +1952,7 @@ TEST_P(QuicSessionTestServer, OnFinPendingStreams) { EXPECT_FALSE(QuicSessionPeer::GetPendingStream(&session_, stream_id)); EXPECT_EQ(0, session_.num_incoming_streams_created()); - EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams()); + EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_)); } TEST_P(QuicSessionTestServer, PendingStreamOnWindowUpdate) { @@ -2013,9 +2005,9 @@ TEST_P(QuicSessionTestServer, DrainingStreamsDoNotCountAsOpened) { i += QuicUtils::StreamIdDelta(connection_->transport_version())) { QuicStreamFrame data1(i, true, 0, quiche::QuicheStringPiece("HT")); session_.OnStreamFrame(data1); - EXPECT_EQ(1u, session_.GetNumOpenIncomingStreams()); - session_.StreamDraining(i); - EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams()); + EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_)); + session_.StreamDraining(i, /*unidirectional=*/false); + EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(&session_)); } } @@ -2048,6 +2040,57 @@ TEST_P(QuicSessionTestClient, AvailableBidirectionalStreamsClient) { &session_, GetNthClientInitiatedBidirectionalId(1))); } +TEST_P(QuicSessionTestClient, InvalidSessionFlowControlWindowInHandshake) { + // Test that receipt of an invalid (< default for gQUIC, < current for TLS) + // session flow control window from the peer results in the connection being + // torn down. + const uint32_t kInvalidWindow = kMinimumFlowControlSendWindow - 1; + QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow(session_.config(), + kInvalidWindow); + EXPECT_CALL(*connection_, + CloseConnection(QUIC_FLOW_CONTROL_INVALID_WINDOW, _, _)); + session_.OnConfigNegotiated(); +} + +TEST_P(QuicSessionTestClient, InvalidBidiStreamLimitInHandshake) { + // IETF QUIC only feature. + if (!VersionHasIetfQuicFrames(transport_version())) { + return; + } + QuicConfigPeer::SetReceivedMaxBidirectionalStreams( + session_.config(), kDefaultMaxStreamsPerConnection - 1); + EXPECT_CALL(*connection_, CloseConnection(QUIC_MAX_STREAMS_ERROR, _, _)); + session_.OnConfigNegotiated(); +} + +TEST_P(QuicSessionTestClient, InvalidUniStreamLimitInHandshake) { + // IETF QUIC only feature. + if (!VersionHasIetfQuicFrames(transport_version())) { + return; + } + QuicConfigPeer::SetReceivedMaxUnidirectionalStreams( + session_.config(), kDefaultMaxStreamsPerConnection - 1); + EXPECT_CALL(*connection_, CloseConnection(QUIC_MAX_STREAMS_ERROR, _, _)); + session_.OnConfigNegotiated(); +} + +TEST_P(QuicSessionTestClient, InvalidStreamFlowControlWindowInHandshake) { + // IETF QUIC only feature. + if (!VersionHasIetfQuicFrames(transport_version())) { + return; + } + session_.CreateOutgoingBidirectionalStream(); + session_.CreateOutgoingBidirectionalStream(); + QuicConfigPeer::SetReceivedInitialMaxStreamDataBytesOutgoingBidirectional( + session_.config(), kMinimumFlowControlSendWindow - 1); + + EXPECT_CALL(*connection_, CloseConnection(_, _, _)) + .WillOnce( + Invoke(connection_, &MockQuicConnection::ReallyCloseConnection)); + EXPECT_CALL(*connection_, SendConnectionClosePacket(_, _)); + session_.OnConfigNegotiated(); +} + TEST_P(QuicSessionTestClient, OnMaxStreamFrame) { if (!VersionUsesHttp3(transport_version())) { return; @@ -2387,8 +2430,14 @@ TEST_P(QuicSessionTestServer, RetransmitLostDataCausesConnectionClose) { session_.OnFrameLost(QuicFrame(frame)); // Retransmit stream data causes connection close. Stream has not sent fin // yet, so an RST is sent. - EXPECT_CALL(*stream, OnCanWrite()) - .WillOnce(Invoke(stream, &QuicStream::OnClose)); + if (session_.break_close_loop()) { + EXPECT_CALL(*stream, OnCanWrite()).WillOnce(Invoke([this, stream]() { + session_.CloseStream(stream->id()); + })); + } else { + EXPECT_CALL(*stream, OnCanWrite()) + .WillOnce(Invoke(stream, &QuicStream::OnClose)); + } if (VersionHasIetfQuicFrames(transport_version())) { // Once for the RST_STREAM, once for the STOP_SENDING EXPECT_CALL(*connection_, SendControlFrame(_)) @@ -2746,6 +2795,7 @@ TEST_P(QuicSessionTestServer, OnStopSendingForWriteClosedStream) { TestStream* stream = session_.CreateOutgoingBidirectionalStream(); QuicStreamId stream_id = stream->id(); + QuicStreamPeer::SetFinSent(stream); stream->CloseWriteSide(); EXPECT_TRUE(stream->write_side_closed()); QuicStopSendingFrame frame(1, stream_id, 123); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream.cc index 86beaef0f7b..40a67bba21c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream.cc @@ -4,6 +4,7 @@ #include "net/third_party/quiche/src/quic/core/quic_stream.h" +#include <limits> #include <string> #include "net/third_party/quiche/src/quic/core/quic_error_codes.h" @@ -29,15 +30,15 @@ namespace quic { namespace { -size_t DefaultFlowControlWindow(ParsedQuicVersion version) { +QuicByteCount DefaultFlowControlWindow(ParsedQuicVersion version) { if (!version.AllowsLowFlowControlLimits()) { return kDefaultFlowControlSendWindow; } return 0; } -size_t GetInitialStreamFlowControlWindowToSend(QuicSession* session, - QuicStreamId stream_id) { +QuicByteCount GetInitialStreamFlowControlWindowToSend(QuicSession* session, + QuicStreamId stream_id) { ParsedQuicVersion version = session->connection()->version(); if (version.handshake_protocol != PROTOCOL_TLS1_3) { return session->config()->GetInitialStreamFlowControlWindowToSend(); @@ -60,8 +61,8 @@ size_t GetInitialStreamFlowControlWindowToSend(QuicSession* session, ->GetInitialMaxStreamDataBytesIncomingBidirectionalToSend(); } -size_t GetReceivedFlowControlWindow(QuicSession* session, - QuicStreamId stream_id) { +QuicByteCount GetReceivedFlowControlWindow(QuicSession* session, + QuicStreamId stream_id) { ParsedQuicVersion version = session->connection()->version(); if (version.handshake_protocol != PROTOCOL_TLS1_3) { if (session->config()->HasReceivedInitialStreamFlowControlWindowBytes()) { @@ -189,7 +190,7 @@ void PendingStream::OnStreamFrame(const QuicStreamFrame& frame) { } // This count includes duplicate data received. - size_t frame_payload_size = frame.data_length; + QuicByteCount frame_payload_size = frame.data_length; stream_bytes_read_ += frame_payload_size; // Flow control is interested in tracking highest received offset. @@ -257,7 +258,7 @@ bool PendingStream::MaybeIncreaseHighestReceivedOffset( return true; } -void PendingStream::MarkConsumed(size_t num_bytes) { +void PendingStream::MarkConsumed(QuicByteCount num_bytes) { sequencer_.MarkConsumed(num_bytes); } @@ -353,6 +354,7 @@ QuicStream::QuicStream(QuicStreamId id, buffered_data_threshold_(GetQuicFlag(FLAGS_quic_buffered_data_threshold)), is_static_(is_static), deadline_(QuicTime::Zero()), + was_draining_(false), type_(VersionHasIetfQuicFrames(session->transport_version()) && type != CRYPTO ? QuicUtils::GetStreamType(id_, @@ -361,10 +363,10 @@ QuicStream::QuicStream(QuicStreamId id, : type), perspective_(session->perspective()) { if (type_ == WRITE_UNIDIRECTIONAL) { - set_fin_received(true); + fin_received_ = true; CloseReadSide(); } else if (type_ == READ_UNIDIRECTIONAL) { - set_fin_sent(true); + fin_sent_ = true; CloseWriteSide(); } if (type_ != CRYPTO) { @@ -431,9 +433,14 @@ void QuicStream::OnStreamFrame(const QuicStreamFrame& frame) { } if (frame.fin) { - fin_received_ = true; - if (fin_sent_) { - session_->StreamDraining(id_); + if (!session_->deprecate_draining_streams() || !fin_received_) { + fin_received_ = true; + if (fin_sent_) { + DCHECK(!was_draining_ || !session_->deprecate_draining_streams()); + session_->StreamDraining(id_, + /*unidirectional=*/type_ != BIDIRECTIONAL); + was_draining_ = true; + } } } @@ -446,7 +453,7 @@ void QuicStream::OnStreamFrame(const QuicStreamFrame& frame) { } // This count includes duplicate data received. - size_t frame_payload_size = frame.data_length; + QuicByteCount frame_payload_size = frame.data_length; stream_bytes_read_ += frame_payload_size; // Flow control is interested in tracking highest received offset. @@ -455,7 +462,10 @@ void QuicStream::OnStreamFrame(const QuicStreamFrame& frame) { MaybeIncreaseHighestReceivedOffset(frame.offset + frame_payload_size)) { // As the highest received offset has changed, check to see if this is a // violation of flow control. - if (flow_controller_->FlowControlViolation() || + QUIC_BUG_IF(!flow_controller_.has_value()) + << ENDPOINT << "OnStreamFrame called on stream without flow control"; + if ((flow_controller_.has_value() && + flow_controller_->FlowControlViolation()) || connection_flow_controller_->FlowControlViolation()) { OnUnrecoverableError(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, "Flow control violation after increasing offset"); @@ -519,7 +529,10 @@ void QuicStream::OnStreamReset(const QuicRstStreamFrame& frame) { } MaybeIncreaseHighestReceivedOffset(frame.byte_offset); - if (flow_controller_->FlowControlViolation() || + QUIC_BUG_IF(!flow_controller_.has_value()) + << ENDPOINT << "OnStreamReset called on stream without flow control"; + if ((flow_controller_.has_value() && + flow_controller_->FlowControlViolation()) || connection_flow_controller_->FlowControlViolation()) { OnUnrecoverableError(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, "Flow control violation after increasing offset"); @@ -560,11 +573,23 @@ void QuicStream::OnFinRead() { CloseReadSide(); } +void QuicStream::SetFinSent() { + DCHECK(!VersionUsesHttp3(transport_version())); + fin_sent_ = true; +} + void QuicStream::Reset(QuicRstStreamErrorCode error) { stream_error_ = error; - // Sending a RstStream results in calling CloseStream. session()->SendRstStream(id(), error, stream_bytes_written()); rst_sent_ = true; + if (session_->break_close_loop()) { + if (read_side_closed_ && write_side_closed_ && !IsWaitingForAcks()) { + session()->OnStreamDoneWaitingForAcks(id_); + return; + } + CloseReadSide(); + CloseWriteSide(); + } } void QuicStream::OnUnrecoverableError(QuicErrorCode error, @@ -660,6 +685,11 @@ void QuicStream::OnCanWrite() { } void QuicStream::MaybeSendBlocked() { + if (!flow_controller_.has_value()) { + QUIC_BUG << ENDPOINT + << "MaybeSendBlocked called on stream without flow control"; + return; + } if (flow_controller_->ShouldSendBlocked()) { session_->SendBlocked(id_); } @@ -751,7 +781,12 @@ void QuicStream::CloseReadSide() { if (write_side_closed_) { QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << id(); - session_->CloseStream(id()); + if (session_->break_close_loop()) { + session_->OnStreamClosed(id()); + OnClose(); + } else { + session_->CloseStream(id()); + } } } @@ -764,7 +799,12 @@ void QuicStream::CloseWriteSide() { write_side_closed_ = true; if (read_side_closed_) { QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << id(); - session_->CloseStream(id()); + if (session_->break_close_loop()) { + session_->OnStreamClosed(id()); + OnClose(); + } else { + session_->CloseStream(id()); + } } } @@ -787,8 +827,12 @@ void QuicStream::StopReading() { } void QuicStream::OnClose() { - CloseReadSide(); - CloseWriteSide(); + if (session()->break_close_loop()) { + DCHECK(read_side_closed_ && write_side_closed_); + } else { + CloseReadSide(); + CloseWriteSide(); + } if (!fin_sent_ && !rst_sent_) { // For flow control accounting, tell the peer how many bytes have been @@ -801,7 +845,8 @@ void QuicStream::OnClose() { rst_sent_ = true; } - if (flow_controller_->FlowControlViolation() || + if (!flow_controller_.has_value() || + flow_controller_->FlowControlViolation() || connection_flow_controller_->FlowControlViolation()) { return; } @@ -823,6 +868,12 @@ void QuicStream::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) { return; } + if (!flow_controller_.has_value()) { + QUIC_BUG << ENDPOINT + << "OnWindowUpdateFrame called on stream without flow control"; + return; + } + if (flow_controller_->UpdateSendWindowOffset(frame.max_data)) { // Let session unblock this stream. session_->MarkConnectionLevelWriteBlocked(id_); @@ -831,6 +882,12 @@ void QuicStream::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) { bool QuicStream::MaybeIncreaseHighestReceivedOffset( QuicStreamOffset new_offset) { + if (!flow_controller_.has_value()) { + QUIC_BUG << ENDPOINT + << "MaybeIncreaseHighestReceivedOffset called on stream without " + "flow control"; + return false; + } uint64_t increment = new_offset - flow_controller_->highest_received_byte_offset(); if (!flow_controller_->UpdateHighestReceivedOffset(new_offset)) { @@ -849,6 +906,11 @@ bool QuicStream::MaybeIncreaseHighestReceivedOffset( } void QuicStream::AddBytesSent(QuicByteCount bytes) { + if (!flow_controller_.has_value()) { + QUIC_BUG << ENDPOINT + << "AddBytesSent called on stream without flow control"; + return; + } flow_controller_->AddBytesSent(bytes); if (stream_contributes_to_connection_flow_control_) { connection_flow_controller_->AddBytesSent(bytes); @@ -862,6 +924,12 @@ void QuicStream::AddBytesConsumed(QuicByteCount bytes) { // QuicStreamSequencers used by QuicCryptoStream. return; } + if (!flow_controller_.has_value()) { + QUIC_BUG + << ENDPOINT + << "AddBytesConsumed called on non-crypto stream without flow control"; + return; + } // Only adjust stream level flow controller if still reading. if (!read_side_closed_) { flow_controller_->AddBytesConsumed(bytes); @@ -872,11 +940,27 @@ void QuicStream::AddBytesConsumed(QuicByteCount bytes) { } } -void QuicStream::UpdateSendWindowOffset(QuicStreamOffset new_window) { - if (flow_controller_->UpdateSendWindowOffset(new_window)) { +bool QuicStream::ConfigSendWindowOffset(QuicStreamOffset new_offset) { + if (!flow_controller_.has_value()) { + QUIC_BUG << ENDPOINT + << "ConfigSendWindowOffset called on stream without flow control"; + return false; + } + if (perspective_ == Perspective::IS_CLIENT && + session()->version().AllowsLowFlowControlLimits() && + new_offset < flow_controller_->send_window_offset()) { + OnUnrecoverableError( + QUIC_FLOW_CONTROL_INVALID_WINDOW, + quiche::QuicheStrCat("New stream max data ", new_offset, + " decreases current limit: ", + flow_controller_->send_window_offset())); + return false; + } + if (flow_controller_->UpdateSendWindowOffset(new_offset)) { // Let session unblock this stream. session_->MarkConnectionLevelWriteBlocked(id_); } + return true; } void QuicStream::AddRandomPaddingAfterFin() { @@ -999,7 +1083,7 @@ bool QuicStream::IsWaitingForAcks() const { (send_buffer_.stream_bytes_outstanding() || fin_outstanding_); } -size_t QuicStream::ReadableBytes() const { +QuicByteCount QuicStream::ReadableBytes() const { return sequencer_.ReadableBytes(); } @@ -1021,7 +1105,7 @@ void QuicStream::WriteBufferedData() { } // Size of buffered data. - size_t write_length = BufferedDataBytes(); + QuicByteCount write_length = BufferedDataBytes(); // A FIN with zero data payload should not be flow control blocked. bool fin_with_zero_data = (fin_buffered_ && write_length == 0); @@ -1029,7 +1113,14 @@ void QuicStream::WriteBufferedData() { bool fin = fin_buffered_; // How much data flow control permits to be written. - QuicByteCount send_window = flow_controller_->SendWindowSize(); + QuicByteCount send_window; + if (flow_controller_.has_value()) { + send_window = flow_controller_->SendWindowSize(); + } else { + send_window = std::numeric_limits<QuicByteCount>::max(); + QUIC_BUG << ENDPOINT + << "WriteBufferedData called on stream without flow control"; + } if (stream_contributes_to_connection_flow_control_) { send_window = std::min(send_window, connection_flow_controller_->SendWindowSize()); @@ -1046,13 +1137,10 @@ void QuicStream::WriteBufferedData() { fin = false; // Writing more data would be a violation of flow control. - write_length = static_cast<size_t>(send_window); + write_length = send_window; QUIC_DVLOG(1) << "stream " << id() << " shortens write length to " << write_length << " due to flow control"; } - if (!session_->write_with_transmission()) { - session_->SetTransmissionType(NOT_RETRANSMISSION); - } StreamSendingState state = fin ? FIN : NO_FIN; if (fin && add_random_padding_after_fin_) { @@ -1082,10 +1170,14 @@ void QuicStream::WriteBufferedData() { MaybeSendBlocked(); } if (fin && consumed_data.fin_consumed) { + DCHECK(!fin_sent_); fin_sent_ = true; fin_outstanding_ = true; if (fin_received_) { - session_->StreamDraining(id_); + DCHECK(!was_draining_); + session_->StreamDraining(id_, + /*unidirectional=*/type_ != BIDIRECTIONAL); + was_draining_ = true; } CloseWriteSide(); } else if (fin && !consumed_data.fin_consumed) { @@ -1124,7 +1216,7 @@ const QuicIntervalSet<QuicStreamOffset>& QuicStream::bytes_acked() const { return send_buffer_.bytes_acked(); } -void QuicStream::OnStreamDataConsumed(size_t bytes_consumed) { +void QuicStream::OnStreamDataConsumed(QuicByteCount bytes_consumed) { send_buffer_.OnStreamDataConsumed(bytes_consumed); } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream.h b/chromium/net/third_party/quiche/src/quic/core/quic_stream.h index aa2e11d5a60..fe9d04c021f 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream.h @@ -76,7 +76,7 @@ class QUIC_EXPORT_PRIVATE PendingStream const QuicStreamSequencer* sequencer() const { return &sequencer_; } - void MarkConsumed(size_t num_bytes); + void MarkConsumed(QuicByteCount num_bytes); // Tells the sequencer to ignore all incoming data itself and not call // OnDataAvailable(). @@ -165,10 +165,12 @@ class QUIC_EXPORT_PRIVATE QuicStream // stream to write any pending data. virtual void OnCanWrite(); - // Called by the session just before the object is destroyed. + // Called just before the object is destroyed. // The object should not be accessed after OnClose is called. // Sends a RST_STREAM with code QUIC_RST_ACKNOWLEDGEMENT if neither a FIN nor // a RST_STREAM has been sent. + // TODO(fayang): move this to protected when deprecating + // quic_break_session_stream_close_loop. virtual void OnClose(); // Called by the session when the endpoint receives a RST_STREAM from the @@ -199,7 +201,7 @@ class QUIC_EXPORT_PRIVATE QuicStream bool IsWaitingForAcks() const; // Number of bytes available to read. - size_t ReadableBytes() const; + QuicByteCount ReadableBytes() const; QuicRstStreamErrorCode stream_error() const { return stream_error_; } QuicErrorCode connection_error() const { return connection_error_; } @@ -224,8 +226,6 @@ class QUIC_EXPORT_PRIVATE QuicStream size_t busy_counter() const { return busy_counter_; } void set_busy_counter(size_t busy_counter) { busy_counter_ = busy_counter; } - void set_fin_sent(bool fin_sent) { fin_sent_ = fin_sent; } - void set_fin_received(bool fin_received) { fin_received_ = fin_received; } void set_rst_sent(bool rst_sent) { rst_sent_ = rst_sent; } void set_rst_received(bool rst_received) { rst_received_ = rst_received; } @@ -244,9 +244,8 @@ class QUIC_EXPORT_PRIVATE QuicStream // Returns true if the highest offset did increase. bool MaybeIncreaseHighestReceivedOffset(QuicStreamOffset new_offset); - // Updates the flow controller's send window offset and calls OnCanWrite if - // it was blocked before. - void UpdateSendWindowOffset(QuicStreamOffset new_offset); + // Set the flow controller's send window offset from session config. + bool ConfigSendWindowOffset(QuicStreamOffset new_offset); // Returns true if the stream has received either a RST_STREAM or a FIN - // either of which gives a definitive number of bytes which the peer has @@ -357,19 +356,23 @@ class QUIC_EXPORT_PRIVATE QuicStream // Does not send a FIN. May cause the stream to be closed. virtual void CloseWriteSide(); + // Close the read side of the stream. May cause the stream to be closed. + // Subclasses and consumers should use StopReading to terminate reading early + // if expecting a FIN. Can be used directly by subclasses if not expecting a + // FIN. + // TODO(fayang): move this to protected when removing + // QuicSession::CloseStream. + void CloseReadSide(); + // Returns true if the stream is static. bool is_static() const { return is_static_; } + bool was_draining() const { return was_draining_; } + static spdy::SpdyStreamPrecedence CalculateDefaultPriority( const QuicSession* session); protected: - // Close the read side of the socket. May cause the stream to be closed. - // Subclasses and consumers should use StopReading to terminate reading early - // if expecting a FIN. Can be used directly by subclasses if not expecting a - // FIN. - void CloseReadSide(); - // Called when data of [offset, offset + data_length] is buffered in send // buffer. virtual void OnDataBuffered( @@ -389,7 +392,7 @@ class QUIC_EXPORT_PRIVATE QuicStream virtual void OnCanWriteNewData() {} // Called when |bytes_consumed| bytes has been consumed. - virtual void OnStreamDataConsumed(size_t bytes_consumed); + virtual void OnStreamDataConsumed(QuicByteCount bytes_consumed); // Called by the stream sequencer as bytes are consumed from the buffer. // If the receive window has dropped below the threshold, then send a @@ -403,6 +406,10 @@ class QUIC_EXPORT_PRIVATE QuicStream // this virtual so that subclasses can implement their own logics. virtual void OnDeadlinePassed(); + // Called to set fin_sent_. This is only used by Google QUIC while body is + // empty. + void SetFinSent(); + StreamDelegateInterface* stream_delegate() { return stream_delegate_; } bool fin_buffered() const { return fin_buffered_; } @@ -532,6 +539,10 @@ class QUIC_EXPORT_PRIVATE QuicStream // If initialized, reset this stream at this deadline. QuicTime deadline_; + // True if this stream has entered draining state. Only used when + // quic_deprecate_draining_streams is true. + bool was_draining_; + // Indicates whether this stream is bidirectional, read unidirectional or // write unidirectional. const StreamType type_; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.cc index c6869a23b12..ba31decd2b9 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.cc @@ -10,6 +10,7 @@ #include "net/third_party/quiche/src/quic/core/quic_constants.h" #include "net/third_party/quiche/src/quic/core/quic_session.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/core/quic_versions.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" @@ -24,40 +25,31 @@ QuicStreamIdManager::QuicStreamIdManager( DelegateInterface* delegate, bool unidirectional, Perspective perspective, - QuicTransportVersion transport_version, + ParsedQuicVersion version, QuicStreamCount max_allowed_outgoing_streams, QuicStreamCount max_allowed_incoming_streams) : delegate_(delegate), unidirectional_(unidirectional), perspective_(perspective), - transport_version_(transport_version), + version_(version), outgoing_max_streams_(max_allowed_outgoing_streams), next_outgoing_stream_id_(GetFirstOutgoingStreamId()), outgoing_stream_count_(0), incoming_actual_max_streams_(max_allowed_incoming_streams), - // Advertised max starts at actual because it's communicated in the - // handshake. incoming_advertised_max_streams_(max_allowed_incoming_streams), incoming_initial_max_open_streams_(max_allowed_incoming_streams), incoming_stream_count_(0), largest_peer_created_stream_id_( - QuicUtils::GetInvalidStreamId(transport_version)), - max_streams_window_(0) { - CalculateIncomingMaxStreamsWindow(); -} + QuicUtils::GetInvalidStreamId(version.transport_version)) {} QuicStreamIdManager::~QuicStreamIdManager() {} -// The peer sends a streams blocked frame when it can not open any more -// streams because it has runs into the limit. bool QuicStreamIdManager::OnStreamsBlockedFrame( const QuicStreamsBlockedFrame& frame, std::string* error_details) { - // Ensure that the frame has the correct directionality. DCHECK_EQ(frame.unidirectional, unidirectional_); if (frame.stream_count > incoming_advertised_max_streams_) { // Peer thinks it can send more streams that we've told it. - // This is a protocol error. *error_details = quiche::QuicheStrCat( "StreamsBlockedFrame's stream count ", frame.stream_count, " exceeds incoming max stream ", incoming_advertised_max_streams_); @@ -65,8 +57,7 @@ bool QuicStreamIdManager::OnStreamsBlockedFrame( } if (frame.stream_count < incoming_actual_max_streams_) { // Peer thinks it's blocked on a stream count that is less than our current - // max. Inform the peer of the correct stream count. Sending a MAX_STREAMS - // frame in this case is not controlled by the window. + // max. Inform the peer of the correct stream count. SendMaxStreamsFrame(); } return true; @@ -90,8 +81,9 @@ bool QuicStreamIdManager::MaybeAllowNewOutgoingStreams( void QuicStreamIdManager::SetMaxOpenIncomingStreams( QuicStreamCount max_open_streams) { QUIC_BUG_IF(incoming_stream_count_ > 0) - << "non-zero stream count when setting max incoming stream."; - QUIC_LOG_IF(WARNING, incoming_initial_max_open_streams_ != max_open_streams) + << "non-zero incoming stream count " << incoming_stream_count_ + << " when setting max incoming stream to " << max_open_streams; + QUIC_DLOG_IF(WARNING, incoming_initial_max_open_streams_ != max_open_streams) << quiche::QuicheStrCat( unidirectional_ ? "unidirectional " : "bidirectional: ", "incoming stream limit changed from ", @@ -99,12 +91,12 @@ void QuicStreamIdManager::SetMaxOpenIncomingStreams( incoming_actual_max_streams_ = max_open_streams; incoming_advertised_max_streams_ = max_open_streams; incoming_initial_max_open_streams_ = max_open_streams; - CalculateIncomingMaxStreamsWindow(); } void QuicStreamIdManager::MaybeSendMaxStreamsFrame() { if ((incoming_advertised_max_streams_ - incoming_stream_count_) > - max_streams_window_) { + (incoming_initial_max_open_streams_ / + GetQuicFlag(FLAGS_quic_max_streams_window_divisor))) { // window too large, no advertisement return; } @@ -118,39 +110,36 @@ void QuicStreamIdManager::SendMaxStreamsFrame() { void QuicStreamIdManager::OnStreamClosed(QuicStreamId stream_id) { DCHECK_NE(QuicUtils::IsBidirectionalStreamId(stream_id), unidirectional_); - if (!IsIncomingStream(stream_id)) { + if (QuicUtils::IsOutgoingStreamId(version_, stream_id, perspective_)) { // Nothing to do for outgoing streams. return; } // If the stream is inbound, we can increase the actual stream limit and maybe - // advertise the new limit to the peer. Have to check to make sure that we do - // not exceed the maximum. + // advertise the new limit to the peer. if (incoming_actual_max_streams_ == QuicUtils::GetMaxStreamCount()) { // Reached the maximum stream id value that the implementation // supports. Nothing can be done here. return; } - // One stream closed ... another can be opened. + // One stream closed, and another one can be opened. incoming_actual_max_streams_++; MaybeSendMaxStreamsFrame(); } QuicStreamId QuicStreamIdManager::GetNextOutgoingStreamId() { - // Applications should always consult CanOpenNextOutgoingStream() first. - // If they ask for stream ids that violate the limit, it's an implementation - // bug. QUIC_BUG_IF(outgoing_stream_count_ >= outgoing_max_streams_) << "Attempt to allocate a new outgoing stream that would exceed the " "limit (" << outgoing_max_streams_ << ")"; QuicStreamId id = next_outgoing_stream_id_; - next_outgoing_stream_id_ += QuicUtils::StreamIdDelta(transport_version_); + next_outgoing_stream_id_ += + QuicUtils::StreamIdDelta(version_.transport_version); outgoing_stream_count_++; return id; } bool QuicStreamIdManager::CanOpenNextOutgoingStream() const { - DCHECK(VersionHasIetfQuicFrames(transport_version_)); + DCHECK(VersionHasIetfQuicFrames(version_.transport_version)); return outgoing_stream_count_ < outgoing_max_streams_; } @@ -159,23 +148,25 @@ bool QuicStreamIdManager::MaybeIncreaseLargestPeerStreamId( std::string* error_details) { // |stream_id| must be an incoming stream of the right directionality. DCHECK_NE(QuicUtils::IsBidirectionalStreamId(stream_id), unidirectional_); - DCHECK_NE(QuicUtils::IsServerInitiatedStreamId(transport_version_, stream_id), - perspective() == Perspective::IS_SERVER); + DCHECK_NE(QuicUtils::IsServerInitiatedStreamId(version_.transport_version, + stream_id), + perspective_ == Perspective::IS_SERVER); if (available_streams_.erase(stream_id) == 1) { // stream_id is available. return true; } if (largest_peer_created_stream_id_ != - QuicUtils::GetInvalidStreamId(transport_version_)) { + QuicUtils::GetInvalidStreamId(version_.transport_version)) { DCHECK_GT(stream_id, largest_peer_created_stream_id_); } // Calculate increment of incoming_stream_count_ by creating stream_id. - const QuicStreamCount delta = QuicUtils::StreamIdDelta(transport_version_); + const QuicStreamCount delta = + QuicUtils::StreamIdDelta(version_.transport_version); const QuicStreamId least_new_stream_id = largest_peer_created_stream_id_ == - QuicUtils::GetInvalidStreamId(transport_version_) + QuicUtils::GetInvalidStreamId(version_.transport_version) ? GetFirstIncomingStreamId() : largest_peer_created_stream_id_ + delta; const QuicStreamCount stream_count_increment = @@ -203,59 +194,36 @@ bool QuicStreamIdManager::MaybeIncreaseLargestPeerStreamId( bool QuicStreamIdManager::IsAvailableStream(QuicStreamId id) const { DCHECK_NE(QuicUtils::IsBidirectionalStreamId(id), unidirectional_); - if (!IsIncomingStream(id)) { + if (QuicUtils::IsOutgoingStreamId(version_, id, perspective_)) { // Stream IDs under next_ougoing_stream_id_ are either open or previously // open but now closed. return id >= next_outgoing_stream_id_; } // For peer created streams, we also need to consider available streams. return largest_peer_created_stream_id_ == - QuicUtils::GetInvalidStreamId(transport_version_) || + QuicUtils::GetInvalidStreamId(version_.transport_version) || id > largest_peer_created_stream_id_ || QuicContainsKey(available_streams_, id); } -bool QuicStreamIdManager::IsIncomingStream(QuicStreamId id) const { - DCHECK_NE(QuicUtils::IsBidirectionalStreamId(id), unidirectional_); - // The 0x1 bit in the stream id indicates whether the stream id is - // server- or client- initiated. Next_OUTGOING_stream_id_ has that bit - // set based on whether this node is a server or client. Thus, if the stream - // id in question has the 0x1 bit set opposite of next_OUTGOING_stream_id_, - // then that stream id is incoming -- it is for streams initiated by the peer. - return (id & 0x1) != (next_outgoing_stream_id_ & 0x1); -} - QuicStreamId QuicStreamIdManager::GetFirstOutgoingStreamId() const { return (unidirectional_) ? QuicUtils::GetFirstUnidirectionalStreamId( - transport_version_, perspective()) + version_.transport_version, perspective_) : QuicUtils::GetFirstBidirectionalStreamId( - transport_version_, perspective()); + version_.transport_version, perspective_); } QuicStreamId QuicStreamIdManager::GetFirstIncomingStreamId() const { return (unidirectional_) ? QuicUtils::GetFirstUnidirectionalStreamId( - transport_version_, peer_perspective()) + version_.transport_version, + QuicUtils::InvertPerspective(perspective_)) : QuicUtils::GetFirstBidirectionalStreamId( - transport_version_, peer_perspective()); -} - -Perspective QuicStreamIdManager::perspective() const { - return perspective_; + version_.transport_version, + QuicUtils::InvertPerspective(perspective_)); } -Perspective QuicStreamIdManager::peer_perspective() const { - return QuicUtils::InvertPerspective(perspective()); -} - -QuicStreamCount QuicStreamIdManager::available_incoming_streams() { +QuicStreamCount QuicStreamIdManager::available_incoming_streams() const { return incoming_advertised_max_streams_ - incoming_stream_count_; } -void QuicStreamIdManager::CalculateIncomingMaxStreamsWindow() { - max_streams_window_ = incoming_actual_max_streams_ / kMaxStreamsWindowDivisor; - if (max_streams_window_ == 0) { - max_streams_window_ = 1; - } -} - } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.h index fa4b1a06b47..9e6ef20112a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.h @@ -17,16 +17,7 @@ class QuicSessionPeer; class QuicStreamIdManagerPeer; } // namespace test -// Amount to increment a stream ID value to get the next stream ID in -// the stream ID space. -const QuicStreamId kV99StreamIdIncrement = 4; - -// This constant controls the size of the window when deciding whether -// to generate a MAX_STREAMS frame or not. See the discussion of the -// window, below, for more details. -const int kMaxStreamsWindowDivisor = 2; - -// This class manages the stream ids for Version 99/IETF QUIC. +// This class manages the stream ids for IETF QUIC. class QUIC_EXPORT_PRIVATE QuicStreamIdManager { public: class QUIC_EXPORT_PRIVATE DelegateInterface { @@ -41,7 +32,7 @@ class QUIC_EXPORT_PRIVATE QuicStreamIdManager { QuicStreamIdManager(DelegateInterface* delegate, bool unidirectional, Perspective perspective, - QuicTransportVersion transport_version, + ParsedQuicVersion version, QuicStreamCount max_allowed_outgoing_streams, QuicStreamCount max_allowed_incoming_streams); @@ -52,7 +43,7 @@ class QUIC_EXPORT_PRIVATE QuicStreamIdManager { std::string DebugString() const { return quiche::QuicheStrCat( " { unidirectional_: ", unidirectional_, - ", perspective: ", perspective(), + ", perspective: ", perspective_, ", outgoing_max_streams_: ", outgoing_max_streams_, ", next_outgoing_stream_id_: ", next_outgoing_stream_id_, ", outgoing_stream_count_: ", outgoing_stream_count_, @@ -62,7 +53,7 @@ class QUIC_EXPORT_PRIVATE QuicStreamIdManager { ", incoming_stream_count_: ", incoming_stream_count_, ", available_streams_.size(): ", available_streams_.size(), ", largest_peer_created_stream_id_: ", largest_peer_created_stream_id_, - ", max_streams_window_: ", max_streams_window_, " }"); + " }"); } // Processes the STREAMS_BLOCKED frame. If error is encountered, populates @@ -70,7 +61,7 @@ class QUIC_EXPORT_PRIVATE QuicStreamIdManager { bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame, std::string* error_details); - // Indicates whether the next outgoing stream ID can be allocated or not. + // Returns whether the next outgoing stream ID can be allocated or not. bool CanOpenNextOutgoingStream() const; // Generate and send a MAX_STREAMS frame. @@ -83,8 +74,7 @@ class QUIC_EXPORT_PRIVATE QuicStreamIdManager { void OnStreamClosed(QuicStreamId stream_id); // Returns the next outgoing stream id. Applications must call - // CanOpenNextOutgoingStream() first. A QUIC_BUG is logged if this method - // allocates a stream ID past the peer specified limit. + // CanOpenNextOutgoingStream() first. QuicStreamId GetNextOutgoingStreamId(); void SetMaxOpenIncomingStreams(QuicStreamCount max_open_streams); @@ -95,42 +85,28 @@ class QUIC_EXPORT_PRIVATE QuicStreamIdManager { bool MaybeAllowNewOutgoingStreams(QuicStreamCount max_open_streams); // Checks if the incoming stream ID exceeds the MAX_STREAMS limit. If the - // limit is exceeded, populates |error_detials| and returns false. Uses the - // actual maximium, not the most recently advertised value, in order to - // enforce the Google-QUIC number of open streams behavior. - // This method should be called exactly once for each incoming stream - // creation. + // limit is exceeded, populates |error_detials| and returns false. bool MaybeIncreaseLargestPeerStreamId(const QuicStreamId stream_id, std::string* error_details); // Returns true if |id| is still available. bool IsAvailableStream(QuicStreamId id) const; - // Return true if given stream is peer initiated. - bool IsIncomingStream(QuicStreamId id) const; - QuicStreamCount incoming_initial_max_open_streams() const { return incoming_initial_max_open_streams_; } - QuicStreamCount max_streams_window() const { return max_streams_window_; } - QuicStreamId next_outgoing_stream_id() const { return next_outgoing_stream_id_; } // Number of streams that the peer believes that it can still create. - QuicStreamCount available_incoming_streams(); + QuicStreamCount available_incoming_streams() const; QuicStreamId largest_peer_created_stream_id() const { return largest_peer_created_stream_id_; } - // These are the limits for outgoing and incoming streams, - // respectively. For incoming there are two limits, what has - // been advertised to the peer and what is actually available. - // The advertised incoming amount should never be more than the actual - // incoming one. QuicStreamCount outgoing_max_streams() const { return outgoing_max_streams_; } QuicStreamCount incoming_actual_max_streams() const { return incoming_actual_max_streams_; @@ -138,13 +114,9 @@ class QUIC_EXPORT_PRIVATE QuicStreamIdManager { QuicStreamCount incoming_advertised_max_streams() const { return incoming_advertised_max_streams_; } - // Number of streams that have been opened (including those that have been - // opened and then closed. Must never exceed outgoing_max_streams - QuicStreamCount outgoing_stream_count() { return outgoing_stream_count_; } - - // Perspective (CLIENT/SERVER) of this node and the peer, respectively. - Perspective perspective() const; - Perspective peer_perspective() const; + QuicStreamCount outgoing_stream_count() const { + return outgoing_stream_count_; + } private: friend class test::QuicSessionPeer; @@ -160,10 +132,7 @@ class QUIC_EXPORT_PRIVATE QuicStreamIdManager { QuicStreamId GetFirstOutgoingStreamId() const; QuicStreamId GetFirstIncomingStreamId() const; - void CalculateIncomingMaxStreamsWindow(); - // Back reference to the session containing this Stream ID Manager. - // needed to access various session methods, such as perspective() DelegateInterface* delegate_; // Whether this stream id manager is for unidrectional (true) or bidirectional @@ -173,14 +142,12 @@ class QUIC_EXPORT_PRIVATE QuicStreamIdManager { // Is this manager a client or a server. const Perspective perspective_; - // Transport version used for this manager. - const QuicTransportVersion transport_version_; + // QUIC version used for this manager. + const ParsedQuicVersion version_; - // This is the number of streams that this node can initiate. - // This limit is: - // - Initiated to a value specified in the constructor - // - May be updated when the config is received. - // - Is updated whenever a MAX STREAMS frame is received. + // The number of streams that this node can initiate. + // This limit is first set when config is negotiated, but may be updated upon + // receiving MAX_STREAMS frame. QuicStreamCount outgoing_max_streams_; // The ID to use for the next outgoing stream. @@ -193,31 +160,25 @@ class QUIC_EXPORT_PRIVATE QuicStreamIdManager { // FOR INCOMING STREAMS - // The maximum number of streams that can be opened by the peer. + // The actual maximum number of streams that can be opened by the peer. QuicStreamCount incoming_actual_max_streams_; + // Max incoming stream number that has been advertised to the peer and is <= + // incoming_actual_max_streams_. It is set to incoming_actual_max_streams_ + // when a MAX_STREAMS is sent. QuicStreamCount incoming_advertised_max_streams_; // Initial maximum on the number of open streams allowed. QuicStreamCount incoming_initial_max_open_streams_; - // This is the number of streams that have been created -- some are still - // open, the others have been closed. It is the number that is compared - // against MAX_STREAMS when deciding whether to accept a new stream or not. + // The number of streams that have been created, including open ones and + // closed ones. QuicStreamCount incoming_stream_count_; // Set of stream ids that are less than the largest stream id that has been // received, but are nonetheless available to be created. - QuicUnorderedSet<QuicStreamId> available_streams_; + QuicHashSet<QuicStreamId> available_streams_; QuicStreamId largest_peer_created_stream_id_; - - // When incoming streams close the local node sends MAX_STREAMS frames. It - // does so only when the peer can open fewer than |max_stream_id_window_| - // streams. That is, when |incoming_actual_max_streams_| - - // |incoming_advertised_max_streams_| is less than the window. - // max_streams_window_ is set to 1/2 of the initial number of incoming streams - // that are allowed (as set in the constructor). - QuicStreamId max_streams_window_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager_test.cc index 3207e59558b..2179ba2c860 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager_test.cc @@ -24,8 +24,10 @@ namespace { class MockDelegate : public QuicStreamIdManager::DelegateInterface { public: - MOCK_METHOD2(SendMaxStreams, - void(QuicStreamCount stream_count, bool unidirectional)); + MOCK_METHOD(void, + SendMaxStreams, + (QuicStreamCount stream_count, bool unidirectional), + (override)); }; struct TestParams { @@ -71,7 +73,7 @@ class QuicStreamIdManagerTest : public QuicTestWithParam<TestParams> { : stream_id_manager_(&delegate_, IsUnidirectional(), perspective(), - transport_version(), + GetParam().version, 0, kDefaultMaxStreamsPerConnection) { DCHECK(VersionHasIetfQuicFrames(transport_version())); @@ -84,7 +86,7 @@ class QuicStreamIdManagerTest : public QuicTestWithParam<TestParams> { // Returns the stream ID for the Nth incoming stream (created by the peer) // of the corresponding directionality of this manager. QuicStreamId GetNthIncomingStreamId(int n) { - return kV99StreamIdIncrement * n + + return QuicUtils::StreamIdDelta(transport_version()) * n + (IsUnidirectional() ? QuicUtils::GetFirstUnidirectionalStreamId( transport_version(), @@ -115,11 +117,6 @@ TEST_P(QuicStreamIdManagerTest, Initialization) { stream_id_manager_.incoming_advertised_max_streams()); EXPECT_EQ(kDefaultMaxStreamsPerConnection, stream_id_manager_.incoming_initial_max_open_streams()); - - // The window for advertising updates to the MAX STREAM ID is half the number - // of streams allowed. - EXPECT_EQ(kDefaultMaxStreamsPerConnection / 2, - stream_id_manager_.max_streams_window()); } // This test checks that the stream advertisement window is set to 1 @@ -128,7 +125,6 @@ TEST_P(QuicStreamIdManagerTest, CheckMaxStreamsWindowForSingleStream) { stream_id_manager_.SetMaxOpenIncomingStreams(1); EXPECT_EQ(1u, stream_id_manager_.incoming_initial_max_open_streams()); EXPECT_EQ(1u, stream_id_manager_.incoming_actual_max_streams()); - EXPECT_EQ(1u, stream_id_manager_.max_streams_window()); } TEST_P(QuicStreamIdManagerTest, CheckMaxStreamsBadValuesOverMaxFailsOutgoing) { @@ -279,18 +275,17 @@ TEST_P(QuicStreamIdManagerTest, GetNextOutgoingStream) { EXPECT_TRUE( stream_id_manager_.MaybeAllowNewOutgoingStreams(number_of_streams)); - QuicStreamId stream_id = - IsUnidirectional() - ? QuicUtils::GetFirstUnidirectionalStreamId( - transport_version(), stream_id_manager_.perspective()) - : QuicUtils::GetFirstBidirectionalStreamId( - transport_version(), stream_id_manager_.perspective()); + QuicStreamId stream_id = IsUnidirectional() + ? QuicUtils::GetFirstUnidirectionalStreamId( + transport_version(), perspective()) + : QuicUtils::GetFirstBidirectionalStreamId( + transport_version(), perspective()); EXPECT_EQ(number_of_streams, stream_id_manager_.outgoing_max_streams()); while (number_of_streams) { EXPECT_TRUE(stream_id_manager_.CanOpenNextOutgoingStream()); EXPECT_EQ(stream_id, stream_id_manager_.GetNextOutgoingStreamId()); - stream_id += kV99StreamIdIncrement; + stream_id += QuicUtils::StreamIdDelta(transport_version()); number_of_streams--; } @@ -316,23 +311,21 @@ TEST_P(QuicStreamIdManagerTest, MaybeIncreaseLargestPeerStreamId) { // A bad stream ID results in a closed connection. std::string error_details; EXPECT_FALSE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId( - max_stream_id + kV99StreamIdIncrement, &error_details)); - EXPECT_EQ( - error_details, - quiche::QuicheStrCat("Stream id ", max_stream_id + kV99StreamIdIncrement, - " would exceed stream count limit 100")); + max_stream_id + QuicUtils::StreamIdDelta(transport_version()), + &error_details)); + EXPECT_EQ(error_details, + quiche::QuicheStrCat( + "Stream id ", + max_stream_id + QuicUtils::StreamIdDelta(transport_version()), + " would exceed stream count limit 100")); } TEST_P(QuicStreamIdManagerTest, MaxStreamsWindow) { - // Test that a MAX_STREAMS frame is generated when the peer has less than - // |max_streams_window_| streams left that it can initiate. - - // First, open, and then close, max_streams_window_ streams. This will - // max_streams_window_ streams available for the peer -- no MAX_STREAMS - // should be sent. The -1 is because the check in - // QuicStreamIdManager::MaybeSendMaxStreamsFrame sends a MAX_STREAMS if the - // number of available streams at the peer is <= |max_streams_window_| - int stream_count = stream_id_manager_.max_streams_window() - 1; + // Open and then close a number of streams to get close to the threshold of + // sending a MAX_STREAM_FRAME. + int stream_count = stream_id_manager_.incoming_initial_max_open_streams() / + GetQuicFlag(FLAGS_quic_max_streams_window_divisor) - + 1; // Should not get a control-frame transmission since the peer should have // "plenty" of stream IDs to use. @@ -342,7 +335,8 @@ TEST_P(QuicStreamIdManagerTest, MaxStreamsWindow) { QuicStreamId stream_id = GetNthIncomingStreamId(0); size_t old_available_incoming_streams = stream_id_manager_.available_incoming_streams(); - while (stream_count) { + auto i = stream_count; + while (i) { EXPECT_TRUE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id, nullptr)); @@ -352,12 +346,11 @@ TEST_P(QuicStreamIdManagerTest, MaxStreamsWindow) { EXPECT_EQ(old_available_incoming_streams, stream_id_manager_.available_incoming_streams()); - stream_count--; - stream_id += kV99StreamIdIncrement; + i--; + stream_id += QuicUtils::StreamIdDelta(transport_version()); } // Now close them, still should get no MAX_STREAMS - stream_count = stream_id_manager_.max_streams_window(); stream_id = GetNthIncomingStreamId(0); QuicStreamCount expected_actual_max = stream_id_manager_.incoming_actual_max_streams(); @@ -366,7 +359,7 @@ TEST_P(QuicStreamIdManagerTest, MaxStreamsWindow) { while (stream_count) { stream_id_manager_.OnStreamClosed(stream_id); stream_count--; - stream_id += kV99StreamIdIncrement; + stream_id += QuicUtils::StreamIdDelta(transport_version()); expected_actual_max++; EXPECT_EQ(expected_actual_max, stream_id_manager_.incoming_actual_max_streams()); @@ -418,24 +411,21 @@ TEST_P(QuicStreamIdManagerTest, MaxStreamsSlidingWindow) { stream_id_manager_.incoming_advertised_max_streams(); // Open/close enough streams to shrink the window without causing a MAX - // STREAMS to be generated. The window will open (and a MAX STREAMS generated) - // when max_streams_window() stream IDs have been made available. The loop + // STREAMS to be generated. The loop // will make that many stream IDs available, so the last CloseStream should - // cause a MAX STREAMS frame to be generated. - int i = static_cast<int>(stream_id_manager_.max_streams_window()); + int i = + static_cast<int>(stream_id_manager_.incoming_initial_max_open_streams() / + GetQuicFlag(FLAGS_quic_max_streams_window_divisor)); QuicStreamId id = QuicStreamIdManagerPeer::GetFirstIncomingStreamId(&stream_id_manager_); - EXPECT_CALL( - delegate_, - SendMaxStreams(first_advert + stream_id_manager_.max_streams_window(), - IsUnidirectional())); + EXPECT_CALL(delegate_, SendMaxStreams(first_advert + i, IsUnidirectional())); while (i) { EXPECT_TRUE( stream_id_manager_.MaybeIncreaseLargestPeerStreamId(id, nullptr)); stream_id_manager_.OnStreamClosed(id); i--; - id += kV99StreamIdIncrement; + id += QuicUtils::StreamIdDelta(transport_version()); } } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer.h b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer.h index 50b5b68eaed..a74526b949e 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer.h @@ -50,6 +50,7 @@ class QUIC_EXPORT_PRIVATE QuicStreamSequencer { QuicStreamSequencer(const QuicStreamSequencer&) = delete; QuicStreamSequencer(QuicStreamSequencer&&) = default; QuicStreamSequencer& operator=(const QuicStreamSequencer&) = delete; + QuicStreamSequencer& operator=(QuicStreamSequencer&&) = default; virtual ~QuicStreamSequencer(); // If the frame is the next one we need in order to process in-order data, diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.h b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.h index 356b62fccc9..0ad984117de 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.h @@ -94,6 +94,7 @@ class QUIC_EXPORT_PRIVATE QuicStreamSequencerBuffer { QuicStreamSequencerBuffer(QuicStreamSequencerBuffer&&) = default; QuicStreamSequencerBuffer& operator=(const QuicStreamSequencerBuffer&) = delete; + QuicStreamSequencerBuffer& operator=(QuicStreamSequencerBuffer&&) = default; ~QuicStreamSequencerBuffer(); // Free the space used to buffer data. @@ -212,10 +213,10 @@ class QUIC_EXPORT_PRIVATE QuicStreamSequencerBuffer { std::string ReceivedFramesDebugString() const; // The maximum total capacity of this buffer in byte, as constructed. - const size_t max_buffer_capacity_bytes_; + size_t max_buffer_capacity_bytes_; // How many blocks this buffer would need when it reaches full capacity. - const size_t blocks_count_; + size_t blocks_count_; // Number of bytes read out of buffer. QuicStreamOffset total_bytes_read_; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_test.cc index 188eb86f6fe..bdf141267a7 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_test.cc @@ -31,13 +31,14 @@ namespace test { class MockStream : public QuicStreamSequencer::StreamInterface { public: - MOCK_METHOD0(OnFinRead, void()); - MOCK_METHOD0(OnDataAvailable, void()); - MOCK_METHOD2(OnUnrecoverableError, - void(QuicErrorCode error, const std::string& details)); - MOCK_METHOD1(Reset, void(QuicRstStreamErrorCode error)); - MOCK_METHOD0(OnCanWrite, void()); - MOCK_METHOD1(AddBytesConsumed, void(QuicByteCount bytes)); + MOCK_METHOD(void, OnFinRead, (), (override)); + MOCK_METHOD(void, OnDataAvailable, (), (override)); + MOCK_METHOD(void, + OnUnrecoverableError, + (QuicErrorCode error, const std::string& details), + (override)); + MOCK_METHOD(void, Reset, (QuicRstStreamErrorCode error), (override)); + MOCK_METHOD(void, AddBytesConsumed, (QuicByteCount bytes), (override)); QuicStreamId id() const override { return 1; } }; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc index eea7b15113e..f30a3be7216 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc @@ -49,7 +49,7 @@ namespace { const char kData1[] = "FooAndBar"; const char kData2[] = "EepAndBaz"; -const size_t kDataLen = 9; +const QuicByteCount kDataLen = 9; class TestStream : public QuicStream { public: @@ -61,9 +61,9 @@ class TestStream : public QuicStream { TestStream(PendingStream* pending, StreamType type, bool is_static) : QuicStream(pending, type, is_static) {} - MOCK_METHOD0(OnDataAvailable, void()); + MOCK_METHOD(void, OnDataAvailable, (), (override)); - MOCK_METHOD0(OnCanWriteNewData, void()); + MOCK_METHOD(void, OnCanWriteNewData, (), (override)); using QuicStream::CanWriteNewData; using QuicStream::CanWriteNewDataAfterData; @@ -125,7 +125,7 @@ class QuicStreamTest : public QuicTestWithParam<ParsedQuicVersion> { QuicConsumedData CloseStreamOnWriteError( QuicStreamId id, - size_t /*write_length*/, + QuicByteCount /*write_length*/, QuicStreamOffset /*offset*/, StreamSendingState /*state*/, TransmissionType /*type*/, @@ -271,7 +271,7 @@ TEST_P(QuicStreamTest, FromPendingStreamThenData) { TEST_P(QuicStreamTest, WriteAllData) { Initialize(); - size_t length = + QuicByteCount length = 1 + QuicPacketCreator::StreamFramePacketOverhead( connection_->transport_version(), PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, @@ -360,7 +360,7 @@ TEST_P(QuicStreamTest, WriteOrBufferData) { Initialize(); EXPECT_FALSE(HasWriteBlockedStreams()); - size_t length = + QuicByteCount length = 1 + QuicPacketCreator::StreamFramePacketOverhead( connection_->transport_version(), PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, @@ -455,7 +455,12 @@ TEST_P(QuicStreamTest, RstAlwaysSentIfNoFinSent) { // Now close the stream, and expect that we send a RST. EXPECT_CALL(*session_, SendRstStream(_, _, _)); - stream_->OnClose(); + if (session_->break_close_loop()) { + stream_->CloseReadSide(); + stream_->CloseWriteSide(); + } else { + stream_->OnClose(); + } EXPECT_FALSE(session_->HasUnackedStreamData()); EXPECT_FALSE(fin_sent()); EXPECT_TRUE(rst_sent()); @@ -482,7 +487,12 @@ TEST_P(QuicStreamTest, RstNotSentIfFinSent) { EXPECT_FALSE(rst_sent()); // Now close the stream, and expect that we do not send a RST. - stream_->OnClose(); + if (session_->break_close_loop()) { + stream_->CloseReadSide(); + stream_->CloseWriteSide(); + } else { + stream_->OnClose(); + } EXPECT_TRUE(fin_sent()); EXPECT_FALSE(rst_sent()); } @@ -506,7 +516,12 @@ TEST_P(QuicStreamTest, OnlySendOneRst) { // Now close the stream (any further resets being sent would break the // expectation above). - stream_->OnClose(); + if (session_->break_close_loop()) { + stream_->CloseReadSide(); + stream_->CloseWriteSide(); + } else { + stream_->OnClose(); + } EXPECT_FALSE(fin_sent()); EXPECT_TRUE(rst_sent()); } @@ -642,7 +657,12 @@ TEST_P(QuicStreamTest, InvalidFinalByteOffsetFromRst) { CloseConnection(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, _, _)); stream_->OnStreamReset(rst_frame); EXPECT_TRUE(stream_->HasReceivedFinalOffset()); - stream_->OnClose(); + if (session_->break_close_loop()) { + stream_->CloseReadSide(); + stream_->CloseWriteSide(); + } else { + stream_->OnClose(); + } } TEST_P(QuicStreamTest, FinalByteOffsetFromZeroLengthStreamFrame) { @@ -734,7 +754,7 @@ TEST_P(QuicStreamTest, SetDrainingIncomingOutgoing) { EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_)); EXPECT_FALSE(stream_->reading_stopped()); - EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams()); + EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); // Outgoing data with FIN. EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _)) @@ -746,9 +766,8 @@ TEST_P(QuicStreamTest, SetDrainingIncomingOutgoing) { nullptr); EXPECT_TRUE(stream_->write_side_closed()); - EXPECT_EQ(1u, QuicSessionPeer::GetDrainingStreams(session_.get()) - ->count(kTestStreamId)); - EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); + EXPECT_EQ(1u, session_->GetNumDrainingStreams()); + EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); } TEST_P(QuicStreamTest, SetDrainingOutgoingIncoming) { @@ -765,7 +784,7 @@ TEST_P(QuicStreamTest, SetDrainingOutgoingIncoming) { nullptr); EXPECT_TRUE(stream_->write_side_closed()); - EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams()); + EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); // Incoming data with FIN. QuicStreamFrame stream_frame_with_fin(stream_->id(), true, 1234, "."); @@ -775,9 +794,8 @@ TEST_P(QuicStreamTest, SetDrainingOutgoingIncoming) { EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_)); EXPECT_FALSE(stream_->reading_stopped()); - EXPECT_EQ(1u, QuicSessionPeer::GetDrainingStreams(session_.get()) - ->count(kTestStreamId)); - EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); + EXPECT_EQ(1u, session_->GetNumDrainingStreams()); + EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); } TEST_P(QuicStreamTest, EarlyResponseFinHandling) { @@ -1058,8 +1076,9 @@ TEST_P(QuicStreamTest, WriteBufferedData) { EXPECT_FALSE(stream_->CanWriteNewData()); // Send buffered data to make buffered data size < threshold. - size_t data_to_write = 3 * data.length() - 200 - - GetQuicFlag(FLAGS_quic_buffered_data_threshold) + 1; + QuicByteCount data_to_write = + 3 * data.length() - 200 - + GetQuicFlag(FLAGS_quic_buffered_data_threshold) + 1; EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) .WillOnce(InvokeWithoutArgs([this, data_to_write]() { return session_->ConsumeData(stream_->id(), data_to_write, 200u, NO_FIN, @@ -1192,8 +1211,9 @@ TEST_P(QuicStreamTest, WriteMemSlices) { EXPECT_EQ(2 * QUICHE_ARRAYSIZE(data) - 100, stream_->BufferedDataBytes()); EXPECT_FALSE(stream_->fin_buffered()); - size_t data_to_write = 2 * QUICHE_ARRAYSIZE(data) - 100 - - GetQuicFlag(FLAGS_quic_buffered_data_threshold) + 1; + QuicByteCount data_to_write = + 2 * QUICHE_ARRAYSIZE(data) - 100 - + GetQuicFlag(FLAGS_quic_buffered_data_threshold) + 1; EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) .WillOnce(InvokeWithoutArgs([this, data_to_write]() { return session_->ConsumeData(stream_->id(), data_to_write, 100u, NO_FIN, diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_time.h b/chromium/net/third_party/quiche/src/quic/core/quic_time.h index d4429e34ceb..adecbcd1514 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_time.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_time.h @@ -254,8 +254,8 @@ inline QuicTime::Delta operator*(QuicTime::Delta lhs, int rhs) { return QuicTime::Delta(lhs.time_offset_ * rhs); } inline QuicTime::Delta operator*(QuicTime::Delta lhs, double rhs) { - return QuicTime::Delta( - static_cast<int64_t>(std::llround(lhs.time_offset_ * rhs))); + return QuicTime::Delta(static_cast<int64_t>( + std::llround(static_cast<double>(lhs.time_offset_) * rhs))); } inline QuicTime::Delta operator*(int lhs, QuicTime::Delta rhs) { return rhs * lhs; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.cc index 2b0c267f626..433a3ab3285 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.cc @@ -162,12 +162,13 @@ void QuicTimeWaitListManager::ProcessPacket( if (!connection_data->ietf_quic) { QUIC_CODE_COUNT(quic_received_short_header_packet_for_gquic); } - if (connection_data->encryption_level == ENCRYPTION_INITIAL) { + if (GetQuicRestartFlag( + quic_replace_time_wait_list_encryption_level) || + connection_data->encryption_level == ENCRYPTION_INITIAL) { + // TODO(b/153096082) Rename this code count. QUIC_CODE_COUNT( quic_encryption_none_termination_packets_for_short_header); - // Send stateless reset in response to short header packets, - // because ENCRYPTION_INITIAL termination packets will not be - // processed by clients. + // Send stateless reset in response to short header packets. SendPublicReset(self_address, peer_address, connection_id, connection_data->ietf_quic, std::move(packet_context)); @@ -190,6 +191,19 @@ void QuicTimeWaitListManager::ProcessPacket( packet_context.get()); } return; + + case SEND_CONNECTION_CLOSE_PACKETS: + if (connection_data->termination_packets.empty()) { + QUIC_BUG << "There are no termination packets."; + return; + } + for (const auto& packet : connection_data->termination_packets) { + SendOrQueuePacket(std::make_unique<QueuedPacket>( + self_address, peer_address, packet->Clone()), + packet_context.get()); + } + return; + case SEND_STATELESS_RESET: if (header_format == IETF_QUIC_LONG_HEADER_PACKET) { QUIC_CODE_COUNT(quic_stateless_reset_long_header_packet); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h index c9a5261d62f..64138de14bb 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h @@ -44,6 +44,9 @@ class QUIC_NO_EXPORT QuicTimeWaitListManager // Send specified termination packets, error if termination packet is // unavailable. SEND_TERMINATION_PACKETS, + // The same as SEND_TERMINATION_PACKETS except that the corresponding + // termination packets are provided by the connection. + SEND_CONNECTION_CLOSE_PACKETS, // Send stateless reset (public reset for GQUIC). SEND_STATELESS_RESET, @@ -244,6 +247,7 @@ class QUIC_NO_EXPORT QuicTimeWaitListManager int num_packets; bool ietf_quic; QuicTime time_added; + // TODO(b/153096082) Remove this field. // Encryption level of termination_packets. EncryptionLevel encryption_level; // These packets may contain CONNECTION_CLOSE frames, or SREJ messages. diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager_test.cc index b07c83ea44f..468b21bf78f 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager_test.cc @@ -113,8 +113,8 @@ class MockAlarmFactory : public QuicAlarmFactory { return QuicArenaScopedPtr<MockAlarm>( new MockAlarm(std::move(delegate), alarm_index_++, this)); } - MOCK_METHOD2(OnAlarmSet, void(int, QuicTime)); - MOCK_METHOD1(OnAlarmCancelled, void(int)); + MOCK_METHOD(void, OnAlarmSet, (int, QuicTime), ()); + MOCK_METHOD(void, OnAlarmCancelled, (int), ()); private: int alarm_index_ = 0; @@ -322,9 +322,12 @@ TEST_F(QuicTimeWaitListManagerTest, SendConnectionClose) { termination_packets.push_back( std::unique_ptr<QuicEncryptedPacket>(new QuicEncryptedPacket( new char[kConnectionCloseLength], kConnectionCloseLength, true))); - AddConnectionId(connection_id_, QuicVersionMax(), - QuicTimeWaitListManager::SEND_TERMINATION_PACKETS, - &termination_packets); + AddConnectionId( + connection_id_, QuicVersionMax(), + GetQuicRestartFlag(quic_replace_time_wait_list_encryption_level) + ? QuicTimeWaitListManager::SEND_CONNECTION_CLOSE_PACKETS + : QuicTimeWaitListManager::SEND_TERMINATION_PACKETS, + &termination_packets); EXPECT_CALL(writer_, WritePacket(_, kConnectionCloseLength, self_address_.host(), peer_address_, _)) .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1))); @@ -342,9 +345,12 @@ TEST_F(QuicTimeWaitListManagerTest, SendTwoConnectionCloses) { termination_packets.push_back( std::unique_ptr<QuicEncryptedPacket>(new QuicEncryptedPacket( new char[kConnectionCloseLength], kConnectionCloseLength, true))); - AddConnectionId(connection_id_, QuicVersionMax(), - QuicTimeWaitListManager::SEND_TERMINATION_PACKETS, - &termination_packets); + AddConnectionId( + connection_id_, QuicVersionMax(), + GetQuicRestartFlag(quic_replace_time_wait_list_encryption_level) + ? QuicTimeWaitListManager::SEND_CONNECTION_CLOSE_PACKETS + : QuicTimeWaitListManager::SEND_TERMINATION_PACKETS, + &termination_packets); EXPECT_CALL(writer_, WritePacket(_, kConnectionCloseLength, self_address_.host(), peer_address_, _)) .Times(2) @@ -646,6 +652,30 @@ TEST_F(QuicTimeWaitListManagerTest, IETF_QUIC_SHORT_HEADER_PACKET, std::make_unique<QuicPerPacketContext>()); } +TEST_F(QuicTimeWaitListManagerTest, + SendConnectionClosePacketsInResponseToShortHeaders) { + SetQuicRestartFlag(quic_replace_time_wait_list_encryption_level, true); + const size_t kConnectionCloseLength = 100; + EXPECT_CALL(visitor_, OnConnectionAddedToTimeWaitList(connection_id_)); + std::vector<std::unique_ptr<QuicEncryptedPacket>> termination_packets; + termination_packets.push_back( + std::unique_ptr<QuicEncryptedPacket>(new QuicEncryptedPacket( + new char[kConnectionCloseLength], kConnectionCloseLength, true))); + // Add a CONNECTION_CLOSE termination packet. + time_wait_list_manager_.AddConnectionIdToTimeWait( + connection_id_, /*ietf_quic=*/true, + QuicTimeWaitListManager::SEND_CONNECTION_CLOSE_PACKETS, + ENCRYPTION_INITIAL, &termination_packets); + EXPECT_CALL(writer_, WritePacket(_, kConnectionCloseLength, + self_address_.host(), peer_address_, _)) + .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1))); + + // Processes IETF short header packet. + time_wait_list_manager_.ProcessPacket( + self_address_, peer_address_, connection_id_, + IETF_QUIC_SHORT_HEADER_PACKET, std::make_unique<QuicPerPacketContext>()); +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_types.cc b/chromium/net/third_party/quiche/src/quic/core/quic_types.cc index ce24d57113d..36614cd8f0a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_types.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_types.cc @@ -6,7 +6,6 @@ #include <cstdint> -#include "third_party/boringssl/src/include/openssl/ssl.h" #include "net/third_party/quiche/src/quic/core/quic_error_codes.h" #include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h" @@ -18,12 +17,56 @@ std::ostream& operator<<(std::ostream& os, const QuicConsumedData& s) { return os; } -std::ostream& operator<<(std::ostream& os, const Perspective& s) { - if (s == Perspective::IS_SERVER) { - os << "IS_SERVER"; - } else { - os << "IS_CLIENT"; +std::string PerspectiveToString(Perspective perspective) { + if (perspective == Perspective::IS_SERVER) { + return "IS_SERVER"; + } + if (perspective == Perspective::IS_CLIENT) { + return "IS_CLIENT"; + } + return quiche::QuicheStrCat("Unknown(", static_cast<int>(perspective), ")"); +} + +std::ostream& operator<<(std::ostream& os, const Perspective& perspective) { + os << PerspectiveToString(perspective); + return os; +} + +std::string ConnectionCloseSourceToString( + ConnectionCloseSource connection_close_source) { + if (connection_close_source == ConnectionCloseSource::FROM_PEER) { + return "FROM_PEER"; + } + if (connection_close_source == ConnectionCloseSource::FROM_SELF) { + return "FROM_SELF"; } + return quiche::QuicheStrCat("Unknown(", + static_cast<int>(connection_close_source), ")"); +} + +std::ostream& operator<<(std::ostream& os, + const ConnectionCloseSource& connection_close_source) { + os << ConnectionCloseSourceToString(connection_close_source); + return os; +} + +std::string ConnectionCloseBehaviorToString( + ConnectionCloseBehavior connection_close_behavior) { + if (connection_close_behavior == ConnectionCloseBehavior::SILENT_CLOSE) { + return "SILENT_CLOSE"; + } + if (connection_close_behavior == + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET) { + return "SEND_CONNECTION_CLOSE_PACKET"; + } + return quiche::QuicheStrCat("Unknown(", + static_cast<int>(connection_close_behavior), ")"); +} + +std::ostream& operator<<( + std::ostream& os, + const ConnectionCloseBehavior& connection_close_behavior) { + os << ConnectionCloseBehaviorToString(connection_close_behavior); return os; } @@ -85,465 +128,6 @@ MessageResult::MessageResult(MessageStatus status, QuicMessageId message_id) case x: \ return #x; -std::string QuicIetfTransportErrorCodeString(QuicIetfTransportErrorCodes c) { - if (static_cast<uint64_t>(c) >= 0xff00u) { - return quiche::QuicheStrCat("Private(", static_cast<uint64_t>(c), ")"); - } - if (c >= CRYPTO_ERROR_FIRST && c <= CRYPTO_ERROR_LAST) { - const int tls_error = static_cast<int>(c - CRYPTO_ERROR_FIRST); - const char* tls_error_description = SSL_alert_desc_string_long(tls_error); - if (strcmp("unknown", tls_error_description) != 0) { - return quiche::QuicheStrCat("CRYPTO_ERROR(", tls_error_description, ")"); - } - return quiche::QuicheStrCat("CRYPTO_ERROR(unknown(", tls_error, "))"); - } - - switch (c) { - RETURN_STRING_LITERAL(NO_IETF_QUIC_ERROR); - RETURN_STRING_LITERAL(INTERNAL_ERROR); - RETURN_STRING_LITERAL(SERVER_BUSY_ERROR); - RETURN_STRING_LITERAL(FLOW_CONTROL_ERROR); - RETURN_STRING_LITERAL(STREAM_LIMIT_ERROR); - RETURN_STRING_LITERAL(STREAM_STATE_ERROR); - RETURN_STRING_LITERAL(FINAL_SIZE_ERROR); - RETURN_STRING_LITERAL(FRAME_ENCODING_ERROR); - RETURN_STRING_LITERAL(TRANSPORT_PARAMETER_ERROR); - RETURN_STRING_LITERAL(CONNECTION_ID_LIMIT_ERROR); - RETURN_STRING_LITERAL(PROTOCOL_VIOLATION); - RETURN_STRING_LITERAL(INVALID_TOKEN); - RETURN_STRING_LITERAL(CRYPTO_BUFFER_EXCEEDED); - // CRYPTO_ERROR is handled in the if before this switch, these cases do not - // change behavior and are only here to make the compiler happy. - case CRYPTO_ERROR_FIRST: - case CRYPTO_ERROR_LAST: - DCHECK(false) << "Unexpected error " << static_cast<uint64_t>(c); - break; - } - - return quiche::QuicheStrCat("Unknown(", static_cast<uint64_t>(c), ")"); -} - -std::ostream& operator<<(std::ostream& os, - const QuicIetfTransportErrorCodes& c) { - os << QuicIetfTransportErrorCodeString(c); - return os; -} - -QuicErrorCodeToIetfMapping QuicErrorCodeToTransportErrorCode( - QuicErrorCode error) { - switch (error) { - // TODO(fkastenholz): Currently, all QuicError codes will map - // to application error codes and the original Google QUIC error - // code. This will change over time as we go through all calls to - // CloseConnection() and see whether the call is a Transport or an - // Application close and what the translated code should be. - case QUIC_NO_ERROR: - return {true, {static_cast<uint64_t>(QUIC_NO_ERROR)}}; - case QUIC_INTERNAL_ERROR: - return {true, {static_cast<uint64_t>(QUIC_INTERNAL_ERROR)}}; - case QUIC_STREAM_DATA_AFTER_TERMINATION: - return {true, - {static_cast<uint64_t>(QUIC_STREAM_DATA_AFTER_TERMINATION)}}; - case QUIC_INVALID_PACKET_HEADER: - return {true, {static_cast<uint64_t>(QUIC_INVALID_PACKET_HEADER)}}; - case QUIC_INVALID_FRAME_DATA: - return {true, {static_cast<uint64_t>(QUIC_INVALID_FRAME_DATA)}}; - case QUIC_MISSING_PAYLOAD: - return {true, {static_cast<uint64_t>(QUIC_MISSING_PAYLOAD)}}; - case QUIC_INVALID_FEC_DATA: - return {true, {static_cast<uint64_t>(QUIC_INVALID_FEC_DATA)}}; - case QUIC_INVALID_STREAM_DATA: - return {true, {static_cast<uint64_t>(QUIC_INVALID_STREAM_DATA)}}; - case QUIC_OVERLAPPING_STREAM_DATA: - return {true, {static_cast<uint64_t>(QUIC_OVERLAPPING_STREAM_DATA)}}; - case QUIC_UNENCRYPTED_STREAM_DATA: - return {true, {static_cast<uint64_t>(QUIC_UNENCRYPTED_STREAM_DATA)}}; - case QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA: - return {true, - {static_cast<uint64_t>( - QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA)}}; - case QUIC_MAYBE_CORRUPTED_MEMORY: - return {true, {static_cast<uint64_t>(QUIC_MAYBE_CORRUPTED_MEMORY)}}; - case QUIC_UNENCRYPTED_FEC_DATA: - return {true, {static_cast<uint64_t>(QUIC_UNENCRYPTED_FEC_DATA)}}; - case QUIC_INVALID_RST_STREAM_DATA: - return {true, {static_cast<uint64_t>(QUIC_INVALID_RST_STREAM_DATA)}}; - case QUIC_INVALID_CONNECTION_CLOSE_DATA: - return {true, - {static_cast<uint64_t>(QUIC_INVALID_CONNECTION_CLOSE_DATA)}}; - case QUIC_INVALID_GOAWAY_DATA: - return {true, {static_cast<uint64_t>(QUIC_INVALID_GOAWAY_DATA)}}; - case QUIC_INVALID_WINDOW_UPDATE_DATA: - return {true, {static_cast<uint64_t>(QUIC_INVALID_WINDOW_UPDATE_DATA)}}; - case QUIC_INVALID_BLOCKED_DATA: - return {true, {static_cast<uint64_t>(QUIC_INVALID_BLOCKED_DATA)}}; - case QUIC_INVALID_STOP_WAITING_DATA: - return {true, {static_cast<uint64_t>(QUIC_INVALID_STOP_WAITING_DATA)}}; - case QUIC_INVALID_PATH_CLOSE_DATA: - return {true, {static_cast<uint64_t>(QUIC_INVALID_PATH_CLOSE_DATA)}}; - case QUIC_INVALID_ACK_DATA: - return {true, {static_cast<uint64_t>(QUIC_INVALID_ACK_DATA)}}; - case QUIC_INVALID_MESSAGE_DATA: - return {true, {static_cast<uint64_t>(QUIC_INVALID_MESSAGE_DATA)}}; - case QUIC_INVALID_VERSION_NEGOTIATION_PACKET: - return {true, - {static_cast<uint64_t>(QUIC_INVALID_VERSION_NEGOTIATION_PACKET)}}; - case QUIC_INVALID_PUBLIC_RST_PACKET: - return {true, {static_cast<uint64_t>(QUIC_INVALID_PUBLIC_RST_PACKET)}}; - case QUIC_DECRYPTION_FAILURE: - return {true, {static_cast<uint64_t>(QUIC_DECRYPTION_FAILURE)}}; - case QUIC_ENCRYPTION_FAILURE: - return {true, {static_cast<uint64_t>(QUIC_ENCRYPTION_FAILURE)}}; - case QUIC_PACKET_TOO_LARGE: - return {true, {static_cast<uint64_t>(QUIC_PACKET_TOO_LARGE)}}; - case QUIC_PEER_GOING_AWAY: - return {true, {static_cast<uint64_t>(QUIC_PEER_GOING_AWAY)}}; - case QUIC_INVALID_STREAM_ID: - return {true, {static_cast<uint64_t>(QUIC_INVALID_STREAM_ID)}}; - case QUIC_INVALID_PRIORITY: - return {true, {static_cast<uint64_t>(QUIC_INVALID_PRIORITY)}}; - case QUIC_TOO_MANY_OPEN_STREAMS: - return {true, {static_cast<uint64_t>(QUIC_TOO_MANY_OPEN_STREAMS)}}; - case QUIC_TOO_MANY_AVAILABLE_STREAMS: - return {true, {static_cast<uint64_t>(QUIC_TOO_MANY_AVAILABLE_STREAMS)}}; - case QUIC_PUBLIC_RESET: - return {true, {static_cast<uint64_t>(QUIC_PUBLIC_RESET)}}; - case QUIC_INVALID_VERSION: - return {true, {static_cast<uint64_t>(QUIC_INVALID_VERSION)}}; - case QUIC_INVALID_HEADER_ID: - return {true, {static_cast<uint64_t>(QUIC_INVALID_HEADER_ID)}}; - case QUIC_INVALID_NEGOTIATED_VALUE: - return {true, {static_cast<uint64_t>(QUIC_INVALID_NEGOTIATED_VALUE)}}; - case QUIC_DECOMPRESSION_FAILURE: - return {true, {static_cast<uint64_t>(QUIC_DECOMPRESSION_FAILURE)}}; - case QUIC_NETWORK_IDLE_TIMEOUT: - return {true, {static_cast<uint64_t>(QUIC_NETWORK_IDLE_TIMEOUT)}}; - case QUIC_HANDSHAKE_TIMEOUT: - return {true, {static_cast<uint64_t>(QUIC_HANDSHAKE_TIMEOUT)}}; - case QUIC_ERROR_MIGRATING_ADDRESS: - return {true, {static_cast<uint64_t>(QUIC_ERROR_MIGRATING_ADDRESS)}}; - case QUIC_ERROR_MIGRATING_PORT: - return {true, {static_cast<uint64_t>(QUIC_ERROR_MIGRATING_PORT)}}; - case QUIC_PACKET_WRITE_ERROR: - return {true, {static_cast<uint64_t>(QUIC_PACKET_WRITE_ERROR)}}; - case QUIC_PACKET_READ_ERROR: - return {true, {static_cast<uint64_t>(QUIC_PACKET_READ_ERROR)}}; - case QUIC_EMPTY_STREAM_FRAME_NO_FIN: - return {true, {static_cast<uint64_t>(QUIC_EMPTY_STREAM_FRAME_NO_FIN)}}; - case QUIC_INVALID_HEADERS_STREAM_DATA: - return {true, {static_cast<uint64_t>(QUIC_INVALID_HEADERS_STREAM_DATA)}}; - case QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE: - return { - true, - {static_cast<uint64_t>(QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE)}}; - case QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA: - return { - true, - {static_cast<uint64_t>(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA)}}; - case QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA: - return {true, - {static_cast<uint64_t>(QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA)}}; - case QUIC_FLOW_CONTROL_INVALID_WINDOW: - return {true, {static_cast<uint64_t>(QUIC_FLOW_CONTROL_INVALID_WINDOW)}}; - case QUIC_CONNECTION_IP_POOLED: - return {true, {static_cast<uint64_t>(QUIC_CONNECTION_IP_POOLED)}}; - case QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS: - return {true, - {static_cast<uint64_t>(QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS)}}; - case QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS: - return { - true, - {static_cast<uint64_t>(QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS)}}; - case QUIC_CONNECTION_CANCELLED: - return {true, {static_cast<uint64_t>(QUIC_CONNECTION_CANCELLED)}}; - case QUIC_BAD_PACKET_LOSS_RATE: - return {true, {static_cast<uint64_t>(QUIC_BAD_PACKET_LOSS_RATE)}}; - case QUIC_PUBLIC_RESETS_POST_HANDSHAKE: - return {true, {static_cast<uint64_t>(QUIC_PUBLIC_RESETS_POST_HANDSHAKE)}}; - case QUIC_FAILED_TO_SERIALIZE_PACKET: - return {true, {static_cast<uint64_t>(QUIC_FAILED_TO_SERIALIZE_PACKET)}}; - case QUIC_TOO_MANY_RTOS: - return {true, {static_cast<uint64_t>(QUIC_TOO_MANY_RTOS)}}; - case QUIC_HANDSHAKE_FAILED: - return {true, {static_cast<uint64_t>(QUIC_HANDSHAKE_FAILED)}}; - case QUIC_CRYPTO_TAGS_OUT_OF_ORDER: - return {true, {static_cast<uint64_t>(QUIC_CRYPTO_TAGS_OUT_OF_ORDER)}}; - case QUIC_CRYPTO_TOO_MANY_ENTRIES: - return {true, {static_cast<uint64_t>(QUIC_CRYPTO_TOO_MANY_ENTRIES)}}; - case QUIC_CRYPTO_INVALID_VALUE_LENGTH: - return {true, {static_cast<uint64_t>(QUIC_CRYPTO_INVALID_VALUE_LENGTH)}}; - case QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE: - return {true, - {static_cast<uint64_t>( - QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE)}}; - case QUIC_INVALID_CRYPTO_MESSAGE_TYPE: - return {true, {static_cast<uint64_t>(QUIC_INVALID_CRYPTO_MESSAGE_TYPE)}}; - case QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER: - return {true, - {static_cast<uint64_t>(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER)}}; - case QUIC_INVALID_CHANNEL_ID_SIGNATURE: - return {true, {static_cast<uint64_t>(QUIC_INVALID_CHANNEL_ID_SIGNATURE)}}; - case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND: - return {true, - {static_cast<uint64_t>(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND)}}; - case QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP: - return { - true, - {static_cast<uint64_t>(QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP)}}; - case QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND: - return {true, - {static_cast<uint64_t>(QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND)}}; - case QUIC_UNSUPPORTED_PROOF_DEMAND: - return {true, {static_cast<uint64_t>(QUIC_UNSUPPORTED_PROOF_DEMAND)}}; - case QUIC_CRYPTO_INTERNAL_ERROR: - return {true, {static_cast<uint64_t>(QUIC_CRYPTO_INTERNAL_ERROR)}}; - case QUIC_CRYPTO_VERSION_NOT_SUPPORTED: - return {true, {static_cast<uint64_t>(QUIC_CRYPTO_VERSION_NOT_SUPPORTED)}}; - case QUIC_CRYPTO_NO_SUPPORT: - return {true, {static_cast<uint64_t>(QUIC_CRYPTO_NO_SUPPORT)}}; - case QUIC_CRYPTO_TOO_MANY_REJECTS: - return {true, {static_cast<uint64_t>(QUIC_CRYPTO_TOO_MANY_REJECTS)}}; - case QUIC_PROOF_INVALID: - return {true, {static_cast<uint64_t>(QUIC_PROOF_INVALID)}}; - case QUIC_CRYPTO_DUPLICATE_TAG: - return {true, {static_cast<uint64_t>(QUIC_CRYPTO_DUPLICATE_TAG)}}; - case QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT: - return {true, - {static_cast<uint64_t>(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT)}}; - case QUIC_CRYPTO_SERVER_CONFIG_EXPIRED: - return {true, {static_cast<uint64_t>(QUIC_CRYPTO_SERVER_CONFIG_EXPIRED)}}; - case QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED: - return {true, - {static_cast<uint64_t>(QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED)}}; - case QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO: - return {true, - {static_cast<uint64_t>( - QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO)}}; - case QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE: - return {true, - {static_cast<uint64_t>( - QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE)}}; - case QUIC_CRYPTO_CHLO_TOO_LARGE: - return {true, {static_cast<uint64_t>(QUIC_CRYPTO_CHLO_TOO_LARGE)}}; - case QUIC_VERSION_NEGOTIATION_MISMATCH: - return {true, {static_cast<uint64_t>(QUIC_VERSION_NEGOTIATION_MISMATCH)}}; - case QUIC_BAD_MULTIPATH_FLAG: - return {true, {static_cast<uint64_t>(QUIC_BAD_MULTIPATH_FLAG)}}; - case QUIC_MULTIPATH_PATH_DOES_NOT_EXIST: - return {true, - {static_cast<uint64_t>(QUIC_MULTIPATH_PATH_DOES_NOT_EXIST)}}; - case QUIC_MULTIPATH_PATH_NOT_ACTIVE: - return {true, {static_cast<uint64_t>(QUIC_MULTIPATH_PATH_NOT_ACTIVE)}}; - case QUIC_IP_ADDRESS_CHANGED: - return {true, {static_cast<uint64_t>(QUIC_IP_ADDRESS_CHANGED)}}; - case QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS: - return {true, - {static_cast<uint64_t>( - QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS)}}; - case QUIC_CONNECTION_MIGRATION_TOO_MANY_CHANGES: - return { - true, - {static_cast<uint64_t>(QUIC_CONNECTION_MIGRATION_TOO_MANY_CHANGES)}}; - case QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK: - return { - true, - {static_cast<uint64_t>(QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK)}}; - case QUIC_CONNECTION_MIGRATION_NON_MIGRATABLE_STREAM: - return {true, - {static_cast<uint64_t>( - QUIC_CONNECTION_MIGRATION_NON_MIGRATABLE_STREAM)}}; - case QUIC_CONNECTION_MIGRATION_DISABLED_BY_CONFIG: - return {true, - {static_cast<uint64_t>( - QUIC_CONNECTION_MIGRATION_DISABLED_BY_CONFIG)}}; - case QUIC_CONNECTION_MIGRATION_INTERNAL_ERROR: - return { - true, - {static_cast<uint64_t>(QUIC_CONNECTION_MIGRATION_INTERNAL_ERROR)}}; - case QUIC_CONNECTION_MIGRATION_HANDSHAKE_UNCONFIRMED: - return {true, - {static_cast<uint64_t>( - QUIC_CONNECTION_MIGRATION_HANDSHAKE_UNCONFIRMED)}}; - case QUIC_TOO_MANY_STREAM_DATA_INTERVALS: - return {true, - {static_cast<uint64_t>(QUIC_TOO_MANY_STREAM_DATA_INTERVALS)}}; - case QUIC_STREAM_SEQUENCER_INVALID_STATE: - return {true, - {static_cast<uint64_t>(QUIC_STREAM_SEQUENCER_INVALID_STATE)}}; - case QUIC_TOO_MANY_SESSIONS_ON_SERVER: - return {true, {static_cast<uint64_t>(QUIC_TOO_MANY_SESSIONS_ON_SERVER)}}; - case QUIC_STREAM_LENGTH_OVERFLOW: - return {true, {static_cast<uint64_t>(QUIC_STREAM_LENGTH_OVERFLOW)}}; - case QUIC_INVALID_MAX_DATA_FRAME_DATA: - return {true, {static_cast<uint64_t>(QUIC_INVALID_MAX_DATA_FRAME_DATA)}}; - case QUIC_INVALID_MAX_STREAM_DATA_FRAME_DATA: - return {true, - {static_cast<uint64_t>(QUIC_INVALID_MAX_STREAM_DATA_FRAME_DATA)}}; - case QUIC_MAX_STREAMS_DATA: - return {true, {static_cast<uint64_t>(QUIC_MAX_STREAMS_DATA)}}; - case QUIC_STREAMS_BLOCKED_DATA: - return {true, {static_cast<uint64_t>(QUIC_STREAMS_BLOCKED_DATA)}}; - case QUIC_INVALID_STREAM_BLOCKED_DATA: - return {true, {static_cast<uint64_t>(QUIC_INVALID_STREAM_BLOCKED_DATA)}}; - case QUIC_INVALID_NEW_CONNECTION_ID_DATA: - return {true, - {static_cast<uint64_t>(QUIC_INVALID_NEW_CONNECTION_ID_DATA)}}; - case QUIC_INVALID_STOP_SENDING_FRAME_DATA: - return {true, - {static_cast<uint64_t>(QUIC_INVALID_STOP_SENDING_FRAME_DATA)}}; - case QUIC_INVALID_PATH_CHALLENGE_DATA: - return {true, {static_cast<uint64_t>(QUIC_INVALID_PATH_CHALLENGE_DATA)}}; - case QUIC_INVALID_PATH_RESPONSE_DATA: - return {true, {static_cast<uint64_t>(QUIC_INVALID_PATH_RESPONSE_DATA)}}; - case IETF_QUIC_PROTOCOL_VIOLATION: - return {true, {static_cast<uint64_t>(IETF_QUIC_PROTOCOL_VIOLATION)}}; - case QUIC_INVALID_NEW_TOKEN: - return {true, {static_cast<uint64_t>(QUIC_INVALID_NEW_TOKEN)}}; - case QUIC_DATA_RECEIVED_ON_WRITE_UNIDIRECTIONAL_STREAM: - return {true, - {static_cast<uint64_t>( - QUIC_DATA_RECEIVED_ON_WRITE_UNIDIRECTIONAL_STREAM)}}; - case QUIC_TRY_TO_WRITE_DATA_ON_READ_UNIDIRECTIONAL_STREAM: - return {true, - {static_cast<uint64_t>( - QUIC_TRY_TO_WRITE_DATA_ON_READ_UNIDIRECTIONAL_STREAM)}}; - case QUIC_INVALID_RETIRE_CONNECTION_ID_DATA: - return {true, - {static_cast<uint64_t>(QUIC_INVALID_RETIRE_CONNECTION_ID_DATA)}}; - case QUIC_STREAMS_BLOCKED_ERROR: - return {true, {static_cast<uint64_t>(QUIC_STREAMS_BLOCKED_ERROR)}}; - case QUIC_MAX_STREAMS_ERROR: - return {true, {static_cast<uint64_t>(QUIC_MAX_STREAMS_ERROR)}}; - case QUIC_HTTP_DECODER_ERROR: - return {true, {static_cast<uint64_t>(QUIC_HTTP_DECODER_ERROR)}}; - case QUIC_STALE_CONNECTION_CANCELLED: - return {true, {static_cast<uint64_t>(QUIC_STALE_CONNECTION_CANCELLED)}}; - case QUIC_IETF_GQUIC_ERROR_MISSING: - return {true, {static_cast<uint64_t>(QUIC_IETF_GQUIC_ERROR_MISSING)}}; - case QUIC_WINDOW_UPDATE_RECEIVED_ON_READ_UNIDIRECTIONAL_STREAM: - return {true, - {static_cast<uint64_t>( - QUIC_WINDOW_UPDATE_RECEIVED_ON_READ_UNIDIRECTIONAL_STREAM)}}; - case QUIC_TOO_MANY_BUFFERED_CONTROL_FRAMES: - return {true, - {static_cast<uint64_t>(QUIC_TOO_MANY_BUFFERED_CONTROL_FRAMES)}}; - case QUIC_TRANSPORT_INVALID_CLIENT_INDICATION: - return {false, {0u}}; - case QUIC_QPACK_DECOMPRESSION_FAILED: - return { - false, - {static_cast<uint64_t>(IETF_QUIC_HTTP_QPACK_DECOMPRESSION_FAILED)}}; - case QUIC_QPACK_ENCODER_STREAM_ERROR: - return { - false, - {static_cast<uint64_t>(IETF_QUIC_HTTP_QPACK_ENCODER_STREAM_ERROR)}}; - case QUIC_QPACK_DECODER_STREAM_ERROR: - return { - false, - {static_cast<uint64_t>(IETF_QUIC_HTTP_QPACK_DECODER_STREAM_ERROR)}}; - case QUIC_STREAM_DATA_BEYOND_CLOSE_OFFSET: - return {true, - {static_cast<uint64_t>(QUIC_STREAM_DATA_BEYOND_CLOSE_OFFSET)}}; - case QUIC_STREAM_MULTIPLE_OFFSET: - return {true, {static_cast<uint64_t>(QUIC_STREAM_MULTIPLE_OFFSET)}}; - case QUIC_HTTP_FRAME_TOO_LARGE: - return {false, - {static_cast<uint64_t>( - QuicHttp3ErrorCode::IETF_QUIC_HTTP3_EXCESSIVE_LOAD)}}; - case QUIC_HTTP_FRAME_ERROR: - return {false, - {static_cast<uint64_t>( - QuicHttp3ErrorCode::IETF_QUIC_HTTP3_FRAME_ERROR)}}; - case QUIC_HTTP_FRAME_UNEXPECTED_ON_SPDY_STREAM: - return {false, - {static_cast<uint64_t>( - QuicHttp3ErrorCode::IETF_QUIC_HTTP3_FRAME_UNEXPECTED)}}; - case QUIC_HTTP_FRAME_UNEXPECTED_ON_CONTROL_STREAM: - return {false, - {static_cast<uint64_t>( - QuicHttp3ErrorCode::IETF_QUIC_HTTP3_FRAME_UNEXPECTED)}}; - case QUIC_HTTP_INVALID_FRAME_SEQUENCE_ON_SPDY_STREAM: - return {false, - {static_cast<uint64_t>( - QuicHttp3ErrorCode::IETF_QUIC_HTTP3_FRAME_UNEXPECTED)}}; - case QUIC_HTTP_INVALID_FRAME_SEQUENCE_ON_CONTROL_STREAM: - return {false, - {static_cast<uint64_t>( - QuicHttp3ErrorCode::IETF_QUIC_HTTP3_FRAME_UNEXPECTED)}}; - case QUIC_HTTP_DUPLICATE_UNIDIRECTIONAL_STREAM: - return {false, - {static_cast<uint64_t>( - QuicHttp3ErrorCode::IETF_QUIC_HTTP3_STREAM_CREATION_ERROR)}}; - case QUIC_HTTP_SERVER_INITIATED_BIDIRECTIONAL_STREAM: - return {false, - {static_cast<uint64_t>( - QuicHttp3ErrorCode::IETF_QUIC_HTTP3_STREAM_CREATION_ERROR)}}; - case QUIC_HTTP_STREAM_WRONG_DIRECTION: - return {true, {static_cast<uint64_t>(STREAM_STATE_ERROR)}}; - case QUIC_HTTP_CLOSED_CRITICAL_STREAM: - return {false, - {static_cast<uint64_t>( - QuicHttp3ErrorCode::IETF_QUIC_HTTP3_CLOSED_CRITICAL_STREAM)}}; - case QUIC_HTTP_MISSING_SETTINGS_FRAME: - return {false, - {static_cast<uint64_t>( - QuicHttp3ErrorCode::IETF_QUIC_HTTP3_MISSING_SETTINGS)}}; - case QUIC_HTTP_DUPLICATE_SETTING_IDENTIFIER: - return {false, - {static_cast<uint64_t>( - QuicHttp3ErrorCode::IETF_QUIC_HTTP3_SETTINGS_ERROR)}}; - case QUIC_HPACK_INDEX_VARINT_ERROR: - return {false, {static_cast<uint64_t>(QUIC_HPACK_INDEX_VARINT_ERROR)}}; - case QUIC_HPACK_NAME_LENGTH_VARINT_ERROR: - return {false, - {static_cast<uint64_t>(QUIC_HPACK_NAME_LENGTH_VARINT_ERROR)}}; - case QUIC_HPACK_VALUE_LENGTH_VARINT_ERROR: - return {false, - {static_cast<uint64_t>(QUIC_HPACK_VALUE_LENGTH_VARINT_ERROR)}}; - case QUIC_HPACK_NAME_TOO_LONG: - return {false, {static_cast<uint64_t>(QUIC_HPACK_NAME_TOO_LONG)}}; - case QUIC_HPACK_VALUE_TOO_LONG: - return {false, {static_cast<uint64_t>(QUIC_HPACK_VALUE_TOO_LONG)}}; - case QUIC_HPACK_NAME_HUFFMAN_ERROR: - return {false, {static_cast<uint64_t>(QUIC_HPACK_NAME_HUFFMAN_ERROR)}}; - case QUIC_HPACK_VALUE_HUFFMAN_ERROR: - return {false, {static_cast<uint64_t>(QUIC_HPACK_VALUE_HUFFMAN_ERROR)}}; - case QUIC_HPACK_MISSING_DYNAMIC_TABLE_SIZE_UPDATE: - return {false, - {static_cast<uint64_t>( - QUIC_HPACK_MISSING_DYNAMIC_TABLE_SIZE_UPDATE)}}; - case QUIC_HPACK_INVALID_INDEX: - return {false, {static_cast<uint64_t>(QUIC_HPACK_INVALID_INDEX)}}; - case QUIC_HPACK_INVALID_NAME_INDEX: - return {false, {static_cast<uint64_t>(QUIC_HPACK_INVALID_NAME_INDEX)}}; - case QUIC_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_NOT_ALLOWED: - return {false, - {static_cast<uint64_t>( - QUIC_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_NOT_ALLOWED)}}; - case QUIC_HPACK_INITIAL_TABLE_SIZE_UPDATE_IS_ABOVE_LOW_WATER_MARK: - return { - false, - {static_cast<uint64_t>( - QUIC_HPACK_INITIAL_TABLE_SIZE_UPDATE_IS_ABOVE_LOW_WATER_MARK)}}; - case QUIC_HPACK_TABLE_SIZE_UPDATE_IS_ABOVE_ACKNOWLEDGED_SETTING: - return {false, - {static_cast<uint64_t>( - QUIC_HPACK_TABLE_SIZE_UPDATE_IS_ABOVE_ACKNOWLEDGED_SETTING)}}; - case QUIC_HPACK_TRUNCATED_BLOCK: - return {false, {static_cast<uint64_t>(QUIC_HPACK_TRUNCATED_BLOCK)}}; - case QUIC_HPACK_FRAGMENT_TOO_LONG: - return {false, {static_cast<uint64_t>(QUIC_HPACK_FRAGMENT_TOO_LONG)}}; - case QUIC_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT: - return {false, - {static_cast<uint64_t>( - QUIC_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT)}}; - case QUIC_LAST_ERROR: - return {false, {static_cast<uint64_t>(QUIC_LAST_ERROR)}}; - } - // If it's an unknown code, indicate it's an application error code. - return {false, {NO_IETF_QUIC_ERROR}}; -} - std::string QuicIetfFrameTypeString(QuicIetfFrameType t) { if (IS_IETF_STREAM_FRAME(t)) { return "IETF_STREAM"; @@ -730,4 +314,6 @@ std::ostream& operator<<(std::ostream& os, AddressChangeType type) { return os; } +#undef RETURN_STRING_LITERAL // undef for jumbo builds + } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_types.h b/chromium/net/third_party/quiche/src/quic/core/quic_types.h index 76d3bab90cc..f2919ef3766 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_types.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_types.h @@ -21,39 +21,42 @@ namespace quic { -typedef uint16_t QuicPacketLength; -typedef uint32_t QuicControlFrameId; -typedef uint32_t QuicHeaderId; -typedef uint32_t QuicMessageId; -typedef uint64_t QuicDatagramFlowId; - -typedef uint32_t QuicStreamId; - -// Count of stream IDs. Used in MAX_STREAMS and STREAMS_BLOCKED -// frames. -typedef uint32_t QuicStreamCount; - -typedef uint64_t QuicByteCount; -typedef uint64_t QuicPacketCount; -typedef uint64_t QuicPublicResetNonceProof; -typedef uint64_t QuicStreamOffset; -typedef std::array<char, 32> DiversificationNonce; -typedef std::vector<std::pair<QuicPacketNumber, QuicTime>> PacketTimeVector; - -typedef uint64_t QuicIetfStreamDataLength; -typedef uint64_t QuicIetfStreamId; -typedef uint64_t QuicIetfStreamOffset; - -const size_t kQuicPathFrameBufferSize = 8; -typedef std::array<uint8_t, kQuicPathFrameBufferSize> QuicPathFrameBuffer; +using QuicPacketLength = uint16_t; +using QuicControlFrameId = uint32_t; +using QuicMessageId = uint32_t; +using QuicDatagramFlowId = uint64_t; + +// IMPORTANT: IETF QUIC defines stream IDs and stream counts as being unsigned +// 62-bit numbers. However, we have decided to only support up to 2^32-1 streams +// in order to reduce the size of data structures such as QuicStreamFrame +// and QuicTransmissionInfo, as that allows them to fit in cache lines and has +// visible perfomance impact. +using QuicStreamId = uint32_t; + +// Count of stream IDs. Used in MAX_STREAMS and STREAMS_BLOCKED frames. +using QuicStreamCount = QuicStreamId; + +using QuicByteCount = uint64_t; +using QuicPacketCount = uint64_t; +using QuicPublicResetNonceProof = uint64_t; +using QuicStreamOffset = uint64_t; +using DiversificationNonce = std::array<char, 32>; +using PacketTimeVector = std::vector<std::pair<QuicPacketNumber, QuicTime>>; + +enum : size_t { kQuicPathFrameBufferSize = 8 }; +using QuicPathFrameBuffer = std::array<uint8_t, kQuicPathFrameBufferSize>; // Application error code used in the QUIC Stop Sending frame. -typedef uint16_t QuicApplicationErrorCode; +using QuicApplicationErrorCode = uint16_t; // The connection id sequence number specifies the order that connection // ids must be used in. This is also the sequence number carried in // the IETF QUIC NEW_CONNECTION_ID and RETIRE_CONNECTION_ID frames. -typedef uint64_t QuicConnectionIdSequenceNumber; +using QuicConnectionIdSequenceNumber = uint64_t; + +// A custom data that represents application-specific settings. +// In HTTP/3 for example, it includes the encoded SETTINGS. +using ApplicationState = std::vector<uint8_t>; // A struct for functions which consume data payloads and fins. struct QUIC_EXPORT_PRIVATE QuicConsumedData { @@ -183,18 +186,32 @@ enum HasRetransmittableData : uint8_t { enum IsHandshake : uint8_t { NOT_HANDSHAKE, IS_HANDSHAKE }; enum class Perspective : uint8_t { IS_SERVER, IS_CLIENT }; + +QUIC_EXPORT_PRIVATE std::string PerspectiveToString(Perspective perspective); QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, - const Perspective& s); + const Perspective& perspective); // Describes whether a ConnectionClose was originated by the peer. enum class ConnectionCloseSource { FROM_PEER, FROM_SELF }; +QUIC_EXPORT_PRIVATE std::string ConnectionCloseSourceToString( + ConnectionCloseSource connection_close_source); +QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const ConnectionCloseSource& connection_close_source); + // Should a connection be closed silently or not. enum class ConnectionCloseBehavior { SILENT_CLOSE, SEND_CONNECTION_CLOSE_PACKET }; +QUIC_EXPORT_PRIVATE std::string ConnectionCloseBehaviorToString( + ConnectionCloseBehavior connection_close_behavior); +QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const ConnectionCloseBehavior& connection_close_behavior); + enum QuicFrameType : uint8_t { // Regular frame types. The values set here cannot change without the // introduction of a new QUIC version. @@ -313,13 +330,12 @@ enum QuicVariableLengthIntegerLength : uint8_t { VARIABLE_LENGTH_INTEGER_LENGTH_2 = 2, VARIABLE_LENGTH_INTEGER_LENGTH_4 = 4, VARIABLE_LENGTH_INTEGER_LENGTH_8 = 8, -}; -// By default we write the IETF long header length using the 2-byte encoding -// of variable length integers, even when the length is below 64, which allows -// us to fill in the length before knowing what the length actually is. -const QuicVariableLengthIntegerLength kQuicDefaultLongHeaderLengthLength = - VARIABLE_LENGTH_INTEGER_LENGTH_2; + // By default we write the IETF long header length using the 2-byte encoding + // of variable length integers, even when the length is below 64, which allows + // us to fill in the length before knowing what the length actually is. + kQuicDefaultLongHeaderLengthLength = VARIABLE_LENGTH_INTEGER_LENGTH_2, +}; enum QuicPacketNumberLength : uint8_t { PACKET_1BYTE_PACKET_NUMBER = 1, @@ -529,7 +545,7 @@ struct QUIC_EXPORT_PRIVATE AckedPacket { }; // A vector of acked packets. -typedef QuicInlinedVector<AckedPacket, 2> AckedPacketVector; +using AckedPacketVector = QuicInlinedVector<AckedPacket, 2>; // Information about a newly lost packet. struct QUIC_EXPORT_PRIVATE LostPacket { @@ -546,46 +562,7 @@ struct QUIC_EXPORT_PRIVATE LostPacket { }; // A vector of lost packets. -typedef QuicInlinedVector<LostPacket, 2> LostPacketVector; - -enum QuicIetfTransportErrorCodes : uint64_t { - NO_IETF_QUIC_ERROR = 0x0, - INTERNAL_ERROR = 0x1, - SERVER_BUSY_ERROR = 0x2, - FLOW_CONTROL_ERROR = 0x3, - STREAM_LIMIT_ERROR = 0x4, - STREAM_STATE_ERROR = 0x5, - FINAL_SIZE_ERROR = 0x6, - FRAME_ENCODING_ERROR = 0x7, - TRANSPORT_PARAMETER_ERROR = 0x8, - CONNECTION_ID_LIMIT_ERROR = 0x9, - PROTOCOL_VIOLATION = 0xA, - INVALID_TOKEN = 0xB, - CRYPTO_BUFFER_EXCEEDED = 0xD, - CRYPTO_ERROR_FIRST = 0x100, - CRYPTO_ERROR_LAST = 0x1FF, -}; -QUIC_EXPORT_PRIVATE std::string QuicIetfTransportErrorCodeString( - QuicIetfTransportErrorCodes c); - -QUIC_EXPORT_PRIVATE std::ostream& operator<<( - std::ostream& os, - const QuicIetfTransportErrorCodes& c); - -// Returns the mapping of the QuicErrorCode to an IETF TransportErrorCode. If -// first element of the pair is false, it means that an IETF Application Close -// should be done instead. - -struct QUIC_EXPORT_PRIVATE QuicErrorCodeToIetfMapping { - bool is_transport_close_; - union { - uint64_t application_error_code_; - QuicIetfTransportErrorCodes transport_error_code_; - }; -}; - -QUIC_EXPORT_PRIVATE QuicErrorCodeToIetfMapping -QuicErrorCodeToTransportErrorCode(QuicErrorCode error); +using LostPacketVector = QuicInlinedVector<LostPacket, 2>; // Please note, this value cannot used directly for packet serialization. enum QuicLongHeaderType : uint8_t { @@ -716,11 +693,11 @@ QUIC_EXPORT_PRIVATE std::string SerializedPacketFateToString( SerializedPacketFate fate); // There are three different forms of CONNECTION_CLOSE. -typedef enum QuicConnectionCloseType { +enum QuicConnectionCloseType { GOOGLE_QUIC_CONNECTION_CLOSE = 0, IETF_QUIC_TRANSPORT_CONNECTION_CLOSE = 1, IETF_QUIC_APPLICATION_CONNECTION_CLOSE = 2 -} QuicConnectionCloseType; +}; QUIC_EXPORT_PRIVATE std::ostream& operator<<( std::ostream& os, @@ -750,6 +727,13 @@ enum HandshakeState { HANDSHAKE_CONFIRMED, }; +struct QUIC_NO_EXPORT NextReleaseTimeResult { + // The ideal release time of the packet being sent. + QuicTime release_time; + // Whether it is allowed to send the packet before release_time. + bool allow_burst; +}; + } // namespace quic #endif // QUICHE_QUIC_CORE_QUIC_TYPES_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_types_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_types_test.cc deleted file mode 100644 index dc37c43e24e..00000000000 --- a/chromium/net/third_party/quiche/src/quic/core/quic_types_test.cc +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/quiche/src/quic/core/quic_types.h" - -#include <cstdint> - -#include "third_party/boringssl/src/include/openssl/ssl.h" -#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" - -namespace quic { -namespace test { -namespace { - -class QuicTypesTest : public QuicTest {}; - -TEST_F(QuicTypesTest, QuicIetfTransportErrorCodeString) { - EXPECT_EQ("Private(65280)", - QuicIetfTransportErrorCodeString( - static_cast<quic::QuicIetfTransportErrorCodes>(0xff00u))); - - EXPECT_EQ("CRYPTO_ERROR(missing extension)", - QuicIetfTransportErrorCodeString( - static_cast<quic::QuicIetfTransportErrorCodes>( - CRYPTO_ERROR_FIRST + SSL_AD_MISSING_EXTENSION))); - - EXPECT_EQ("NO_IETF_QUIC_ERROR", - QuicIetfTransportErrorCodeString(NO_IETF_QUIC_ERROR)); - EXPECT_EQ("INTERNAL_ERROR", QuicIetfTransportErrorCodeString(INTERNAL_ERROR)); - EXPECT_EQ("SERVER_BUSY_ERROR", - QuicIetfTransportErrorCodeString(SERVER_BUSY_ERROR)); - EXPECT_EQ("FLOW_CONTROL_ERROR", - QuicIetfTransportErrorCodeString(FLOW_CONTROL_ERROR)); - EXPECT_EQ("STREAM_LIMIT_ERROR", - QuicIetfTransportErrorCodeString(STREAM_LIMIT_ERROR)); - EXPECT_EQ("STREAM_STATE_ERROR", - QuicIetfTransportErrorCodeString(STREAM_STATE_ERROR)); - EXPECT_EQ("FINAL_SIZE_ERROR", - QuicIetfTransportErrorCodeString(FINAL_SIZE_ERROR)); - EXPECT_EQ("FRAME_ENCODING_ERROR", - QuicIetfTransportErrorCodeString(FRAME_ENCODING_ERROR)); - EXPECT_EQ("TRANSPORT_PARAMETER_ERROR", - QuicIetfTransportErrorCodeString(TRANSPORT_PARAMETER_ERROR)); - EXPECT_EQ("CONNECTION_ID_LIMIT_ERROR", - QuicIetfTransportErrorCodeString(CONNECTION_ID_LIMIT_ERROR)); - EXPECT_EQ("PROTOCOL_VIOLATION", - QuicIetfTransportErrorCodeString(PROTOCOL_VIOLATION)); - EXPECT_EQ("INVALID_TOKEN", QuicIetfTransportErrorCodeString(INVALID_TOKEN)); - EXPECT_EQ("CRYPTO_BUFFER_EXCEEDED", - QuicIetfTransportErrorCodeString(CRYPTO_BUFFER_EXCEEDED)); - - EXPECT_EQ("Unknown(1024)", - QuicIetfTransportErrorCodeString( - static_cast<quic::QuicIetfTransportErrorCodes>(0x400))); -} - -} // namespace -} // namespace test -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.cc index 1dda8881066..0a014bebe78 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.cc @@ -20,7 +20,7 @@ QuicVersionManager::QuicVersionManager( enable_version_draft_25_( GetQuicReloadableFlag(quic_enable_version_draft_25_v3)), disable_version_q050_(GetQuicReloadableFlag(quic_disable_version_q050)), - enable_version_t050_(GetQuicReloadableFlag(quic_enable_version_t050)), + enable_version_t050_(GetQuicReloadableFlag(quic_enable_version_t050_v2)), disable_version_q049_(GetQuicReloadableFlag(quic_disable_version_q049)), disable_version_q048_(GetQuicReloadableFlag(quic_disable_version_q048)), disable_version_q046_(GetQuicReloadableFlag(quic_disable_version_q046)), @@ -44,6 +44,17 @@ const ParsedQuicVersionVector& QuicVersionManager::GetSupportedVersions() { return filtered_supported_versions_; } +const ParsedQuicVersionVector& +QuicVersionManager::GetSupportedVersionsWithQuicCrypto() { + MaybeRefilterSupportedVersions(); + return filtered_supported_versions_with_quic_crypto_; +} + +const std::vector<std::string>& QuicVersionManager::GetSupportedAlpns() { + MaybeRefilterSupportedVersions(); + return filtered_supported_alpns_; +} + void QuicVersionManager::MaybeRefilterSupportedVersions() { static_assert(SupportedVersions().size() == 8u, "Supported versions out of sync"); @@ -53,7 +64,8 @@ void QuicVersionManager::MaybeRefilterSupportedVersions() { GetQuicReloadableFlag(quic_enable_version_draft_25_v3) || disable_version_q050_ != GetQuicReloadableFlag(quic_disable_version_q050) || - enable_version_t050_ != GetQuicReloadableFlag(quic_enable_version_t050) || + enable_version_t050_ != + GetQuicReloadableFlag(quic_enable_version_t050_v2) || disable_version_q049_ != GetQuicReloadableFlag(quic_disable_version_q049) || disable_version_q048_ != @@ -67,7 +79,7 @@ void QuicVersionManager::MaybeRefilterSupportedVersions() { enable_version_draft_25_ = GetQuicReloadableFlag(quic_enable_version_draft_25_v3); disable_version_q050_ = GetQuicReloadableFlag(quic_disable_version_q050); - enable_version_t050_ = GetQuicReloadableFlag(quic_enable_version_t050); + enable_version_t050_ = GetQuicReloadableFlag(quic_enable_version_t050_v2); disable_version_q049_ = GetQuicReloadableFlag(quic_disable_version_q049); disable_version_q048_ = GetQuicReloadableFlag(quic_disable_version_q048); disable_version_q046_ = GetQuicReloadableFlag(quic_disable_version_q046); @@ -80,15 +92,25 @@ void QuicVersionManager::MaybeRefilterSupportedVersions() { void QuicVersionManager::RefilterSupportedVersions() { filtered_supported_versions_ = FilterSupportedVersions(allowed_supported_versions_); + filtered_supported_versions_with_quic_crypto_.clear(); filtered_transport_versions_.clear(); - for (ParsedQuicVersion version : filtered_supported_versions_) { + filtered_supported_alpns_.clear(); + for (const ParsedQuicVersion& version : filtered_supported_versions_) { auto transport_version = version.transport_version; if (std::find(filtered_transport_versions_.begin(), filtered_transport_versions_.end(), transport_version) == filtered_transport_versions_.end()) { filtered_transport_versions_.push_back(transport_version); } + if (version.handshake_protocol == PROTOCOL_QUIC_CRYPTO) { + filtered_supported_versions_with_quic_crypto_.push_back(version); + } + filtered_supported_alpns_.emplace_back(AlpnForVersion(version)); } } +void QuicVersionManager::AddCustomAlpn(const std::string& alpn) { + filtered_supported_alpns_.push_back(alpn); +} + } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h index 4d683745bdc..c5111edf260 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h @@ -26,6 +26,13 @@ class QUIC_EXPORT_PRIVATE QuicVersionManager { // as the versions passed to the constructor. const ParsedQuicVersionVector& GetSupportedVersions(); + // Returns currently supported versions using QUIC crypto. + const ParsedQuicVersionVector& GetSupportedVersionsWithQuicCrypto(); + + // Returns the list of supported ALPNs, based on the current supported + // versions and any custom additions by subclasses. + const std::vector<std::string>& GetSupportedAlpns(); + protected: // If the value of any reloadable flag is different from the cached value, // re-filter |filtered_supported_versions_| and update the cached flag values. @@ -39,6 +46,10 @@ class QUIC_EXPORT_PRIVATE QuicVersionManager { return filtered_transport_versions_; } + // Mechanism for subclasses to add custom ALPNs to the supported list. + // Should be called in constructor and RefilterSupportedVersions. + void AddCustomAlpn(const std::string& alpn); + private: // Cached value of reloadable flags. // quic_enable_version_draft_27 flag @@ -47,7 +58,7 @@ class QUIC_EXPORT_PRIVATE QuicVersionManager { bool enable_version_draft_25_; // quic_disable_version_q050 flag bool disable_version_q050_; - // quic_enable_version_t050 flag + // quic_enable_version_t050_v2 flag bool enable_version_t050_; // quic_disable_version_q049 flag bool disable_version_q049_; @@ -63,10 +74,15 @@ class QUIC_EXPORT_PRIVATE QuicVersionManager { // This vector contains QUIC versions which are currently supported based on // flags. ParsedQuicVersionVector filtered_supported_versions_; + // Currently supported versions using QUIC crypto. + ParsedQuicVersionVector filtered_supported_versions_with_quic_crypto_; // This vector contains the transport versions from // |filtered_supported_versions_|. No guarantees are made that the same // transport version isn't repeated. QuicTransportVersionVector filtered_transport_versions_; + // Contains the list of ALPNs corresponding to filtered_supported_versions_ + // with custom ALPNs added. + std::vector<std::string> filtered_supported_alpns_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager_test.cc index 98dc4a348ec..3a8e98ff520 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager_test.cc @@ -9,6 +9,8 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h" +using ::testing::ElementsAre; + namespace quic { namespace test { namespace { @@ -20,7 +22,7 @@ TEST_F(QuicVersionManagerTest, QuicVersionManager) { "Supported versions out of sync"); SetQuicReloadableFlag(quic_enable_version_draft_27, false); SetQuicReloadableFlag(quic_enable_version_draft_25_v3, false); - SetQuicReloadableFlag(quic_enable_version_t050, false); + SetQuicReloadableFlag(quic_enable_version_t050_v2, false); SetQuicReloadableFlag(quic_disable_version_q050, false); SetQuicReloadableFlag(quic_disable_version_q049, false); SetQuicReloadableFlag(quic_disable_version_q048, false); @@ -41,30 +43,59 @@ TEST_F(QuicVersionManagerTest, QuicVersionManager) { ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43)); EXPECT_EQ(expected_parsed_versions, manager.GetSupportedVersions()); + EXPECT_EQ(expected_parsed_versions, + manager.GetSupportedVersionsWithQuicCrypto()); EXPECT_EQ(FilterSupportedVersions(AllSupportedVersions()), manager.GetSupportedVersions()); + EXPECT_EQ(CurrentSupportedVersionsWithQuicCrypto(), + manager.GetSupportedVersionsWithQuicCrypto()); + EXPECT_THAT( + manager.GetSupportedAlpns(), + ElementsAre("h3-Q050", "h3-Q049", "h3-Q048", "h3-Q046", "h3-Q043")); SetQuicReloadableFlag(quic_enable_version_draft_27, true); - expected_parsed_versions.push_back( + expected_parsed_versions.insert( + expected_parsed_versions.begin(), ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27)); EXPECT_EQ(expected_parsed_versions, manager.GetSupportedVersions()); + EXPECT_EQ(expected_parsed_versions.size() - 1, + manager.GetSupportedVersionsWithQuicCrypto().size()); EXPECT_EQ(FilterSupportedVersions(AllSupportedVersions()), manager.GetSupportedVersions()); + EXPECT_EQ(CurrentSupportedVersionsWithQuicCrypto(), + manager.GetSupportedVersionsWithQuicCrypto()); + EXPECT_THAT(manager.GetSupportedAlpns(), + ElementsAre("h3-27", "h3-Q050", "h3-Q049", "h3-Q048", "h3-Q046", + "h3-Q043")); SetQuicReloadableFlag(quic_enable_version_draft_25_v3, true); - expected_parsed_versions.push_back( + expected_parsed_versions.insert( + expected_parsed_versions.begin() + 1, ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25)); EXPECT_EQ(expected_parsed_versions, manager.GetSupportedVersions()); - EXPECT_EQ(FilterSupportedVersions(AllSupportedVersions()), - manager.GetSupportedVersions()); + EXPECT_EQ(expected_parsed_versions.size() - 2, + manager.GetSupportedVersionsWithQuicCrypto().size()); + EXPECT_EQ(CurrentSupportedVersionsWithQuicCrypto(), + manager.GetSupportedVersionsWithQuicCrypto()); + EXPECT_THAT(manager.GetSupportedAlpns(), + ElementsAre("h3-27", "h3-25", "h3-Q050", "h3-Q049", "h3-Q048", + "h3-Q046", "h3-Q043")); - SetQuicReloadableFlag(quic_enable_version_t050, true); - expected_parsed_versions.push_back( + SetQuicReloadableFlag(quic_enable_version_t050_v2, true); + expected_parsed_versions.insert( + expected_parsed_versions.begin() + 2, ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50)); EXPECT_EQ(expected_parsed_versions, manager.GetSupportedVersions()); + EXPECT_EQ(expected_parsed_versions.size() - 3, + manager.GetSupportedVersionsWithQuicCrypto().size()); EXPECT_EQ(FilterSupportedVersions(AllSupportedVersions()), manager.GetSupportedVersions()); + EXPECT_EQ(CurrentSupportedVersionsWithQuicCrypto(), + manager.GetSupportedVersionsWithQuicCrypto()); + EXPECT_THAT(manager.GetSupportedAlpns(), + ElementsAre("h3-27", "h3-25", "h3-T050", "h3-Q050", "h3-Q049", + "h3-Q048", "h3-Q046", "h3-Q043")); } } // namespace diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_versions.cc b/chromium/net/third_party/quiche/src/quic/core/quic_versions.cc index 6dc67d92078..bf93e8383d2 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_versions.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_versions.cc @@ -158,6 +158,16 @@ bool ParsedQuicVersion::HasVarIntTransportParams() const { return transport_version >= QUIC_VERSION_IETF_DRAFT_27; } +bool ParsedQuicVersion::UsesTls() const { + DCHECK(IsKnown()); + return handshake_protocol == PROTOCOL_TLS1_3; +} + +bool ParsedQuicVersion::UsesQuicCrypto() const { + DCHECK(IsKnown()); + return handshake_protocol == PROTOCOL_QUIC_CRYPTO; +} + bool VersionHasLengthPrefixedConnectionIds( QuicTransportVersion transport_version) { DCHECK(transport_version != QUIC_VERSION_UNSUPPORTED); @@ -169,6 +179,24 @@ std::ostream& operator<<(std::ostream& os, const ParsedQuicVersion& version) { return os; } +std::ostream& operator<<(std::ostream& os, + const ParsedQuicVersionVector& versions) { + os << ParsedQuicVersionVectorToString(versions); + return os; +} + +std::ostream& operator<<(std::ostream& os, + const QuicVersionLabelVector& version_labels) { + os << QuicVersionLabelVectorToString(version_labels); + return os; +} + +std::ostream& operator<<(std::ostream& os, + const QuicTransportVersionVector& transport_versions) { + os << QuicTransportVersionVectorToString(transport_versions); + return os; +} + QuicVersionLabel CreateQuicVersionLabel(ParsedQuicVersion parsed_version) { char proto = 0; switch (parsed_version.handshake_protocol) { @@ -251,6 +279,17 @@ ParsedQuicVersionVector CurrentSupportedVersionsWithQuicCrypto() { return versions; } +ParsedQuicVersionVector AllSupportedVersionsWithTls() { + ParsedQuicVersionVector versions; + for (const ParsedQuicVersion& version : AllSupportedVersions()) { + if (version.handshake_protocol == PROTOCOL_TLS1_3) { + versions.push_back(version); + } + } + QUIC_BUG_IF(versions.empty()) << "No version with TLS handshake found."; + return versions; +} + ParsedQuicVersionVector CurrentSupportedVersionsWithTls() { ParsedQuicVersionVector versions; for (const ParsedQuicVersion& version : CurrentSupportedVersions()) { @@ -369,7 +408,7 @@ ParsedQuicVersionVector FilterSupportedVersions( filtered_versions.push_back(version); } } else { - if (GetQuicReloadableFlag(quic_enable_version_t050)) { + if (GetQuicReloadableFlag(quic_enable_version_t050_v2)) { filtered_versions.push_back(version); } } @@ -619,7 +658,7 @@ void QuicEnableVersion(ParsedQuicVersion parsed_version) { if (parsed_version.handshake_protocol == PROTOCOL_QUIC_CRYPTO) { SetQuicReloadableFlag(quic_disable_version_q050, false); } else { - SetQuicReloadableFlag(quic_enable_version_t050, true); + SetQuicReloadableFlag(quic_enable_version_t050_v2, true); } } else if (parsed_version.transport_version == QUIC_VERSION_49) { SetQuicReloadableFlag(quic_disable_version_q049, false); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_versions.h b/chromium/net/third_party/quiche/src/quic/core/quic_versions.h index 7850b416fc9..5f3a9689198 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_versions.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_versions.h @@ -330,6 +330,12 @@ struct QUIC_EXPORT_PRIVATE ParsedQuicVersion { // Returns true if this version uses variable-length integers when // encoding transport parameter types and lengths. bool HasVarIntTransportParams() const; + + // Returns whether this version uses PROTOCOL_TLS1_3. + bool UsesTls() const; + + // Returns whether this version uses PROTOCOL_QUIC_CRYPTO. + bool UsesQuicCrypto() const; }; QUIC_EXPORT_PRIVATE ParsedQuicVersion UnsupportedQuicVersion(); @@ -341,31 +347,43 @@ QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, using ParsedQuicVersionVector = std::vector<ParsedQuicVersion>; +QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const ParsedQuicVersionVector& versions); + // Representation of the on-the-wire QUIC version number. Will be written/read // to the wire in network-byte-order. using QuicVersionLabel = uint32_t; using QuicVersionLabelVector = std::vector<QuicVersionLabel>; +QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const QuicVersionLabelVector& version_labels); + // This vector contains all crypto handshake protocols that are supported. constexpr std::array<HandshakeProtocol, 2> SupportedHandshakeProtocols() { - return {PROTOCOL_QUIC_CRYPTO, PROTOCOL_TLS1_3}; + return {PROTOCOL_TLS1_3, PROTOCOL_QUIC_CRYPTO}; } constexpr std::array<ParsedQuicVersion, 8> SupportedVersions() { return { + ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27), + ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25), + ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50), ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50), ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49), ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48), ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46), ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43), - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27), - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25), - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50), }; } using QuicTransportVersionVector = std::vector<QuicTransportVersion>; +QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const QuicTransportVersionVector& transport_versions); + // Returns a vector of QUIC versions in kSupportedTransportVersions. QUIC_EXPORT_PRIVATE QuicTransportVersionVector AllSupportedTransportVersions(); @@ -395,6 +413,10 @@ AllSupportedVersionsWithQuicCrypto(); QUIC_EXPORT_PRIVATE ParsedQuicVersionVector CurrentSupportedVersionsWithQuicCrypto(); +// Returns a subset of AllSupportedVersions() with +// handshake_protocol == PROTOCOL_TLS1_3, in the same order. +QUIC_EXPORT_PRIVATE ParsedQuicVersionVector AllSupportedVersionsWithTls(); + // Returns a subset of CurrentSupportedVersions() with handshake_protocol == // PROTOCOL_TLS1_3. QUIC_EXPORT_PRIVATE ParsedQuicVersionVector CurrentSupportedVersionsWithTls(); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc index 216b0800bbe..3a07221ab94 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc @@ -83,6 +83,65 @@ TEST_F(QuicVersionsTest, KnownAndValid) { static_cast<QuicTransportVersion>(99))); } +TEST_F(QuicVersionsTest, Features) { + ParsedQuicVersion parsed_version_q043 = + ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43); + ParsedQuicVersion parsed_version_draft_27 = + ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27); + + EXPECT_TRUE(parsed_version_q043.IsKnown()); + EXPECT_FALSE(parsed_version_q043.KnowsWhichDecrypterToUse()); + EXPECT_FALSE(parsed_version_q043.UsesInitialObfuscators()); + EXPECT_FALSE(parsed_version_q043.AllowsLowFlowControlLimits()); + EXPECT_FALSE(parsed_version_q043.HasHeaderProtection()); + EXPECT_FALSE(parsed_version_q043.SupportsRetry()); + EXPECT_FALSE(parsed_version_q043.HasRetryIntegrityTag()); + EXPECT_FALSE( + parsed_version_q043.SendsVariableLengthPacketNumberInLongHeader()); + EXPECT_FALSE(parsed_version_q043.AllowsVariableLengthConnectionIds()); + EXPECT_FALSE(parsed_version_q043.SupportsClientConnectionIds()); + EXPECT_FALSE(parsed_version_q043.HasLengthPrefixedConnectionIds()); + EXPECT_FALSE(parsed_version_q043.SupportsAntiAmplificationLimit()); + EXPECT_FALSE(parsed_version_q043.CanSendCoalescedPackets()); + EXPECT_TRUE(parsed_version_q043.SupportsGoogleAltSvcFormat()); + EXPECT_FALSE(parsed_version_q043.HasIetfInvariantHeader()); + EXPECT_FALSE(parsed_version_q043.SupportsMessageFrames()); + EXPECT_FALSE(parsed_version_q043.UsesHttp3()); + EXPECT_FALSE(parsed_version_q043.HasLongHeaderLengths()); + EXPECT_FALSE(parsed_version_q043.UsesCryptoFrames()); + EXPECT_FALSE(parsed_version_q043.HasIetfQuicFrames()); + EXPECT_FALSE(parsed_version_q043.HasHandshakeDone()); + EXPECT_FALSE(parsed_version_q043.HasVarIntTransportParams()); + EXPECT_FALSE(parsed_version_q043.UsesTls()); + EXPECT_TRUE(parsed_version_q043.UsesQuicCrypto()); + + EXPECT_TRUE(parsed_version_draft_27.IsKnown()); + EXPECT_TRUE(parsed_version_draft_27.KnowsWhichDecrypterToUse()); + EXPECT_TRUE(parsed_version_draft_27.UsesInitialObfuscators()); + EXPECT_TRUE(parsed_version_draft_27.AllowsLowFlowControlLimits()); + EXPECT_TRUE(parsed_version_draft_27.HasHeaderProtection()); + EXPECT_TRUE(parsed_version_draft_27.SupportsRetry()); + EXPECT_TRUE(parsed_version_draft_27.HasRetryIntegrityTag()); + EXPECT_TRUE( + parsed_version_draft_27.SendsVariableLengthPacketNumberInLongHeader()); + EXPECT_TRUE(parsed_version_draft_27.AllowsVariableLengthConnectionIds()); + EXPECT_TRUE(parsed_version_draft_27.SupportsClientConnectionIds()); + EXPECT_TRUE(parsed_version_draft_27.HasLengthPrefixedConnectionIds()); + EXPECT_TRUE(parsed_version_draft_27.SupportsAntiAmplificationLimit()); + EXPECT_TRUE(parsed_version_draft_27.CanSendCoalescedPackets()); + EXPECT_FALSE(parsed_version_draft_27.SupportsGoogleAltSvcFormat()); + EXPECT_TRUE(parsed_version_draft_27.HasIetfInvariantHeader()); + EXPECT_TRUE(parsed_version_draft_27.SupportsMessageFrames()); + EXPECT_TRUE(parsed_version_draft_27.UsesHttp3()); + EXPECT_TRUE(parsed_version_draft_27.HasLongHeaderLengths()); + EXPECT_TRUE(parsed_version_draft_27.UsesCryptoFrames()); + EXPECT_TRUE(parsed_version_draft_27.HasIetfQuicFrames()); + EXPECT_TRUE(parsed_version_draft_27.HasHandshakeDone()); + EXPECT_TRUE(parsed_version_draft_27.HasVarIntTransportParams()); + EXPECT_TRUE(parsed_version_draft_27.UsesTls()); + EXPECT_FALSE(parsed_version_draft_27.UsesQuicCrypto()); +} + TEST_F(QuicVersionsTest, QuicVersionLabelToQuicTransportVersion) { // If you add a new version to the QuicTransportVersion enum you will need to // add a new case to QuicVersionLabelToQuicTransportVersion, otherwise this @@ -318,6 +377,10 @@ TEST_F(QuicVersionsTest, QuicVersionLabelToString) { QuicVersionLabelVectorToString(version_labels, ":", 2)); EXPECT_EQ("Q035|Q037|...", QuicVersionLabelVectorToString(version_labels, "|", 1)); + + std::ostringstream os; + os << version_labels; + EXPECT_EQ("Q035,Q037,T038", os.str()); } TEST_F(QuicVersionsTest, QuicVersionToString) { @@ -346,6 +409,10 @@ TEST_F(QuicVersionsTest, QuicVersionToString) { EXPECT_NE("QUIC_VERSION_UNSUPPORTED", QuicVersionToString(transport_version)); } + + std::ostringstream os; + os << versions_vector; + EXPECT_EQ("QUIC_VERSION_UNSUPPORTED,QUIC_VERSION_43", os.str()); } TEST_F(QuicVersionsTest, ParsedQuicVersionToString) { @@ -368,6 +435,10 @@ TEST_F(QuicVersionsTest, ParsedQuicVersionToString) { for (const ParsedQuicVersion& version : AllSupportedVersions()) { EXPECT_NE("0", ParsedQuicVersionToString(version)); } + + std::ostringstream os; + os << versions_vector; + EXPECT_EQ("0,Q043", os.str()); } TEST_F(QuicVersionsTest, FilterSupportedVersionsAllVersions) { @@ -375,7 +446,7 @@ TEST_F(QuicVersionsTest, FilterSupportedVersionsAllVersions) { "Supported versions out of sync"); SetQuicReloadableFlag(quic_enable_version_draft_27, true); SetQuicReloadableFlag(quic_enable_version_draft_25_v3, true); - SetQuicReloadableFlag(quic_enable_version_t050, true); + SetQuicReloadableFlag(quic_enable_version_t050_v2, true); SetQuicReloadableFlag(quic_disable_version_q050, false); SetQuicReloadableFlag(quic_disable_version_q049, false); SetQuicReloadableFlag(quic_disable_version_q048, false); @@ -384,6 +455,12 @@ TEST_F(QuicVersionsTest, FilterSupportedVersionsAllVersions) { ParsedQuicVersionVector expected_parsed_versions; expected_parsed_versions.push_back( + ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27)); + expected_parsed_versions.push_back( + ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25)); + expected_parsed_versions.push_back( + ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50)); + expected_parsed_versions.push_back( ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50)); expected_parsed_versions.push_back( ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49)); @@ -393,12 +470,6 @@ TEST_F(QuicVersionsTest, FilterSupportedVersionsAllVersions) { ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46)); expected_parsed_versions.push_back( ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43)); - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27)); - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25)); - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50)); ASSERT_EQ(expected_parsed_versions, FilterSupportedVersions(AllSupportedVersions())); @@ -410,7 +481,7 @@ TEST_F(QuicVersionsTest, FilterSupportedVersionsNo99) { "Supported versions out of sync"); SetQuicReloadableFlag(quic_enable_version_draft_27, false); SetQuicReloadableFlag(quic_enable_version_draft_25_v3, true); - SetQuicReloadableFlag(quic_enable_version_t050, true); + SetQuicReloadableFlag(quic_enable_version_t050_v2, true); SetQuicReloadableFlag(quic_disable_version_q050, false); SetQuicReloadableFlag(quic_disable_version_q049, false); SetQuicReloadableFlag(quic_disable_version_q048, false); @@ -419,6 +490,10 @@ TEST_F(QuicVersionsTest, FilterSupportedVersionsNo99) { ParsedQuicVersionVector expected_parsed_versions; expected_parsed_versions.push_back( + ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25)); + expected_parsed_versions.push_back( + ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50)); + expected_parsed_versions.push_back( ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50)); expected_parsed_versions.push_back( ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49)); @@ -428,10 +503,6 @@ TEST_F(QuicVersionsTest, FilterSupportedVersionsNo99) { ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46)); expected_parsed_versions.push_back( ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43)); - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25)); - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50)); ASSERT_EQ(expected_parsed_versions, FilterSupportedVersions(AllSupportedVersions())); @@ -442,7 +513,7 @@ TEST_F(QuicVersionsTest, FilterSupportedVersionsNoFlags) { "Supported versions out of sync"); SetQuicReloadableFlag(quic_enable_version_draft_27, false); SetQuicReloadableFlag(quic_enable_version_draft_25_v3, false); - SetQuicReloadableFlag(quic_enable_version_t050, false); + SetQuicReloadableFlag(quic_enable_version_t050_v2, false); SetQuicReloadableFlag(quic_disable_version_q050, false); SetQuicReloadableFlag(quic_disable_version_q049, false); SetQuicReloadableFlag(quic_disable_version_q048, false); @@ -574,9 +645,9 @@ TEST_F(QuicVersionsTest, QuicEnableVersion) { { QuicFlagSaver flag_saver; - SetQuicReloadableFlag(quic_enable_version_t050, false); + SetQuicReloadableFlag(quic_enable_version_t050_v2, false); QuicEnableVersion(parsed_version_t050); - EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_t050)); + EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_t050_v2)); } { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.h b/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.h index c98711292f3..4100df0fc96 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.h @@ -66,6 +66,10 @@ class QUIC_EXPORT_PRIVATE QuicWriteBlockedList { return priority_write_scheduler_->ShouldYield(id); } + spdy::SpdyPriority GetSpdyPriorityofStream(QuicStreamId id) const { + return priority_write_scheduler_->GetStreamPrecedence(id).spdy3_priority(); + } + // Switches write scheduler. This can only be called before any stream is // registered. bool SwitchWriteScheduler(spdy::WriteSchedulerType type, @@ -145,7 +149,8 @@ class QUIC_EXPORT_PRIVATE QuicWriteBlockedList { void RegisterStream(QuicStreamId stream_id, bool is_static_stream, const spdy::SpdyStreamPrecedence& precedence) { - DCHECK(!priority_write_scheduler_->StreamRegistered(stream_id)); + DCHECK(!priority_write_scheduler_->StreamRegistered(stream_id)) + << "stream " << stream_id << " already registered"; DCHECK(PrecedenceMatchesSchedulerType(precedence)); if (is_static_stream) { static_stream_collection_.Register(stream_id); diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.cc b/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.cc new file mode 100644 index 00000000000..7c10d2c8e0b --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.cc @@ -0,0 +1,395 @@ +// Copyright (c) 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/core/tls_chlo_extractor.h" +#include <cstring> +#include <memory> + +#include "third_party/boringssl/src/include/openssl/ssl.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.h" +#include "net/third_party/quiche/src/quic/core/quic_data_reader.h" +#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" +#include "net/third_party/quiche/src/quic/core/quic_framer.h" +#include "net/third_party/quiche/src/quic/core/quic_time.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/core/quic_versions.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h" + +namespace quic { + +TlsChloExtractor::TlsChloExtractor() + : crypto_stream_sequencer_(this), + state_(State::kInitial), + parsed_crypto_frame_in_this_packet_(false) {} + +TlsChloExtractor::TlsChloExtractor(TlsChloExtractor&& other) + : TlsChloExtractor() { + *this = std::move(other); +} + +TlsChloExtractor& TlsChloExtractor::operator=(TlsChloExtractor&& other) { + framer_ = std::move(other.framer_); + if (framer_) { + framer_->set_visitor(this); + } + crypto_stream_sequencer_ = std::move(other.crypto_stream_sequencer_); + crypto_stream_sequencer_.set_stream(this); + ssl_ = std::move(other.ssl_); + if (ssl_) { + std::pair<SSL_CTX*, int> shared_handles = GetSharedSslHandles(); + int ex_data_index = shared_handles.second; + const int rv = SSL_set_ex_data(ssl_.get(), ex_data_index, this); + CHECK_EQ(rv, 1) << "Internal allocation failure in SSL_set_ex_data"; + } + state_ = other.state_; + error_details_ = std::move(other.error_details_); + parsed_crypto_frame_in_this_packet_ = + other.parsed_crypto_frame_in_this_packet_; + alpns_ = std::move(other.alpns_); + server_name_ = std::move(other.server_name_); + return *this; +} + +void TlsChloExtractor::IngestPacket(const ParsedQuicVersion& version, + const QuicReceivedPacket& packet) { + if (state_ == State::kUnrecoverableFailure) { + QUIC_DLOG(ERROR) << "Not ingesting packet after unrecoverable error"; + return; + } + if (version == UnsupportedQuicVersion()) { + QUIC_DLOG(ERROR) << "Not ingesting packet with unsupported version"; + return; + } + if (version.handshake_protocol != PROTOCOL_TLS1_3) { + QUIC_DLOG(ERROR) << "Not ingesting packet with non-TLS version " << version; + return; + } + if (framer_) { + // This is not the first packet we have ingested, check if version matches. + if (!framer_->IsSupportedVersion(version)) { + QUIC_DLOG(ERROR) + << "Not ingesting packet with version mismatch, expected " + << framer_->version() << ", got " << version; + return; + } + } else { + // This is the first packet we have ingested, setup parser. + framer_ = std::make_unique<QuicFramer>( + ParsedQuicVersionVector{version}, QuicTime::Zero(), + Perspective::IS_SERVER, /*expected_server_connection_id_length=*/0); + // Note that expected_server_connection_id_length only matters for short + // headers and we explicitly drop those so we can pass any value here. + framer_->set_visitor(this); + } + + // When the framer parses |packet|, if it sees a CRYPTO frame it will call + // OnCryptoFrame below and that will set parsed_crypto_frame_in_this_packet_ + // to true. + parsed_crypto_frame_in_this_packet_ = false; + const bool parse_success = framer_->ProcessPacket(packet); + if (state_ == State::kInitial && parsed_crypto_frame_in_this_packet_) { + // If we parsed a CRYPTO frame but didn't advance the state from initial, + // then it means that we will need more packets to reassemble the full CHLO, + // so we advance the state here. This can happen when the first packet + // received is not the first one in the crypto stream. This allows us to + // differentiate our state between single-packet CHLO and multi-packet CHLO. + state_ = State::kParsedPartialChloFragment; + } + + if (!parse_success) { + // This could be due to the packet being non-initial for example. + QUIC_DLOG(ERROR) << "Failed to process packet"; + return; + } +} + +// This is called when the framer parsed the unencrypted parts of the header. +bool TlsChloExtractor::OnUnauthenticatedPublicHeader( + const QuicPacketHeader& header) { + if (header.form != IETF_QUIC_LONG_HEADER_PACKET) { + QUIC_DLOG(ERROR) << "Not parsing non-long-header packet " << header; + return false; + } + if (header.long_packet_type != INITIAL) { + QUIC_DLOG(ERROR) << "Not parsing non-initial packet " << header; + return false; + } + // QuicFramer is constructed without knowledge of the server's connection ID + // so it needs to be set up here in order to decrypt the packet. + framer_->SetInitialObfuscators(header.destination_connection_id); + return true; +} + +// This is called by the framer if it detects a change in version during +// parsing. +bool TlsChloExtractor::OnProtocolVersionMismatch(ParsedQuicVersion version) { + // This should never be called because we already check versions in + // IngestPacket. + QUIC_BUG << "Unexpected version mismatch, expected " << framer_->version() + << ", got " << version; + return false; +} + +// This is called by the QuicStreamSequencer if it encounters an unrecoverable +// error that will prevent it from reassembling the crypto stream data. +void TlsChloExtractor::OnUnrecoverableError(QuicErrorCode error, + const std::string& details) { + HandleUnrecoverableError(quiche::QuicheStrCat( + "Crypto stream error ", QuicErrorCodeToString(error), ": ", details)); +} + +// This is called by the framer if it sees a CRYPTO frame during parsing. +bool TlsChloExtractor::OnCryptoFrame(const QuicCryptoFrame& frame) { + if (frame.level != ENCRYPTION_INITIAL) { + // Since we drop non-INITIAL packets in OnUnauthenticatedPublicHeader, + // we should never receive any CRYPTO frames at other encryption levels. + QUIC_BUG << "Parsed bad-level CRYPTO frame " << frame; + return false; + } + // parsed_crypto_frame_in_this_packet_ is checked in IngestPacket to allow + // advancing our state to track the difference between single-packet CHLO + // and multi-packet CHLO. + parsed_crypto_frame_in_this_packet_ = true; + crypto_stream_sequencer_.OnCryptoFrame(frame); + return true; +} + +// Called by the QuicStreamSequencer when it receives a CRYPTO frame that +// advances the amount of contiguous data we now have starting from offset 0. +void TlsChloExtractor::OnDataAvailable() { + // Lazily set up BoringSSL handle. + SetupSslHandle(); + + // Get data from the stream sequencer and pass it to BoringSSL. + struct iovec iov; + while (crypto_stream_sequencer_.GetReadableRegion(&iov)) { + const int rv = SSL_provide_quic_data( + ssl_.get(), ssl_encryption_initial, + reinterpret_cast<const uint8_t*>(iov.iov_base), iov.iov_len); + if (rv != 1) { + HandleUnrecoverableError("SSL_provide_quic_data failed"); + return; + } + crypto_stream_sequencer_.MarkConsumed(iov.iov_len); + } + + // Instruct BoringSSL to attempt parsing a full CHLO from the provided data. + // We ignore the return value since we know the handshake is going to fail + // because we explicitly cancel processing once we've parsed the CHLO. + (void)SSL_do_handshake(ssl_.get()); +} + +// static +TlsChloExtractor* TlsChloExtractor::GetInstanceFromSSL(SSL* ssl) { + std::pair<SSL_CTX*, int> shared_handles = GetSharedSslHandles(); + int ex_data_index = shared_handles.second; + return reinterpret_cast<TlsChloExtractor*>( + SSL_get_ex_data(ssl, ex_data_index)); +} + +// static +int TlsChloExtractor::SetReadSecretCallback( + SSL* ssl, + enum ssl_encryption_level_t /*level*/, + const SSL_CIPHER* /*cipher*/, + const uint8_t* /*secret*/, + size_t /*secret_length*/) { + GetInstanceFromSSL(ssl)->HandleUnexpectedCallback("SetReadSecretCallback"); + return 0; +} + +// static +int TlsChloExtractor::SetWriteSecretCallback( + SSL* ssl, + enum ssl_encryption_level_t /*level*/, + const SSL_CIPHER* /*cipher*/, + const uint8_t* /*secret*/, + size_t /*secret_length*/) { + GetInstanceFromSSL(ssl)->HandleUnexpectedCallback("SetWriteSecretCallback"); + return 0; +} + +// static +int TlsChloExtractor::WriteMessageCallback( + SSL* ssl, + enum ssl_encryption_level_t /*level*/, + const uint8_t* /*data*/, + size_t /*len*/) { + GetInstanceFromSSL(ssl)->HandleUnexpectedCallback("WriteMessageCallback"); + return 0; +} + +// static +int TlsChloExtractor::FlushFlightCallback(SSL* ssl) { + GetInstanceFromSSL(ssl)->HandleUnexpectedCallback("FlushFlightCallback"); + return 0; +} + +void TlsChloExtractor::HandleUnexpectedCallback( + const std::string& callback_name) { + std::string error_details = + quiche::QuicheStrCat("Unexpected callback ", callback_name); + QUIC_BUG << error_details; + HandleUnrecoverableError(error_details); +} + +// static +int TlsChloExtractor::SendAlertCallback(SSL* ssl, + enum ssl_encryption_level_t /*level*/, + uint8_t desc) { + GetInstanceFromSSL(ssl)->SendAlert(desc); + return 0; +} + +void TlsChloExtractor::SendAlert(uint8_t tls_alert_value) { + if (tls_alert_value == SSL3_AD_HANDSHAKE_FAILURE && HasParsedFullChlo()) { + // This is the most common scenario. Since we return an error from + // SelectCertCallback in order to cancel further processing, BoringSSL will + // try to send this alert to tell the client that the handshake failed. + return; + } + HandleUnrecoverableError(quiche::QuicheStrCat( + "BoringSSL attempted to send alert ", static_cast<int>(tls_alert_value), + " ", SSL_alert_desc_string_long(tls_alert_value))); +} + +// static +enum ssl_select_cert_result_t TlsChloExtractor::SelectCertCallback( + const SSL_CLIENT_HELLO* client_hello) { + GetInstanceFromSSL(client_hello->ssl)->HandleParsedChlo(client_hello); + // Always return an error to cancel any further processing in BoringSSL. + return ssl_select_cert_error; +} + +// Extracts the server name and ALPN from the parsed ClientHello. +void TlsChloExtractor::HandleParsedChlo(const SSL_CLIENT_HELLO* client_hello) { + const char* server_name = + SSL_get_servername(client_hello->ssl, TLSEXT_NAMETYPE_host_name); + if (server_name) { + server_name_ = std::string(server_name); + } + const uint8_t* alpn_data; + size_t alpn_len; + int rv = SSL_early_callback_ctx_extension_get( + client_hello, TLSEXT_TYPE_application_layer_protocol_negotiation, + &alpn_data, &alpn_len); + if (rv == 1) { + QuicDataReader alpns_reader(reinterpret_cast<const char*>(alpn_data), + alpn_len); + quiche::QuicheStringPiece alpns_payload; + if (!alpns_reader.ReadStringPiece16(&alpns_payload)) { + HandleUnrecoverableError("Failed to read alpns_payload"); + return; + } + QuicDataReader alpns_payload_reader(alpns_payload); + while (!alpns_payload_reader.IsDoneReading()) { + quiche::QuicheStringPiece alpn_payload; + if (!alpns_payload_reader.ReadStringPiece8(&alpn_payload)) { + HandleUnrecoverableError("Failed to read alpn_payload"); + return; + } + alpns_.emplace_back(std::string(alpn_payload)); + } + } + + // Update our state now that we've parsed a full CHLO. + if (state_ == State::kInitial) { + state_ = State::kParsedFullSinglePacketChlo; + } else if (state_ == State::kParsedPartialChloFragment) { + state_ = State::kParsedFullMultiPacketChlo; + } else { + QUIC_BUG << "Unexpected state on successful parse " + << StateToString(state_); + } +} + +// static +std::pair<SSL_CTX*, int> TlsChloExtractor::GetSharedSslHandles() { + // Use a lambda to benefit from C++11 guarantee that static variables are + // initialized lazily in a thread-safe manner. |shared_handles| is therefore + // guaranteed to be initialized exactly once and never destructed. + static std::pair<SSL_CTX*, int>* shared_handles = []() { + CRYPTO_library_init(); + SSL_CTX* ssl_ctx = SSL_CTX_new(TLS_with_buffers_method()); + SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_3_VERSION); + static const SSL_QUIC_METHOD kQuicCallbacks{ + TlsChloExtractor::SetReadSecretCallback, + TlsChloExtractor::SetWriteSecretCallback, + TlsChloExtractor::WriteMessageCallback, + TlsChloExtractor::FlushFlightCallback, + TlsChloExtractor::SendAlertCallback}; + SSL_CTX_set_quic_method(ssl_ctx, &kQuicCallbacks); + SSL_CTX_set_select_certificate_cb(ssl_ctx, + TlsChloExtractor::SelectCertCallback); + int ex_data_index = + SSL_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr); + return new std::pair<SSL_CTX*, int>(ssl_ctx, ex_data_index); + }(); + return *shared_handles; +} + +// Sets up the per-instance SSL handle needed by BoringSSL. +void TlsChloExtractor::SetupSslHandle() { + if (ssl_) { + // Handles have already been set up. + return; + } + + std::pair<SSL_CTX*, int> shared_handles = GetSharedSslHandles(); + SSL_CTX* ssl_ctx = shared_handles.first; + int ex_data_index = shared_handles.second; + + ssl_ = bssl::UniquePtr<SSL>(SSL_new(ssl_ctx)); + const int rv = SSL_set_ex_data(ssl_.get(), ex_data_index, this); + CHECK_EQ(rv, 1) << "Internal allocation failure in SSL_set_ex_data"; + SSL_set_accept_state(ssl_.get()); +} + +// Called by other methods to record any unrecoverable failures they experience. +void TlsChloExtractor::HandleUnrecoverableError( + const std::string& error_details) { + if (HasParsedFullChlo()) { + // Ignore errors if we've parsed everything successfully. + QUIC_DLOG(ERROR) << "Ignoring error: " << error_details; + return; + } + QUIC_DLOG(ERROR) << "Handling error: " << error_details; + + state_ = State::kUnrecoverableFailure; + + if (error_details_.empty()) { + error_details_ = error_details; + } else { + error_details_ = quiche::QuicheStrCat(error_details_, "; ", error_details); + } +} + +// static +std::string TlsChloExtractor::StateToString(State state) { + switch (state) { + case State::kInitial: + return "Initial"; + case State::kParsedFullSinglePacketChlo: + return "ParsedFullSinglePacketChlo"; + case State::kParsedFullMultiPacketChlo: + return "ParsedFullMultiPacketChlo"; + case State::kParsedPartialChloFragment: + return "ParsedPartialChloFragment"; + case State::kUnrecoverableFailure: + return "UnrecoverableFailure"; + } + return quiche::QuicheStrCat("Unknown(", static_cast<int>(state), ")"); +} + +std::ostream& operator<<(std::ostream& os, + const TlsChloExtractor::State& state) { + os << TlsChloExtractor::StateToString(state); + return os; +} + +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.h b/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.h new file mode 100644 index 00000000000..1762566d70a --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.h @@ -0,0 +1,238 @@ +// Copyright (c) 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_TLS_CHLO_EXTRACTOR_H_ +#define QUICHE_QUIC_CORE_TLS_CHLO_EXTRACTOR_H_ + +#include <memory> +#include <string> +#include <vector> +#include "third_party/boringssl/src/include/openssl/ssl.h" +#include "net/third_party/quiche/src/quic/core/quic_framer.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/core/quic_stream_sequencer.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +// Utility class that allows extracting information from a QUIC-TLS Client +// Hello. This class creates a QuicFramer to parse the packet, and implements +// QuicFramerVisitorInterface to access the frames parsed by the QuicFramer. It +// then uses a QuicStreamSequencer to reassemble the contents of the crypto +// stream, and implements QuicStreamSequencer::StreamInterface to access the +// reassembled data. +class QUIC_NO_EXPORT TlsChloExtractor + : public QuicFramerVisitorInterface, + public QuicStreamSequencer::StreamInterface { + public: + TlsChloExtractor(); + TlsChloExtractor(const TlsChloExtractor&) = delete; + TlsChloExtractor(TlsChloExtractor&&); + TlsChloExtractor& operator=(const TlsChloExtractor&) = delete; + TlsChloExtractor& operator=(TlsChloExtractor&&); + + enum class State : uint8_t { + kInitial = 0, + kParsedFullSinglePacketChlo = 1, + kParsedFullMultiPacketChlo = 2, + kParsedPartialChloFragment = 3, + kUnrecoverableFailure = 4, + }; + + State state() const { return state_; } + std::vector<std::string> alpns() const { return alpns_; } + std::string server_name() const { return server_name_; } + + // Converts |state| to a human-readable string suitable for logging. + static std::string StateToString(State state); + + // Ingests |packet| and attempts to parse out the CHLO. + void IngestPacket(const ParsedQuicVersion& version, + const QuicReceivedPacket& packet); + + // Returns whether the ingested packets have allowed parsing a complete CHLO. + bool HasParsedFullChlo() const { + return state_ == State::kParsedFullSinglePacketChlo || + state_ == State::kParsedFullMultiPacketChlo; + } + + // Methods from QuicFramerVisitorInterface. + void OnError(QuicFramer* /*framer*/) override {} + bool OnProtocolVersionMismatch(ParsedQuicVersion version) override; + void OnPacket() override {} + void OnPublicResetPacket(const QuicPublicResetPacket& /*packet*/) override {} + void OnVersionNegotiationPacket( + const QuicVersionNegotiationPacket& /*packet*/) override {} + void OnRetryPacket(QuicConnectionId /*original_connection_id*/, + QuicConnectionId /*new_connection_id*/, + quiche::QuicheStringPiece /*retry_token*/, + quiche::QuicheStringPiece /*retry_integrity_tag*/, + quiche::QuicheStringPiece /*retry_without_tag*/) override { + } + bool OnUnauthenticatedPublicHeader(const QuicPacketHeader& header) override; + bool OnUnauthenticatedHeader(const QuicPacketHeader& /*header*/) override { + return true; + } + void OnDecryptedPacket(EncryptionLevel /*level*/) override {} + bool OnPacketHeader(const QuicPacketHeader& /*header*/) override { + return true; + } + void OnCoalescedPacket(const QuicEncryptedPacket& /*packet*/) override {} + void OnUndecryptablePacket(const QuicEncryptedPacket& /*packet*/, + EncryptionLevel /*decryption_level*/, + bool /*has_decryption_key*/) override {} + bool OnStreamFrame(const QuicStreamFrame& /*frame*/) override { return true; } + bool OnCryptoFrame(const QuicCryptoFrame& frame) override; + bool OnAckFrameStart(QuicPacketNumber /*largest_acked*/, + QuicTime::Delta /*ack_delay_time*/) override { + return true; + } + bool OnAckRange(QuicPacketNumber /*start*/, + QuicPacketNumber /*end*/) override { + return true; + } + bool OnAckTimestamp(QuicPacketNumber /*packet_number*/, + QuicTime /*timestamp*/) override { + return true; + } + bool OnAckFrameEnd(QuicPacketNumber /*start*/) override { return true; } + bool OnStopWaitingFrame(const QuicStopWaitingFrame& /*frame*/) override { + return true; + } + bool OnPingFrame(const QuicPingFrame& /*frame*/) override { return true; } + bool OnRstStreamFrame(const QuicRstStreamFrame& /*frame*/) override { + return true; + } + bool OnConnectionCloseFrame( + const QuicConnectionCloseFrame& /*frame*/) override { + return true; + } + bool OnNewConnectionIdFrame( + const QuicNewConnectionIdFrame& /*frame*/) override { + return true; + } + bool OnRetireConnectionIdFrame( + const QuicRetireConnectionIdFrame& /*frame*/) override { + return true; + } + bool OnNewTokenFrame(const QuicNewTokenFrame& /*frame*/) override { + return true; + } + bool OnStopSendingFrame(const QuicStopSendingFrame& /*frame*/) override { + return true; + } + bool OnPathChallengeFrame(const QuicPathChallengeFrame& /*frame*/) override { + return true; + } + bool OnPathResponseFrame(const QuicPathResponseFrame& /*frame*/) override { + return true; + } + bool OnGoAwayFrame(const QuicGoAwayFrame& /*frame*/) override { return true; } + bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& /*frame*/) override { + return true; + } + bool OnStreamsBlockedFrame( + const QuicStreamsBlockedFrame& /*frame*/) override { + return true; + } + bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& /*frame*/) override { + return true; + } + bool OnBlockedFrame(const QuicBlockedFrame& /*frame*/) override { + return true; + } + bool OnPaddingFrame(const QuicPaddingFrame& /*frame*/) override { + return true; + } + bool OnMessageFrame(const QuicMessageFrame& /*frame*/) override { + return true; + } + bool OnHandshakeDoneFrame(const QuicHandshakeDoneFrame& /*frame*/) override { + return true; + } + void OnPacketComplete() override {} + bool IsValidStatelessResetToken(QuicUint128 /*token*/) const override { + return true; + } + void OnAuthenticatedIetfStatelessResetPacket( + const QuicIetfStatelessResetPacket& /*packet*/) override {} + + // Methods from QuicStreamSequencer::StreamInterface. + void OnDataAvailable() override; + void OnFinRead() override {} + void AddBytesConsumed(QuicByteCount /*bytes*/) override {} + void Reset(QuicRstStreamErrorCode /*error*/) override {} + void OnUnrecoverableError(QuicErrorCode error, + const std::string& details) override; + QuicStreamId id() const override { return 0; } + + private: + // Parses the length of the CHLO message by looking at the first four bytes. + // Returns whether we have received enough data to parse the full CHLO now. + bool MaybeAttemptToParseChloLength(); + // Parses the full CHLO message if enough data has been received. + void AttemptToParseFullChlo(); + // Moves to the failed state and records the error details. + void HandleUnrecoverableError(const std::string& error_details); + // Lazily sets up shared SSL handles if needed. + static std::pair<SSL_CTX*, int> GetSharedSslHandles(); + // Lazily sets up the per-instance SSL handle if needed. + void SetupSslHandle(); + // Extract the TlsChloExtractor instance from |ssl|. + static TlsChloExtractor* GetInstanceFromSSL(SSL* ssl); + + // BoringSSL static TLS callbacks. + static enum ssl_select_cert_result_t SelectCertCallback( + const SSL_CLIENT_HELLO* client_hello); + static int SetReadSecretCallback(SSL* ssl, + enum ssl_encryption_level_t level, + const SSL_CIPHER* cipher, + const uint8_t* secret, + size_t secret_length); + static int SetWriteSecretCallback(SSL* ssl, + enum ssl_encryption_level_t level, + const SSL_CIPHER* cipher, + const uint8_t* secret, + size_t secret_length); + static int WriteMessageCallback(SSL* ssl, + enum ssl_encryption_level_t level, + const uint8_t* data, + size_t len); + static int FlushFlightCallback(SSL* ssl); + static int SendAlertCallback(SSL* ssl, + enum ssl_encryption_level_t level, + uint8_t desc); + + // Called by SelectCertCallback. + void HandleParsedChlo(const SSL_CLIENT_HELLO* client_hello); + // Called by callbacks that should never be called. + void HandleUnexpectedCallback(const std::string& callback_name); + // Called by SendAlertCallback. + void SendAlert(uint8_t tls_alert_value); + + // Used to parse received packets to extract single frames. + std::unique_ptr<QuicFramer> framer_; + // Used to reassemble the crypto stream from received CRYPTO frames. + QuicStreamSequencer crypto_stream_sequencer_; + // BoringSSL handle required to parse the CHLO. + bssl::UniquePtr<SSL> ssl_; + // State of this TlsChloExtractor. + State state_; + // Detail string that can be logged in the presence of unrecoverable errors. + std::string error_details_; + // Whether a CRYPTO frame was parsed in this packet. + bool parsed_crypto_frame_in_this_packet_; + // Array of ALPNs parsed from the CHLO. + std::vector<std::string> alpns_; + // SNI parsed from the CHLO. + std::string server_name_; +}; + +// Convenience method to facilitate logging TlsChloExtractor::State. +QUIC_NO_EXPORT std::ostream& operator<<(std::ostream& os, + const TlsChloExtractor::State& state); + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_TLS_CHLO_EXTRACTOR_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor_test.cc b/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor_test.cc new file mode 100644 index 00000000000..ba57ad02bb9 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor_test.cc @@ -0,0 +1,157 @@ +// Copyright (c) 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/core/tls_chlo_extractor.h" +#include <memory> + +#include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.h" +#include "net/third_party/quiche/src/quic/core/quic_connection.h" +#include "net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.h" +#include "net/third_party/quiche/src/quic/core/quic_versions.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/first_flight.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" + +namespace quic { +namespace test { +namespace { + +class TlsChloExtractorTest : public QuicTestWithParam<ParsedQuicVersion> { + protected: + TlsChloExtractorTest() : version_(GetParam()) {} + + void Initialize() { packets_ = GetFirstFlightOfPackets(version_, config_); } + + void IngestPackets() { + for (const std::unique_ptr<QuicReceivedPacket>& packet : packets_) { + ReceivedPacketInfo packet_info( + QuicSocketAddress(TestPeerIPAddress(), kTestPort), + QuicSocketAddress(TestPeerIPAddress(), kTestPort), *packet); + std::string detailed_error; + bool retry_token_present; + quiche::QuicheStringPiece retry_token; + const QuicErrorCode error = QuicFramer::ParsePublicHeaderDispatcher( + *packet, /*expected_destination_connection_id_length=*/0, + &packet_info.form, &packet_info.long_packet_type, + &packet_info.version_flag, &packet_info.use_length_prefix, + &packet_info.version_label, &packet_info.version, + &packet_info.destination_connection_id, + &packet_info.source_connection_id, &retry_token_present, &retry_token, + &detailed_error); + ASSERT_THAT(error, IsQuicNoError()) << detailed_error; + tls_chlo_extractor_.IngestPacket(packet_info.version, packet_info.packet); + } + packets_.clear(); + } + + void ValidateChloDetails() { + EXPECT_TRUE(tls_chlo_extractor_.HasParsedFullChlo()); + ASSERT_EQ(tls_chlo_extractor_.alpns().size(), 1u); + EXPECT_EQ(tls_chlo_extractor_.alpns()[0], AlpnForVersion(version_)); + EXPECT_EQ(tls_chlo_extractor_.server_name(), TestHostname()); + } + + void IncreaseSizeOfChlo() { + // Add a 2000-byte custom parameter to increase the length of the CHLO. + constexpr auto kCustomParameterId = + static_cast<TransportParameters::TransportParameterId>(0xff33); + std::string kCustomParameterValue(2000, '-'); + config_.custom_transport_parameters_to_send()[kCustomParameterId] = + kCustomParameterValue; + } + + ParsedQuicVersion version_; + TlsChloExtractor tls_chlo_extractor_; + QuicConfig config_; + std::vector<std::unique_ptr<QuicReceivedPacket>> packets_; +}; + +INSTANTIATE_TEST_SUITE_P(TlsChloExtractorTests, + TlsChloExtractorTest, + ::testing::ValuesIn(AllSupportedVersionsWithTls()), + ::testing::PrintToStringParamName()); + +TEST_P(TlsChloExtractorTest, Simple) { + Initialize(); + EXPECT_EQ(packets_.size(), 1u); + IngestPackets(); + ValidateChloDetails(); + EXPECT_EQ(tls_chlo_extractor_.state(), + TlsChloExtractor::State::kParsedFullSinglePacketChlo); +} + +TEST_P(TlsChloExtractorTest, MultiPacket) { + IncreaseSizeOfChlo(); + Initialize(); + EXPECT_EQ(packets_.size(), 2u); + IngestPackets(); + ValidateChloDetails(); + EXPECT_EQ(tls_chlo_extractor_.state(), + TlsChloExtractor::State::kParsedFullMultiPacketChlo); +} + +TEST_P(TlsChloExtractorTest, MultiPacketReordered) { + IncreaseSizeOfChlo(); + Initialize(); + ASSERT_EQ(packets_.size(), 2u); + // Artifically reorder both packets. + std::swap(packets_[0], packets_[1]); + IngestPackets(); + ValidateChloDetails(); + EXPECT_EQ(tls_chlo_extractor_.state(), + TlsChloExtractor::State::kParsedFullMultiPacketChlo); +} + +TEST_P(TlsChloExtractorTest, MoveAssignment) { + Initialize(); + EXPECT_EQ(packets_.size(), 1u); + TlsChloExtractor other_extractor; + tls_chlo_extractor_ = std::move(other_extractor); + IngestPackets(); + ValidateChloDetails(); + EXPECT_EQ(tls_chlo_extractor_.state(), + TlsChloExtractor::State::kParsedFullSinglePacketChlo); +} + +TEST_P(TlsChloExtractorTest, MoveAssignmentBetweenPackets) { + IncreaseSizeOfChlo(); + Initialize(); + ASSERT_EQ(packets_.size(), 2u); + TlsChloExtractor other_extractor; + + // Have |other_extractor| parse the first packet. + ReceivedPacketInfo packet_info( + QuicSocketAddress(TestPeerIPAddress(), kTestPort), + QuicSocketAddress(TestPeerIPAddress(), kTestPort), *packets_[0]); + std::string detailed_error; + bool retry_token_present; + quiche::QuicheStringPiece retry_token; + const QuicErrorCode error = QuicFramer::ParsePublicHeaderDispatcher( + *packets_[0], /*expected_destination_connection_id_length=*/0, + &packet_info.form, &packet_info.long_packet_type, + &packet_info.version_flag, &packet_info.use_length_prefix, + &packet_info.version_label, &packet_info.version, + &packet_info.destination_connection_id, &packet_info.source_connection_id, + &retry_token_present, &retry_token, &detailed_error); + ASSERT_THAT(error, IsQuicNoError()) << detailed_error; + other_extractor.IngestPacket(packet_info.version, packet_info.packet); + // Remove the first packet from the list. + packets_.erase(packets_.begin()); + EXPECT_EQ(packets_.size(), 1u); + + // Move the extractor. + tls_chlo_extractor_ = std::move(other_extractor); + + // Have |tls_chlo_extractor_| parse the second packet. + IngestPackets(); + + ValidateChloDetails(); + EXPECT_EQ(tls_chlo_extractor_.state(), + TlsChloExtractor::State::kParsedFullMultiPacketChlo); +} + +} // namespace +} // namespace test +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc index 5148e71caf5..d4e8ed023b1 100644 --- a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc +++ b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc @@ -8,9 +8,12 @@ #include <string> #include "third_party/boringssl/src/include/openssl/ssl.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h" #include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h" #include "net/third_party/quiche/src/quic/core/quic_session.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_hostname_utils.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" #include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h" @@ -34,8 +37,10 @@ void TlsClientHandshaker::ProofVerifierCallbackImpl::Run( parent_->verify_result_ = ok ? ssl_verify_ok : ssl_verify_invalid; parent_->state_ = STATE_HANDSHAKE_RUNNING; parent_->proof_verify_callback_ = nullptr; - parent_->proof_handler_->OnProofVerifyDetailsAvailable( - *parent_->verify_details_); + if (parent_->verify_details_) { + parent_->proof_handler_->OnProofVerifyDetailsAvailable( + *parent_->verify_details_); + } parent_->AdvanceHandshake(); } @@ -49,7 +54,8 @@ TlsClientHandshaker::TlsClientHandshaker( QuicSession* session, std::unique_ptr<ProofVerifyContext> verify_context, QuicCryptoClientConfig* crypto_config, - QuicCryptoClientStream::ProofHandler* proof_handler) + QuicCryptoClientStream::ProofHandler* proof_handler, + bool has_application_state) : TlsHandshaker(stream, session), session_(session), server_id_(server_id), @@ -58,7 +64,9 @@ TlsClientHandshaker::TlsClientHandshaker( proof_handler_(proof_handler), session_cache_(crypto_config->session_cache()), user_agent_id_(crypto_config->user_agent_id()), + pre_shared_key_(crypto_config->pre_shared_key()), crypto_negotiated_params_(new QuicCryptoNegotiatedParameters), + has_application_state_(has_application_state), tls_connection_(crypto_config->ssl_ctx(), this) {} TlsClientHandshaker::~TlsClientHandshaker() { @@ -70,9 +78,25 @@ TlsClientHandshaker::~TlsClientHandshaker() { bool TlsClientHandshaker::CryptoConnect() { state_ = STATE_HANDSHAKE_RUNNING; + if (!pre_shared_key_.empty()) { + // TODO(b/154162689) add PSK support to QUIC+TLS. + std::string error_details = + "QUIC client pre-shared keys not yet supported with TLS"; + QUIC_BUG << error_details; + CloseConnection(QUIC_HANDSHAKE_FAILED, error_details); + return false; + } + // Set the SNI to send, if any. SSL_set_connect_state(ssl()); + if (QUIC_DLOG_INFO_IS_ON() && + !QuicHostnameUtils::IsValidSNI(server_id_.host())) { + QUIC_DLOG(INFO) << "Client configured with invalid hostname \"" + << server_id_.host() << "\", not sending as SNI"; + } if (!server_id_.host().empty() && + (QuicHostnameUtils::IsValidSNI(server_id_.host()) || + allow_invalid_sni_for_tests_) && SSL_set_tlsext_host_name(ssl(), server_id_.host().c_str()) != 1) { return false; } @@ -95,6 +119,13 @@ bool TlsClientHandshaker::CryptoConnect() { session_cache_->Lookup(server_id_, SSL_get_SSL_CTX(ssl())); if (cached_state) { SSL_set_session(ssl(), cached_state->tls_session.get()); + if (GetQuicReloadableFlag(quic_enable_zero_rtt_for_tls) && + VersionHasIetfQuicFrames(session()->transport_version()) && + SSL_SESSION_early_data_capable(cached_state->tls_session.get())) { + if (!PrepareZeroRttConfig(cached_state.get())) { + return false; + } + } } } @@ -103,6 +134,30 @@ bool TlsClientHandshaker::CryptoConnect() { return session()->connection()->connected(); } +bool TlsClientHandshaker::PrepareZeroRttConfig( + QuicResumptionState* cached_state) { + std::string error_details; + if (session()->config()->ProcessTransportParameters( + *(cached_state->transport_params), SERVER, + /*is_resumption = */ true, &error_details) != QUIC_NO_ERROR) { + QUIC_BUG << "Unable to parse cached transport parameters."; + CloseConnection(QUIC_HANDSHAKE_FAILED, + "Client failed to parse cached Transport Parameters."); + return false; + } + session()->OnConfigNegotiated(); + + if (has_application_state_) { + if (!session()->SetApplicationState(cached_state->application_state)) { + QUIC_BUG << "Unable to parse cached application state."; + CloseConnection(QUIC_HANDSHAKE_FAILED, + "Client failed to parse cached application state."); + return false; + } + } + return true; +} + static bool IsValidAlpn(const std::string& alpn_string) { return alpn_string.length() <= std::numeric_limits<uint8_t>::max(); } @@ -152,7 +207,14 @@ bool TlsClientHandshaker::SetTransportParameters() { if (!session()->config()->FillTransportParameters(¶ms)) { return false; } - params.google_quic_params->SetStringPiece(kUAID, user_agent_id_); + if (GetQuicRestartFlag(quic_google_transport_param_send_new)) { + if (!user_agent_id_.empty()) { + params.user_agent_id = user_agent_id_; + } + } + if (!GetQuicRestartFlag(quic_google_transport_param_omit_old)) { + params.google_quic_params->SetStringPiece(kUAID, user_agent_id_); + } std::vector<uint8_t> param_bytes; return SerializeTransportParameters(session()->connection()->version(), @@ -163,7 +225,7 @@ bool TlsClientHandshaker::SetTransportParameters() { bool TlsClientHandshaker::ProcessTransportParameters( std::string* error_details) { - TransportParameters params; + received_transport_params_ = std::make_unique<TransportParameters>(); const uint8_t* param_bytes; size_t param_bytes_len; SSL_get_peer_quic_transport_params(ssl(), ¶m_bytes, ¶m_bytes_len); @@ -174,7 +236,8 @@ bool TlsClientHandshaker::ProcessTransportParameters( std::string parse_error_details; if (!ParseTransportParameters( session()->connection()->version(), Perspective::IS_SERVER, - param_bytes, param_bytes_len, ¶ms, &parse_error_details)) { + param_bytes, param_bytes_len, received_transport_params_.get(), + &parse_error_details)) { DCHECK(!parse_error_details.empty()); *error_details = "Unable to parse server's transport parameters: " + parse_error_details; @@ -183,29 +246,37 @@ bool TlsClientHandshaker::ProcessTransportParameters( // When interoperating with non-Google implementations that do not send // the version extension, set it to what we expect. - if (params.version == 0) { - params.version = CreateQuicVersionLabel(session()->connection()->version()); + if (received_transport_params_->version == 0) { + received_transport_params_->version = + CreateQuicVersionLabel(session()->connection()->version()); } - if (params.supported_versions.empty()) { - params.supported_versions.push_back(params.version); + if (received_transport_params_->supported_versions.empty()) { + received_transport_params_->supported_versions.push_back( + received_transport_params_->version); } - if (params.version != + if (received_transport_params_->version != CreateQuicVersionLabel(session()->connection()->version())) { *error_details = "Version mismatch detected"; return false; } if (CryptoUtils::ValidateServerHelloVersions( - params.supported_versions, + received_transport_params_->supported_versions, session()->connection()->server_supported_versions(), error_details) != QUIC_NO_ERROR || session()->config()->ProcessTransportParameters( - params, SERVER, error_details) != QUIC_NO_ERROR) { + *received_transport_params_, SERVER, /* is_resumption = */ false, + error_details) != QUIC_NO_ERROR) { DCHECK(!error_details->empty()); return false; } session()->OnConfigNegotiated(); + if (state_ == STATE_CONNECTION_CLOSED) { + *error_details = + "Session closed the connection when parsing negotiated config."; + return false; + } return true; } @@ -277,6 +348,20 @@ void TlsClientHandshaker::OnOneRttPacketAcknowledged() { OnHandshakeConfirmed(); } +void TlsClientHandshaker::OnHandshakePacketSent() { + if (initial_keys_dropped_) { + return; + } + initial_keys_dropped_ = true; + handshaker_delegate()->DiscardOldEncryptionKey(ENCRYPTION_INITIAL); + handshaker_delegate()->DiscardOldDecryptionKey(ENCRYPTION_INITIAL); +} + +void TlsClientHandshaker::OnConnectionClosed(QuicErrorCode /*error*/, + ConnectionCloseSource /*source*/) { + state_ = STATE_CONNECTION_CLOSED; +} + void TlsClientHandshaker::OnHandshakeDoneReceived() { if (!one_rtt_keys_available_) { CloseConnection(QUIC_HANDSHAKE_FAILED, @@ -290,8 +375,10 @@ void TlsClientHandshaker::SetWriteSecret( EncryptionLevel level, const SSL_CIPHER* cipher, const std::vector<uint8_t>& write_secret) { - if (GetQuicRestartFlag(quic_send_settings_on_write_key_available) && - level == ENCRYPTION_FORWARD_SECURE) { + if (state_ == STATE_CONNECTION_CLOSED) { + return; + } + if (level == ENCRYPTION_FORWARD_SECURE) { encryption_established_ = true; } TlsHandshaker::SetWriteSecret(level, cipher, write_secret); @@ -335,6 +422,7 @@ void TlsClientHandshaker::AdvanceHandshake() { int ssl_error = SSL_get_error(ssl(), rv); bool should_close = true; switch (state_) { + // TODO(b/153726130): handle the case where the server rejects early data. case STATE_HANDSHAKE_RUNNING: should_close = ssl_error != SSL_ERROR_WANT_READ; break; @@ -363,16 +451,14 @@ void TlsClientHandshaker::CloseConnection(QuicErrorCode error, void TlsClientHandshaker::FinishHandshake() { QUIC_LOG(INFO) << "Client: handshake finished"; state_ = STATE_HANDSHAKE_COMPLETE; - if (GetQuicRestartFlag(quic_send_settings_on_write_key_available)) { - // Fill crypto_negotiated_params_: - const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl()); - if (cipher) { - crypto_negotiated_params_->cipher_suite = SSL_CIPHER_get_value(cipher); - } - crypto_negotiated_params_->key_exchange_group = SSL_get_curve_id(ssl()); - crypto_negotiated_params_->peer_signature_algorithm = - SSL_get_peer_signature_algorithm(ssl()); + // Fill crypto_negotiated_params_: + const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl()); + if (cipher) { + crypto_negotiated_params_->cipher_suite = SSL_CIPHER_get_value(cipher); } + crypto_negotiated_params_->key_exchange_group = SSL_get_curve_id(ssl()); + crypto_negotiated_params_->peer_signature_algorithm = + SSL_get_peer_signature_algorithm(ssl()); std::string error_details; if (!ProcessTransportParameters(&error_details)) { @@ -408,23 +494,7 @@ void TlsClientHandshaker::FinishHandshake() { session()->OnAlpnSelected(received_alpn_string); QUIC_DLOG(INFO) << "Client: server selected ALPN: '" << received_alpn_string << "'"; - - if (!GetQuicRestartFlag(quic_send_settings_on_write_key_available)) { - encryption_established_ = true; - } one_rtt_keys_available_ = true; - - if (!GetQuicRestartFlag(quic_send_settings_on_write_key_available)) { - // Fill crypto_negotiated_params_: - const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl()); - if (cipher) { - crypto_negotiated_params_->cipher_suite = SSL_CIPHER_get_value(cipher); - } - crypto_negotiated_params_->key_exchange_group = SSL_get_curve_id(ssl()); - crypto_negotiated_params_->peer_signature_algorithm = - SSL_get_peer_signature_algorithm(ssl()); - } - handshaker_delegate()->OnOneRttKeysAvailable(); } @@ -462,12 +532,14 @@ enum ssl_verify_result_t TlsClientHandshaker::VerifyCert(uint8_t* out_alert) { new ProofVerifierCallbackImpl(this); QuicAsyncStatus verify_result = proof_verifier_->VerifyCertChain( - server_id_.host(), certs, ocsp_response, sct_list, verify_context_.get(), - &cert_verify_error_details_, &verify_details_, + server_id_.host(), server_id_.port(), certs, ocsp_response, sct_list, + verify_context_.get(), &cert_verify_error_details_, &verify_details_, std::unique_ptr<ProofVerifierCallback>(proof_verify_callback)); switch (verify_result) { case QUIC_SUCCESS: - proof_handler_->OnProofVerifyDetailsAvailable(*verify_details_); + if (verify_details_) { + proof_handler_->OnProofVerifyDetailsAvailable(*verify_details_); + } return ssl_verify_ok; case QUIC_PENDING: proof_verify_callback_ = proof_verify_callback; @@ -482,13 +554,25 @@ enum ssl_verify_result_t TlsClientHandshaker::VerifyCert(uint8_t* out_alert) { } void TlsClientHandshaker::InsertSession(bssl::UniquePtr<SSL_SESSION> session) { + if (!received_transport_params_) { + QUIC_BUG << "Transport parameters isn't received"; + return; + } if (session_cache_ == nullptr) { QUIC_DVLOG(1) << "No session cache, not inserting a session"; return; } - auto cache_state = std::make_unique<QuicResumptionState>(); - cache_state->tls_session = std::move(session); - session_cache_->Insert(server_id_, std::move(cache_state)); + if (has_application_state_ && !received_application_state_) { + // Application state is not received yet. cache the sessions. + if (cached_tls_sessions_[0] != nullptr) { + cached_tls_sessions_[1] = std::move(cached_tls_sessions_[0]); + } + cached_tls_sessions_[0] = std::move(session); + return; + } + session_cache_->Insert(server_id_, std::move(session), + *received_transport_params_, + received_application_state_.get()); } void TlsClientHandshaker::WriteMessage(EncryptionLevel level, @@ -496,10 +580,27 @@ void TlsClientHandshaker::WriteMessage(EncryptionLevel level, if (level == ENCRYPTION_HANDSHAKE && state_ < STATE_ENCRYPTION_HANDSHAKE_DATA_SENT) { state_ = STATE_ENCRYPTION_HANDSHAKE_DATA_SENT; - handshaker_delegate()->DiscardOldEncryptionKey(ENCRYPTION_INITIAL); - handshaker_delegate()->DiscardOldDecryptionKey(ENCRYPTION_INITIAL); } TlsHandshaker::WriteMessage(level, data); } +void TlsClientHandshaker::OnApplicationState( + std::unique_ptr<ApplicationState> application_state) { + DCHECK_EQ(STATE_HANDSHAKE_COMPLETE, state_); + received_application_state_ = std::move(application_state); + // At least one tls session is cached before application state is received. So + // insert now. + if (session_cache_ != nullptr && cached_tls_sessions_[0] != nullptr) { + if (cached_tls_sessions_[1] != nullptr) { + // Insert the older session first. + session_cache_->Insert(server_id_, std::move(cached_tls_sessions_[1]), + *received_transport_params_, + received_application_state_.get()); + } + session_cache_->Insert(server_id_, std::move(cached_tls_sessions_[0]), + *received_transport_params_, + received_application_state_.get()); + } +} + } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.h b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.h index d9ee7608f6f..cc601219dfa 100644 --- a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.h +++ b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.h @@ -5,11 +5,15 @@ #ifndef QUICHE_QUIC_CORE_TLS_CLIENT_HANDSHAKER_H_ #define QUICHE_QUIC_CORE_TLS_CLIENT_HANDSHAKER_H_ +#include <cstdint> +#include <memory> #include <string> #include "third_party/boringssl/src/include/openssl/ssl.h" #include "net/third_party/quiche/src/quic/core/crypto/proof_verifier.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h" #include "net/third_party/quiche/src/quic/core/crypto/tls_client_connection.h" +#include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h" #include "net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h" #include "net/third_party/quiche/src/quic/core/quic_crypto_stream.h" #include "net/third_party/quiche/src/quic/core/tls_handshaker.h" @@ -30,7 +34,8 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker QuicSession* session, std::unique_ptr<ProofVerifyContext> verify_context, QuicCryptoClientConfig* crypto_config, - QuicCryptoClientStream::ProofHandler* proof_handler); + QuicCryptoClientStream::ProofHandler* proof_handler, + bool has_application_state); TlsClientHandshaker(const TlsClientHandshaker&) = delete; TlsClientHandshaker& operator=(const TlsClientHandshaker&) = delete; @@ -54,6 +59,9 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker HandshakeState GetHandshakeState() const override; size_t BufferSizeLimitForLevel(EncryptionLevel level) const override; void OnOneRttPacketAcknowledged() override; + void OnHandshakePacketSent() override; + void OnConnectionClosed(QuicErrorCode error, + ConnectionCloseSource source) override; void OnHandshakeDoneReceived() override; void SetWriteSecret(EncryptionLevel level, const SSL_CIPHER* cipher, @@ -63,7 +71,11 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker void WriteMessage(EncryptionLevel level, quiche::QuicheStringPiece data) override; + void OnApplicationState( + std::unique_ptr<ApplicationState> application_state) override; + void AllowEmptyAlpnForTests() { allow_empty_alpn_for_tests_ = true; } + void AllowInvalidSNIForTests() { allow_invalid_sni_for_tests_ = true; } protected: const TlsConnection* tls_connection() const override { @@ -119,6 +131,8 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker void InsertSession(bssl::UniquePtr<SSL_SESSION> session) override; + bool PrepareZeroRttConfig(QuicResumptionState* cached_state); + QuicSession* session() { return session_; } QuicSession* session_; @@ -140,6 +154,9 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker std::string user_agent_id_; + // Pre-shared key used during the handshake. + std::string pre_shared_key_; + // ProofVerifierCallback used for async certificate verification. This object // is owned by |proof_verifier_|. ProofVerifierCallbackImpl* proof_verify_callback_ = nullptr; @@ -148,14 +165,25 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker std::string cert_verify_error_details_; bool encryption_established_ = false; + bool initial_keys_dropped_ = false; bool one_rtt_keys_available_ = false; bool handshake_confirmed_ = false; QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> crypto_negotiated_params_; bool allow_empty_alpn_for_tests_ = false; + bool allow_invalid_sni_for_tests_ = false; + + const bool has_application_state_; TlsClientConnection tls_connection_; + + // If |has_application_state_|, stores the tls session tickets before + // application state is received. The latest one is put in the front. + bssl::UniquePtr<SSL_SESSION> cached_tls_sessions_[2] = {}; + + std::unique_ptr<TransportParameters> received_transport_params_ = nullptr; + std::unique_ptr<ApplicationState> received_application_state_ = nullptr; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker_test.cc b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker_test.cc new file mode 100644 index 00000000000..68c413fbb63 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker_test.cc @@ -0,0 +1,455 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <memory> +#include <string> +#include <utility> + +#include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/core/quic_server_id.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_session_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/simple_session_cache.h" +#include "net/third_party/quiche/src/quic/tools/fake_proof_verifier.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h" +#include "net/third_party/quiche/src/common/test_tools/quiche_test_utils.h" + +using testing::_; + +namespace quic { +namespace test { +namespace { + +constexpr char kServerHostname[] = "test.example.com"; +constexpr uint16_t kServerPort = 443; + +// TestProofVerifier wraps ProofVerifierForTesting, except for VerifyCertChain +// which, if TestProofVerifier is active, always returns QUIC_PENDING. (If this +// test proof verifier is not active, it delegates VerifyCertChain to the +// ProofVerifierForTesting.) The pending VerifyCertChain operation can be +// completed by calling InvokePendingCallback. This allows for testing +// asynchronous VerifyCertChain operations. +class TestProofVerifier : public ProofVerifier { + public: + TestProofVerifier() + : verifier_(crypto_test_utils::ProofVerifierForTesting()) {} + + QuicAsyncStatus VerifyProof( + const std::string& hostname, + const uint16_t port, + const std::string& server_config, + QuicTransportVersion quic_version, + quiche::QuicheStringPiece chlo_hash, + const std::vector<std::string>& certs, + const std::string& cert_sct, + const std::string& signature, + const ProofVerifyContext* context, + std::string* error_details, + std::unique_ptr<ProofVerifyDetails>* details, + std::unique_ptr<ProofVerifierCallback> callback) override { + return verifier_->VerifyProof( + hostname, port, server_config, quic_version, chlo_hash, certs, cert_sct, + signature, context, error_details, details, std::move(callback)); + } + + QuicAsyncStatus VerifyCertChain( + const std::string& hostname, + const uint16_t port, + const std::vector<std::string>& certs, + const std::string& ocsp_response, + const std::string& cert_sct, + const ProofVerifyContext* context, + std::string* error_details, + std::unique_ptr<ProofVerifyDetails>* details, + std::unique_ptr<ProofVerifierCallback> callback) override { + if (!active_) { + return verifier_->VerifyCertChain(hostname, port, certs, ocsp_response, + cert_sct, context, error_details, + details, std::move(callback)); + } + pending_ops_.push_back(std::make_unique<VerifyChainPendingOp>( + hostname, port, certs, ocsp_response, cert_sct, context, error_details, + details, std::move(callback), verifier_.get())); + return QUIC_PENDING; + } + + std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override { + return nullptr; + } + + void Activate() { active_ = true; } + + size_t NumPendingCallbacks() const { return pending_ops_.size(); } + + void InvokePendingCallback(size_t n) { + ASSERT_GT(NumPendingCallbacks(), n); + pending_ops_[n]->Run(); + auto it = pending_ops_.begin() + n; + pending_ops_.erase(it); + } + + private: + // Implementation of ProofVerifierCallback that fails if the callback is ever + // run. + class FailingProofVerifierCallback : public ProofVerifierCallback { + public: + void Run(bool /*ok*/, + const std::string& /*error_details*/, + std::unique_ptr<ProofVerifyDetails>* /*details*/) override { + FAIL(); + } + }; + + class VerifyChainPendingOp { + public: + VerifyChainPendingOp(const std::string& hostname, + const uint16_t port, + const std::vector<std::string>& certs, + const std::string& ocsp_response, + const std::string& cert_sct, + const ProofVerifyContext* context, + std::string* error_details, + std::unique_ptr<ProofVerifyDetails>* details, + std::unique_ptr<ProofVerifierCallback> callback, + ProofVerifier* delegate) + : hostname_(hostname), + port_(port), + certs_(certs), + ocsp_response_(ocsp_response), + cert_sct_(cert_sct), + context_(context), + error_details_(error_details), + details_(details), + callback_(std::move(callback)), + delegate_(delegate) {} + + void Run() { + // TestProofVerifier depends on crypto_test_utils::ProofVerifierForTesting + // running synchronously. It passes a FailingProofVerifierCallback and + // runs the original callback after asserting that the verification ran + // synchronously. + QuicAsyncStatus status = delegate_->VerifyCertChain( + hostname_, port_, certs_, ocsp_response_, cert_sct_, context_, + error_details_, details_, + std::make_unique<FailingProofVerifierCallback>()); + ASSERT_NE(status, QUIC_PENDING); + callback_->Run(status == QUIC_SUCCESS, *error_details_, details_); + } + + private: + std::string hostname_; + const uint16_t port_; + std::vector<std::string> certs_; + std::string ocsp_response_; + std::string cert_sct_; + const ProofVerifyContext* context_; + std::string* error_details_; + std::unique_ptr<ProofVerifyDetails>* details_; + std::unique_ptr<ProofVerifierCallback> callback_; + ProofVerifier* delegate_; + }; + + std::unique_ptr<ProofVerifier> verifier_; + bool active_ = false; + std::vector<std::unique_ptr<VerifyChainPendingOp>> pending_ops_; +}; + +class TlsClientHandshakerTest : public QuicTestWithParam<ParsedQuicVersion> { + public: + TlsClientHandshakerTest() + : supported_versions_({GetParam()}), + server_id_(kServerHostname, kServerPort, false), + crypto_config_(std::make_unique<QuicCryptoClientConfig>( + std::make_unique<TestProofVerifier>(), + std::make_unique<test::SimpleSessionCache>())), + server_compressed_certs_cache_( + QuicCompressedCertsCache::kQuicCompressedCertsCacheSize) { + SetQuicReloadableFlag(quic_enable_tls_resumption, true); + SetQuicReloadableFlag(quic_enable_zero_rtt_for_tls, true); + server_crypto_config_ = crypto_test_utils::CryptoServerConfigForTesting(); + CreateConnection(); + } + + void CreateSession() { + session_ = std::make_unique<TestQuicSpdyClientSession>( + connection_, DefaultQuicConfig(), supported_versions_, server_id_, + crypto_config_.get()); + EXPECT_CALL(*session_, GetAlpnsToOffer()) + .WillRepeatedly(testing::Return(std::vector<std::string>( + {AlpnForVersion(connection_->version())}))); + } + + void CreateConnection() { + connection_ = + new PacketSavingConnection(&client_helper_, &alarm_factory_, + Perspective::IS_CLIENT, supported_versions_); + // Advance the time, because timers do not like uninitialized times. + connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1)); + CreateSession(); + } + + void CompleteCryptoHandshake() { + EXPECT_CALL(*connection_, SendCryptoData(_, _, _)) + .Times(testing::AnyNumber()); + stream()->CryptoConnect(); + QuicConfig config; + crypto_test_utils::HandshakeWithFakeServer( + &config, server_crypto_config_.get(), &server_helper_, &alarm_factory_, + connection_, stream(), AlpnForVersion(connection_->version())); + } + + QuicCryptoClientStream* stream() { + return session_->GetMutableCryptoStream(); + } + + QuicCryptoServerStreamBase* server_stream() { + return server_session_->GetMutableCryptoStream(); + } + + // Initializes a fake server, and all its associated state, for testing. + void InitializeFakeServer() { + TestQuicSpdyServerSession* server_session = nullptr; + CreateServerSessionForTest( + server_id_, QuicTime::Delta::FromSeconds(100000), supported_versions_, + &server_helper_, &alarm_factory_, server_crypto_config_.get(), + &server_compressed_certs_cache_, &server_connection_, &server_session); + server_session_.reset(server_session); + std::string alpn = AlpnForVersion(connection_->version()); + EXPECT_CALL(*server_session_, SelectAlpn(_)) + .WillRepeatedly( + [alpn](const std::vector<quiche::QuicheStringPiece>& alpns) { + return std::find(alpns.cbegin(), alpns.cend(), alpn); + }); + } + + MockQuicConnectionHelper server_helper_; + MockQuicConnectionHelper client_helper_; + MockAlarmFactory alarm_factory_; + PacketSavingConnection* connection_; + ParsedQuicVersionVector supported_versions_; + std::unique_ptr<TestQuicSpdyClientSession> session_; + QuicServerId server_id_; + CryptoHandshakeMessage message_; + std::unique_ptr<QuicCryptoClientConfig> crypto_config_; + + // Server state. + std::unique_ptr<QuicCryptoServerConfig> server_crypto_config_; + PacketSavingConnection* server_connection_; + std::unique_ptr<TestQuicSpdyServerSession> server_session_; + QuicCompressedCertsCache server_compressed_certs_cache_; +}; + +INSTANTIATE_TEST_SUITE_P(TlsHandshakerTests, + TlsClientHandshakerTest, + ::testing::ValuesIn(AllSupportedVersionsWithTls()), + ::testing::PrintToStringParamName()); + +TEST_P(TlsClientHandshakerTest, NotInitiallyConnected) { + EXPECT_FALSE(stream()->encryption_established()); + EXPECT_FALSE(stream()->one_rtt_keys_available()); +} + +TEST_P(TlsClientHandshakerTest, ConnectedAfterHandshake) { + CompleteCryptoHandshake(); + EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol()); + EXPECT_TRUE(stream()->encryption_established()); + EXPECT_TRUE(stream()->one_rtt_keys_available()); + EXPECT_FALSE(stream()->IsResumption()); +} + +TEST_P(TlsClientHandshakerTest, ConnectionClosedOnTlsError) { + // Have client send ClientHello. + stream()->CryptoConnect(); + EXPECT_CALL(*connection_, CloseConnection(QUIC_HANDSHAKE_FAILED, _, _)); + + // Send a zero-length ServerHello from server to client. + char bogus_handshake_message[] = { + // Handshake struct (RFC 8446 appendix B.3) + 2, // HandshakeType server_hello + 0, 0, 0, // uint24 length + }; + stream()->crypto_message_parser()->ProcessInput( + quiche::QuicheStringPiece(bogus_handshake_message, + QUICHE_ARRAYSIZE(bogus_handshake_message)), + ENCRYPTION_INITIAL); + + EXPECT_FALSE(stream()->one_rtt_keys_available()); +} + +TEST_P(TlsClientHandshakerTest, ProofVerifyDetailsAvailableAfterHandshake) { + EXPECT_CALL(*session_, OnProofVerifyDetailsAvailable(testing::_)); + stream()->CryptoConnect(); + QuicConfig config; + crypto_test_utils::HandshakeWithFakeServer( + &config, server_crypto_config_.get(), &server_helper_, &alarm_factory_, + connection_, stream(), AlpnForVersion(connection_->version())); + EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol()); + EXPECT_TRUE(stream()->encryption_established()); + EXPECT_TRUE(stream()->one_rtt_keys_available()); +} + +TEST_P(TlsClientHandshakerTest, HandshakeWithAsyncProofVerifier) { + InitializeFakeServer(); + + // Enable TestProofVerifier to capture call to VerifyCertChain and run it + // asynchronously. + TestProofVerifier* proof_verifier = + static_cast<TestProofVerifier*>(crypto_config_->proof_verifier()); + proof_verifier->Activate(); + + stream()->CryptoConnect(); + // Exchange handshake messages. + std::pair<size_t, size_t> moved_message_counts = + crypto_test_utils::AdvanceHandshake( + connection_, stream(), 0, server_connection_, server_stream(), 0); + + ASSERT_EQ(proof_verifier->NumPendingCallbacks(), 1u); + proof_verifier->InvokePendingCallback(0); + + // Exchange more handshake messages. + crypto_test_utils::AdvanceHandshake( + connection_, stream(), moved_message_counts.first, server_connection_, + server_stream(), moved_message_counts.second); + + EXPECT_TRUE(stream()->encryption_established()); + EXPECT_TRUE(stream()->one_rtt_keys_available()); +} + +TEST_P(TlsClientHandshakerTest, Resumption) { + // Finish establishing the first connection: + CompleteCryptoHandshake(); + + EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol()); + EXPECT_TRUE(stream()->encryption_established()); + EXPECT_TRUE(stream()->one_rtt_keys_available()); + EXPECT_FALSE(stream()->IsResumption()); + + // Create a second connection + CreateConnection(); + CompleteCryptoHandshake(); + + EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol()); + EXPECT_TRUE(stream()->encryption_established()); + EXPECT_TRUE(stream()->one_rtt_keys_available()); + EXPECT_TRUE(stream()->IsResumption()); +} + +TEST_P(TlsClientHandshakerTest, ClientSendsNoSNI) { + // Reconfigure client to sent an empty server hostname. The crypto config also + // needs to be recreated to use a FakeProofVerifier since the server's cert + // won't match the empty hostname. + server_id_ = QuicServerId("", 443); + crypto_config_.reset(new QuicCryptoClientConfig( + std::make_unique<FakeProofVerifier>(), nullptr)); + CreateConnection(); + InitializeFakeServer(); + + stream()->CryptoConnect(); + crypto_test_utils::CommunicateHandshakeMessages( + connection_, stream(), server_connection_, server_stream()); + + EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol()); + EXPECT_TRUE(stream()->encryption_established()); + EXPECT_TRUE(stream()->one_rtt_keys_available()); + + EXPECT_EQ(server_stream()->crypto_negotiated_params().sni, ""); +} + +TEST_P(TlsClientHandshakerTest, ClientSendingTooManyALPNs) { + std::string long_alpn(250, 'A'); + EXPECT_CALL(*session_, GetAlpnsToOffer()) + .WillOnce(testing::Return(std::vector<std::string>({ + long_alpn + "1", + long_alpn + "2", + long_alpn + "3", + long_alpn + "4", + long_alpn + "5", + long_alpn + "6", + long_alpn + "7", + long_alpn + "8", + }))); + EXPECT_QUIC_BUG(stream()->CryptoConnect(), "Failed to set ALPN"); +} + +TEST_P(TlsClientHandshakerTest, ServerRequiresCustomALPN) { + InitializeFakeServer(); + const std::string kTestAlpn = "An ALPN That Client Did Not Offer"; + EXPECT_CALL(*server_session_, SelectAlpn(_)) + .WillOnce( + [kTestAlpn](const std::vector<quiche::QuicheStringPiece>& alpns) { + return std::find(alpns.cbegin(), alpns.cend(), kTestAlpn); + }); + EXPECT_CALL(*connection_, CloseConnection(QUIC_HANDSHAKE_FAILED, + "Server did not select ALPN", _)); + stream()->CryptoConnect(); + crypto_test_utils::AdvanceHandshake(connection_, stream(), 0, + server_connection_, server_stream(), 0); + + EXPECT_FALSE(stream()->one_rtt_keys_available()); + EXPECT_TRUE(stream()->encryption_established()); + EXPECT_FALSE(server_stream()->one_rtt_keys_available()); + EXPECT_TRUE(server_stream()->encryption_established()); +} + +TEST_P(TlsClientHandshakerTest, InvalidSNI) { + // Test that a client will skip sending SNI if configured to send an invalid + // hostname. In this case, the inclusion of '!' is invalid. + server_id_ = QuicServerId("invalid!.example.com", 443); + crypto_config_.reset(new QuicCryptoClientConfig( + std::make_unique<FakeProofVerifier>(), nullptr)); + CreateConnection(); + InitializeFakeServer(); + + stream()->CryptoConnect(); + crypto_test_utils::CommunicateHandshakeMessages( + connection_, stream(), server_connection_, server_stream()); + + EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol()); + EXPECT_TRUE(stream()->encryption_established()); + EXPECT_TRUE(stream()->one_rtt_keys_available()); + + EXPECT_EQ(server_stream()->crypto_negotiated_params().sni, ""); +} + +TEST_P(TlsClientHandshakerTest, BadTransportParams) { + if (!connection_->version().UsesHttp3()) { + return; + } + SetQuicReloadableFlag(quic_notify_handshaker_on_connection_close, true); + // Finish establishing the first connection: + CompleteCryptoHandshake(); + + // Create a second connection + CreateConnection(); + + stream()->CryptoConnect(); + auto* id_manager = QuicSessionPeer::v99_streamid_manager(session_.get()); + EXPECT_EQ(kDefaultMaxStreamsPerConnection, + id_manager->max_outgoing_bidirectional_streams()); + QuicConfig config; + config.SetMaxBidirectionalStreamsToSend( + config.GetMaxBidirectionalStreamsToSend() - 1); + + EXPECT_CALL(*connection_, CloseConnection(QUIC_MAX_STREAMS_ERROR, _, _)) + .WillOnce(testing::Invoke(connection_, + &MockQuicConnection::ReallyCloseConnection)); + // Close connection will be called again in the handshaker, but this will be + // no-op as the connection is already closed. + EXPECT_CALL(*connection_, CloseConnection(QUIC_HANDSHAKE_FAILED, _, _)); + + crypto_test_utils::HandshakeWithFakeServer( + &config, server_crypto_config_.get(), &server_helper_, &alarm_factory_, + connection_, stream(), AlpnForVersion(connection_->version())); +} + +} // namespace +} // namespace test +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_handshaker_test.cc b/chromium/net/third_party/quiche/src/quic/core/tls_handshaker_test.cc index 2d332a385bd..5a2bd6400aa 100644 --- a/chromium/net/third_party/quiche/src/quic/core/tls_handshaker_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/tls_handshaker_test.cc @@ -2,15 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <memory> #include <string> #include <utility> +#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h" #include "net/third_party/quiche/src/quic/core/crypto/tls_client_connection.h" #include "net/third_party/quiche/src/quic/core/crypto/tls_server_connection.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h" #include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" #include "net/third_party/quiche/src/quic/test_tools/fake_proof_source.h" @@ -53,6 +54,7 @@ class TestProofVerifier : public ProofVerifier { QuicAsyncStatus VerifyCertChain( const std::string& hostname, + const uint16_t port, const std::vector<std::string>& certs, const std::string& ocsp_response, const std::string& cert_sct, @@ -61,12 +63,12 @@ class TestProofVerifier : public ProofVerifier { std::unique_ptr<ProofVerifyDetails>* details, std::unique_ptr<ProofVerifierCallback> callback) override { if (!active_) { - return verifier_->VerifyCertChain(hostname, certs, ocsp_response, + return verifier_->VerifyCertChain(hostname, port, certs, ocsp_response, cert_sct, context, error_details, details, std::move(callback)); } pending_ops_.push_back(std::make_unique<VerifyChainPendingOp>( - hostname, certs, ocsp_response, cert_sct, context, error_details, + hostname, port, certs, ocsp_response, cert_sct, context, error_details, details, std::move(callback), verifier_.get())); return QUIC_PENDING; } @@ -101,6 +103,7 @@ class TestProofVerifier : public ProofVerifier { class VerifyChainPendingOp { public: VerifyChainPendingOp(const std::string& hostname, + const uint16_t port, const std::vector<std::string>& certs, const std::string& ocsp_response, const std::string& cert_sct, @@ -110,6 +113,7 @@ class TestProofVerifier : public ProofVerifier { std::unique_ptr<ProofVerifierCallback> callback, ProofVerifier* delegate) : hostname_(hostname), + port_(port), certs_(certs), ocsp_response_(ocsp_response), cert_sct_(cert_sct), @@ -125,7 +129,7 @@ class TestProofVerifier : public ProofVerifier { // runs the original callback after asserting that the verification ran // synchronously. QuicAsyncStatus status = delegate_->VerifyCertChain( - hostname_, certs_, ocsp_response_, cert_sct_, context_, + hostname_, port_, certs_, ocsp_response_, cert_sct_, context_, error_details_, details_, std::make_unique<FailingProofVerifierCallback>()); ASSERT_NE(status, QUIC_PENDING); @@ -134,6 +138,7 @@ class TestProofVerifier : public ProofVerifier { private: std::string hostname_; + const uint16_t port_; std::vector<std::string> certs_; std::string ocsp_response_; std::string cert_sct_; @@ -182,6 +187,7 @@ class TestQuicCryptoStream : public QuicCryptoStream { void OnPacketDecrypted(EncryptionLevel /*level*/) override {} void OnOneRttPacketAcknowledged() override {} + void OnHandshakePacketSent() override {} HandshakeState GetHandshakeState() const override { return handshaker()->GetHandshakeState(); @@ -224,8 +230,16 @@ class MockProofHandler : public QuicCryptoClientStream::ProofHandler { MockProofHandler() = default; ~MockProofHandler() override {} - MOCK_METHOD1(OnProofValid, void(const QuicCryptoClientConfig::CachedState&)); - MOCK_METHOD1(OnProofVerifyDetailsAvailable, void(const ProofVerifyDetails&)); + MOCK_METHOD( // NOLINT(build/deprecated) + void, + OnProofValid, + (const QuicCryptoClientConfig::CachedState&), + (override)); + MOCK_METHOD( // NOLINT(build/deprecated) + void, + OnProofVerifyDetailsAvailable, + (const ProofVerifyDetails&), + (override)); }; class TestQuicCryptoClientStream : public TestQuicCryptoStream { @@ -247,7 +261,8 @@ class TestQuicCryptoClientStream : public TestQuicCryptoStream { session, crypto_test_utils::ProofVerifyContextForTesting(), &crypto_config_, - &proof_handler_)) {} + &proof_handler_, + /*has_application_state = */ false)) {} ~TestQuicCryptoClientStream() override = default; @@ -271,10 +286,9 @@ class TestQuicCryptoClientStream : public TestQuicCryptoStream { class TestTlsServerHandshaker : public TlsServerHandshaker { public: TestTlsServerHandshaker(QuicSession* session, - SSL_CTX* ssl_ctx, - ProofSource* proof_source, + const QuicCryptoServerConfig& crypto_config, TestQuicCryptoStream* test_stream) - : TlsServerHandshaker(session, ssl_ctx, proof_source), + : TlsServerHandshaker(session, crypto_config), test_stream_(test_stream) {} void WriteCryptoData(EncryptionLevel level, @@ -288,15 +302,14 @@ class TestTlsServerHandshaker : public TlsServerHandshaker { class TestQuicCryptoServerStream : public TestQuicCryptoStream { public: - TestQuicCryptoServerStream(QuicSession* session, - FakeProofSource* proof_source) + TestQuicCryptoServerStream(QuicSession* session) : TestQuicCryptoStream(session), - proof_source_(proof_source), - ssl_ctx_(TlsServerConnection::CreateSslCtx()), - handshaker_(new TestTlsServerHandshaker(session, - ssl_ctx_.get(), - proof_source_, - this)) {} + crypto_config_(QuicCryptoServerConfig::TESTING, + QuicRandom::GetInstance(), + std::make_unique<FakeProofSource>(), + KeyExchangeSource::Default()), + handshaker_( + new TestTlsServerHandshaker(session, crypto_config_, this)) {} ~TestQuicCryptoServerStream() override = default; @@ -311,11 +324,12 @@ class TestQuicCryptoServerStream : public TestQuicCryptoStream { TlsHandshaker* handshaker() const override { return handshaker_.get(); } - FakeProofSource* GetFakeProofSource() const { return proof_source_; } + FakeProofSource* GetFakeProofSource() const { + return static_cast<FakeProofSource*>(crypto_config_.proof_source()); + } private: - FakeProofSource* proof_source_; - bssl::UniquePtr<SSL_CTX> ssl_ctx_; + QuicCryptoServerConfig crypto_config_; std::unique_ptr<TlsServerHandshaker> handshaker_; }; @@ -344,8 +358,7 @@ class TlsHandshakerTest : public QuicTestWithParam<ParsedQuicVersion> { server_session_(server_conn_, /*create_mock_crypto_stream=*/false) { client_stream_ = new TestQuicCryptoClientStream(&client_session_); client_session_.SetCryptoStream(client_stream_); - server_stream_ = - new TestQuicCryptoServerStream(&server_session_, &proof_source_); + server_stream_ = new TestQuicCryptoServerStream(&server_session_); server_session_.SetCryptoStream(server_stream_); client_session_.Initialize(); server_session_.Initialize(); @@ -401,7 +414,6 @@ class TlsHandshakerTest : public QuicTestWithParam<ParsedQuicVersion> { MockQuicSession client_session_; MockQuicSession server_session_; - FakeProofSource proof_source_; TestQuicCryptoClientStream* client_stream_; TestQuicCryptoServerStream* server_stream_; }; @@ -434,236 +446,6 @@ TEST_P(TlsHandshakerTest, CryptoHandshake) { ExpectHandshakeSuccessful(); } -TEST_P(TlsHandshakerTest, HandshakeWithAsyncProofSource) { - EXPECT_CALL(*client_conn_, CloseConnection(_, _, _)).Times(0); - EXPECT_CALL(*server_conn_, CloseConnection(_, _, _)).Times(0); - // Enable FakeProofSource to capture call to ComputeTlsSignature and run it - // asynchronously. - FakeProofSource* proof_source = server_stream_->GetFakeProofSource(); - proof_source->Activate(); - - // Start handshake. - client_stream_->CryptoConnect(); - ExchangeHandshakeMessages(client_stream_, server_stream_); - - ASSERT_EQ(proof_source->NumPendingCallbacks(), 1); - proof_source->InvokePendingCallback(0); - - ExchangeHandshakeMessages(client_stream_, server_stream_); - - ExpectHandshakeSuccessful(); -} - -TEST_P(TlsHandshakerTest, CancelPendingProofSource) { - EXPECT_CALL(*client_conn_, CloseConnection(_, _, _)).Times(0); - EXPECT_CALL(*server_conn_, CloseConnection(_, _, _)).Times(0); - // Enable FakeProofSource to capture call to ComputeTlsSignature and run it - // asynchronously. - FakeProofSource* proof_source = server_stream_->GetFakeProofSource(); - proof_source->Activate(); - - // Start handshake. - client_stream_->CryptoConnect(); - ExchangeHandshakeMessages(client_stream_, server_stream_); - - ASSERT_EQ(proof_source->NumPendingCallbacks(), 1); - server_stream_ = nullptr; - - proof_source->InvokePendingCallback(0); -} - -TEST_P(TlsHandshakerTest, HandshakeWithAsyncProofVerifier) { - EXPECT_CALL(*client_conn_, CloseConnection(_, _, _)).Times(0); - EXPECT_CALL(*server_conn_, CloseConnection(_, _, _)).Times(0); - // Enable TestProofVerifier to capture call to VerifyCertChain and run it - // asynchronously. - TestProofVerifier* proof_verifier = client_stream_->GetTestProofVerifier(); - proof_verifier->Activate(); - - EXPECT_CALL(client_stream_->proof_handler(), OnProofVerifyDetailsAvailable); - - // Start handshake. - client_stream_->CryptoConnect(); - ExchangeHandshakeMessages(client_stream_, server_stream_); - - ASSERT_EQ(proof_verifier->NumPendingCallbacks(), 1u); - proof_verifier->InvokePendingCallback(0); - - ExchangeHandshakeMessages(client_stream_, server_stream_); - - ExpectHandshakeSuccessful(); -} - -TEST_P(TlsHandshakerTest, ClientSendsNoSNI) { - // Create a new client stream (and handshaker) with an empty server hostname. - client_stream_ = - new TestQuicCryptoClientStream(&client_session_, QuicServerId("", 443), - std::make_unique<FakeProofVerifier>()); - client_session_.SetCryptoStream(client_stream_); - - EXPECT_CALL(*client_conn_, CloseConnection(_, _, _)).Times(0); - EXPECT_CALL(*server_conn_, CloseConnection(_, _, _)).Times(0); - EXPECT_CALL(client_stream_->proof_handler(), OnProofVerifyDetailsAvailable); - client_stream_->CryptoConnect(); - ExchangeHandshakeMessages(client_stream_, server_stream_); - - ExpectHandshakeSuccessful(); - EXPECT_EQ(server_stream_->crypto_negotiated_params().sni, ""); -} - -TEST_P(TlsHandshakerTest, ServerExtractSNI) { - EXPECT_CALL(*client_conn_, CloseConnection(_, _, _)).Times(0); - EXPECT_CALL(*server_conn_, CloseConnection(_, _, _)).Times(0); - EXPECT_CALL(client_stream_->proof_handler(), OnProofVerifyDetailsAvailable); - client_stream_->CryptoConnect(); - ExchangeHandshakeMessages(client_stream_, server_stream_); - ExpectHandshakeSuccessful(); - - EXPECT_EQ(server_stream_->crypto_negotiated_params().sni, "test.example.com"); -} - -TEST_P(TlsHandshakerTest, ClientConnectionClosedOnTlsError) { - // Have client send ClientHello. - client_stream_->CryptoConnect(); - EXPECT_CALL(*client_conn_, CloseConnection(QUIC_HANDSHAKE_FAILED, _, _)); - - // Send a zero-length ServerHello from server to client. - char bogus_handshake_message[] = { - // Handshake struct (RFC 8446 appendix B.3) - 2, // HandshakeType server_hello - 0, 0, 0, // uint24 length - }; - server_stream_->WriteCryptoData( - ENCRYPTION_INITIAL, - quiche::QuicheStringPiece(bogus_handshake_message, - QUICHE_ARRAYSIZE(bogus_handshake_message))); - server_stream_->SendCryptoMessagesToPeer(client_stream_); - - EXPECT_FALSE(client_stream_->one_rtt_keys_available()); -} - -TEST_P(TlsHandshakerTest, ServerConnectionClosedOnTlsError) { - EXPECT_CALL(*server_conn_, CloseConnection(QUIC_HANDSHAKE_FAILED, _, _)); - - // Send a zero-length ClientHello from client to server. - char bogus_handshake_message[] = { - // Handshake struct (RFC 8446 appendix B.3) - 1, // HandshakeType client_hello - 0, 0, 0, // uint24 length - }; - client_stream_->WriteCryptoData( - ENCRYPTION_INITIAL, - quiche::QuicheStringPiece(bogus_handshake_message, - QUICHE_ARRAYSIZE(bogus_handshake_message))); - client_stream_->SendCryptoMessagesToPeer(server_stream_); - - EXPECT_FALSE(server_stream_->one_rtt_keys_available()); -} - -TEST_P(TlsHandshakerTest, ClientNotSendingALPN) { - client_stream_->client_handshaker()->AllowEmptyAlpnForTests(); - EXPECT_CALL(client_session_, GetAlpnsToOffer()) - .WillOnce(Return(std::vector<std::string>())); - EXPECT_CALL(*client_conn_, CloseConnection(QUIC_HANDSHAKE_FAILED, - "Server did not select ALPN", _)); - EXPECT_CALL(*server_conn_, - CloseConnection(QUIC_HANDSHAKE_FAILED, - "Server did not receive a known ALPN", _)); - client_stream_->CryptoConnect(); - ExchangeHandshakeMessages(client_stream_, server_stream_); - - EXPECT_FALSE(client_stream_->one_rtt_keys_available()); - EXPECT_EQ(GetQuicRestartFlag(quic_send_settings_on_write_key_available), - client_stream_->encryption_established()); - EXPECT_FALSE(server_stream_->one_rtt_keys_available()); - EXPECT_EQ(GetQuicRestartFlag(quic_send_settings_on_write_key_available), - server_stream_->encryption_established()); -} - -TEST_P(TlsHandshakerTest, ClientSendingBadALPN) { - const std::string kTestBadClientAlpn = "bad-client-alpn"; - EXPECT_CALL(client_session_, GetAlpnsToOffer()) - .WillOnce(Return(std::vector<std::string>({kTestBadClientAlpn}))); - EXPECT_CALL(*client_conn_, CloseConnection(QUIC_HANDSHAKE_FAILED, - "Server did not select ALPN", _)); - EXPECT_CALL(*server_conn_, - CloseConnection(QUIC_HANDSHAKE_FAILED, - "Server did not receive a known ALPN", _)); - client_stream_->CryptoConnect(); - ExchangeHandshakeMessages(client_stream_, server_stream_); - - EXPECT_FALSE(client_stream_->one_rtt_keys_available()); - EXPECT_EQ(GetQuicRestartFlag(quic_send_settings_on_write_key_available), - client_stream_->encryption_established()); - EXPECT_FALSE(server_stream_->one_rtt_keys_available()); - EXPECT_EQ(GetQuicRestartFlag(quic_send_settings_on_write_key_available), - server_stream_->encryption_established()); -} - -TEST_P(TlsHandshakerTest, ClientSendingTooManyALPNs) { - std::string long_alpn(250, 'A'); - EXPECT_CALL(client_session_, GetAlpnsToOffer()) - .WillOnce(Return(std::vector<std::string>({ - long_alpn + "1", - long_alpn + "2", - long_alpn + "3", - long_alpn + "4", - long_alpn + "5", - long_alpn + "6", - long_alpn + "7", - long_alpn + "8", - }))); - EXPECT_QUIC_BUG(client_stream_->CryptoConnect(), "Failed to set ALPN"); -} - -TEST_P(TlsHandshakerTest, ServerRequiresCustomALPN) { - const std::string kTestAlpn = "An ALPN That Client Did Not Offer"; - EXPECT_CALL(server_session_, SelectAlpn(_)) - .WillOnce( - [kTestAlpn](const std::vector<quiche::QuicheStringPiece>& alpns) { - return std::find(alpns.cbegin(), alpns.cend(), kTestAlpn); - }); - EXPECT_CALL(*client_conn_, CloseConnection(QUIC_HANDSHAKE_FAILED, - "Server did not select ALPN", _)); - EXPECT_CALL(*server_conn_, - CloseConnection(QUIC_HANDSHAKE_FAILED, - "Server did not receive a known ALPN", _)); - client_stream_->CryptoConnect(); - ExchangeHandshakeMessages(client_stream_, server_stream_); - - EXPECT_FALSE(client_stream_->one_rtt_keys_available()); - EXPECT_EQ(GetQuicRestartFlag(quic_send_settings_on_write_key_available), - client_stream_->encryption_established()); - EXPECT_FALSE(server_stream_->one_rtt_keys_available()); - EXPECT_EQ(GetQuicRestartFlag(quic_send_settings_on_write_key_available), - server_stream_->encryption_established()); -} - -TEST_P(TlsHandshakerTest, CustomALPNNegotiation) { - EXPECT_CALL(*client_conn_, CloseConnection(_, _, _)).Times(0); - EXPECT_CALL(*server_conn_, CloseConnection(_, _, _)).Times(0); - - const std::string kTestAlpn = "A Custom ALPN Value"; - const std::vector<std::string> kTestAlpns( - {"foo", "bar", kTestAlpn, "something else"}); - EXPECT_CALL(client_session_, GetAlpnsToOffer()) - .WillRepeatedly(Return(kTestAlpns)); - EXPECT_CALL(server_session_, SelectAlpn(_)) - .WillOnce([kTestAlpn, kTestAlpns]( - const std::vector<quiche::QuicheStringPiece>& alpns) { - EXPECT_THAT(alpns, ElementsAreArray(kTestAlpns)); - return std::find(alpns.cbegin(), alpns.cend(), kTestAlpn); - }); - EXPECT_CALL(client_session_, - OnAlpnSelected(quiche::QuicheStringPiece(kTestAlpn))); - EXPECT_CALL(server_session_, - OnAlpnSelected(quiche::QuicheStringPiece(kTestAlpn))); - client_stream_->CryptoConnect(); - ExchangeHandshakeMessages(client_stream_, server_stream_); - - ExpectHandshakeSuccessful(); -} - } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc index ced2bd4a51c..5bd5b3d642d 100644 --- a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc +++ b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc @@ -44,14 +44,51 @@ void TlsServerHandshaker::SignatureCallback::Cancel() { handshaker_ = nullptr; } -TlsServerHandshaker::TlsServerHandshaker(QuicSession* session, - SSL_CTX* ssl_ctx, - ProofSource* proof_source) +TlsServerHandshaker::DecryptCallback::DecryptCallback( + TlsServerHandshaker* handshaker) + : handshaker_(handshaker) {} + +void TlsServerHandshaker::DecryptCallback::Run(std::vector<uint8_t> plaintext) { + if (handshaker_ == nullptr) { + // The callback was cancelled before we could run. + return; + } + handshaker_->decrypted_session_ticket_ = std::move(plaintext); + // DecryptCallback::Run could be called synchronously. When that happens, we + // are currently in the middle of a call to AdvanceHandshake. + // (AdvanceHandshake called SSL_do_handshake, which through some layers called + // SessionTicketOpen, which called TicketCrypter::Decrypt, which synchronously + // called this function.) In that case, the handshake will continue to be + // processed when this function returns. + // + // When this callback is called asynchronously (i.e. the ticket decryption is + // pending), TlsServerHandshaker is not actively processing handshake + // messages. We need to have it resume processing handshake messages by + // calling AdvanceHandshake. + if (handshaker_->state_ == STATE_TICKET_DECRYPTION_PENDING) { + handshaker_->AdvanceHandshake(); + } + // The TicketDecrypter took ownership of this callback when Decrypt was + // called. Once the callback returns, it will be deleted. Remove the + // (non-owning) pointer to the callback from the handshaker so the handshaker + // doesn't have an invalid pointer hanging around. + handshaker_->ticket_decryption_callback_ = nullptr; +} + +void TlsServerHandshaker::DecryptCallback::Cancel() { + DCHECK(handshaker_); + handshaker_ = nullptr; +} + +TlsServerHandshaker::TlsServerHandshaker( + QuicSession* session, + const QuicCryptoServerConfig& crypto_config) : TlsHandshaker(this, session), QuicCryptoServerStreamBase(session), - proof_source_(proof_source), + proof_source_(crypto_config.proof_source()), + pre_shared_key_(crypto_config.pre_shared_key()), crypto_negotiated_params_(new QuicCryptoNegotiatedParameters), - tls_connection_(ssl_ctx, this) { + tls_connection_(crypto_config.ssl_ctx(), this) { DCHECK_EQ(PROTOCOL_TLS1_3, session->connection()->version().handshake_protocol); @@ -68,6 +105,10 @@ void TlsServerHandshaker::CancelOutstandingCallbacks() { signature_callback_->Cancel(); signature_callback_ = nullptr; } + if (ticket_decryption_callback_) { + ticket_decryption_callback_->Cancel(); + ticket_decryption_callback_ = nullptr; + } } bool TlsServerHandshaker::GetBase64SHA256ClientChannelID( @@ -121,6 +162,11 @@ bool TlsServerHandshaker::ShouldSendExpectCTHeader() const { return false; } +void TlsServerHandshaker::OnConnectionClosed(QuicErrorCode /*error*/, + ConnectionCloseSource /*source*/) { + state_ = STATE_CONNECTION_CLOSED; +} + bool TlsServerHandshaker::encryption_established() const { return encryption_established_; } @@ -195,6 +241,9 @@ void TlsServerHandshaker::AdvanceHandshake() { case STATE_SIGNATURE_PENDING: should_close = ssl_error != SSL_ERROR_WANT_PRIVATE_KEY_OPERATION; break; + case STATE_TICKET_DECRYPTION_PENDING: + should_close = ssl_error != SSL_ERROR_PENDING_TICKET; + break; default: should_close = true; } @@ -246,12 +295,12 @@ bool TlsServerHandshaker::ProcessTransportParameters( client_params.version, session()->connection()->version(), session()->supported_versions(), error_details) != QUIC_NO_ERROR || session()->config()->ProcessTransportParameters( - client_params, CLIENT, error_details) != QUIC_NO_ERROR) { + client_params, CLIENT, /* is_resumption = */ false, error_details) != + QUIC_NO_ERROR) { return false; } ProcessAdditionalTransportParameters(client_params); - session()->OnConfigNegotiated(); return true; } @@ -283,8 +332,11 @@ void TlsServerHandshaker::SetWriteSecret( EncryptionLevel level, const SSL_CIPHER* cipher, const std::vector<uint8_t>& write_secret) { - if (GetQuicRestartFlag(quic_send_settings_on_write_key_available) && - level == ENCRYPTION_FORWARD_SECURE) { + if (GetQuicReloadableFlag(quic_notify_handshaker_on_connection_close) && + state_ == STATE_CONNECTION_CLOSED) { + return; + } + if (level == ENCRYPTION_FORWARD_SECURE) { encryption_established_ = true; // Fill crypto_negotiated_params_: const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl()); @@ -309,20 +361,9 @@ void TlsServerHandshaker::FinishHandshake() { QUIC_LOG(INFO) << "Server: handshake finished"; state_ = STATE_HANDSHAKE_COMPLETE; - - if (!GetQuicRestartFlag(quic_send_settings_on_write_key_available)) { - encryption_established_ = true; - } one_rtt_keys_available_ = true; const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl()); - if (!GetQuicRestartFlag(quic_send_settings_on_write_key_available)) { - // Fill crypto_negotiated_params_: - if (cipher) { - crypto_negotiated_params_->cipher_suite = SSL_CIPHER_get_value(cipher); - } - crypto_negotiated_params_->key_exchange_group = SSL_get_curve_id(ssl()); - } if (!app_data_read_secret_.empty()) { if (!SetReadSecret(ENCRYPTION_FORWARD_SECURE, cipher, @@ -347,7 +388,8 @@ ssl_private_key_result_t TlsServerHandshaker::PrivateKeySign( quiche::QuicheStringPiece in) { signature_callback_ = new SignatureCallback(this); proof_source_->ComputeTlsSignature( - session()->connection()->self_address(), hostname_, sig_alg, in, + session()->connection()->self_address(), + session()->connection()->peer_address(), hostname_, sig_alg, in, std::unique_ptr<SignatureCallback>(signature_callback_)); if (state_ == STATE_SIGNATURE_COMPLETE) { return PrivateKeyComplete(out, out_len, max_out); @@ -373,24 +415,105 @@ ssl_private_key_result_t TlsServerHandshaker::PrivateKeyComplete( return ssl_private_key_success; } +size_t TlsServerHandshaker::SessionTicketMaxOverhead() { + DCHECK(proof_source_->GetTicketCrypter()); + return proof_source_->GetTicketCrypter()->MaxOverhead(); +} + +int TlsServerHandshaker::SessionTicketSeal(uint8_t* out, + size_t* out_len, + size_t max_out_len, + quiche::QuicheStringPiece in) { + DCHECK(proof_source_->GetTicketCrypter()); + std::vector<uint8_t> ticket = proof_source_->GetTicketCrypter()->Encrypt(in); + if (max_out_len < ticket.size()) { + QUIC_BUG + << "TicketCrypter returned " << ticket.size() + << " bytes of ciphertext, which is larger than its max overhead of " + << max_out_len; + return 0; // failure + } + *out_len = ticket.size(); + memcpy(out, ticket.data(), ticket.size()); + return 1; // success +} + +ssl_ticket_aead_result_t TlsServerHandshaker::SessionTicketOpen( + uint8_t* out, + size_t* out_len, + size_t max_out_len, + quiche::QuicheStringPiece in) { + DCHECK(proof_source_->GetTicketCrypter()); + + if (!ticket_decryption_callback_) { + ticket_decryption_callback_ = new DecryptCallback(this); + proof_source_->GetTicketCrypter()->Decrypt( + in, std::unique_ptr<DecryptCallback>(ticket_decryption_callback_)); + // Decrypt can run the callback synchronously. In that case, the callback + // will clear the ticket_decryption_callback_ pointer, and instead of + // returning ssl_ticket_aead_retry, we should continue processing to return + // the decrypted ticket. + // + // If the callback is not run asynchronously, return ssl_ticket_aead_retry + // and when the callback is complete this function will be run again to + // return the result. + if (ticket_decryption_callback_) { + state_ = STATE_TICKET_DECRYPTION_PENDING; + return ssl_ticket_aead_retry; + } + } + ticket_decryption_callback_ = nullptr; + state_ = STATE_LISTENING; + if (decrypted_session_ticket_.empty()) { + QUIC_DLOG(ERROR) << "Session ticket decryption failed; ignoring ticket"; + // Ticket decryption failed. Ignore the ticket. + return ssl_ticket_aead_ignore_ticket; + } + if (max_out_len < decrypted_session_ticket_.size()) { + return ssl_ticket_aead_error; + } + memcpy(out, decrypted_session_ticket_.data(), + decrypted_session_ticket_.size()); + *out_len = decrypted_session_ticket_.size(); + QUIC_RELOADABLE_FLAG_COUNT(quic_enable_tls_resumption); + + return ssl_ticket_aead_success; +} + int TlsServerHandshaker::SelectCertificate(int* out_alert) { const char* hostname = SSL_get_servername(ssl(), TLSEXT_NAMETYPE_host_name); if (hostname) { hostname_ = hostname; crypto_negotiated_params_->sni = QuicHostnameUtils::NormalizeHostname(hostname_); + if (GetQuicReloadableFlag(quic_tls_enforce_valid_sni)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_tls_enforce_valid_sni); + if (!QuicHostnameUtils::IsValidSNI(hostname_)) { + // TODO(b/151676147): Include this error string in the CONNECTION_CLOSE + // frame. + QUIC_LOG(ERROR) << "Invalid SNI provided: \"" << hostname_ << "\""; + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + } } else { QUIC_LOG(INFO) << "No hostname indicated in SNI"; } QuicReferenceCountedPointer<ProofSource::Chain> chain = proof_source_->GetCertChain(session()->connection()->self_address(), + session()->connection()->peer_address(), hostname_); - if (chain->certs.empty()) { + if (!chain || chain->certs.empty()) { QUIC_LOG(ERROR) << "No certs provided for host '" << hostname_ << "'"; return SSL_TLSEXT_ERR_ALERT_FATAL; } + if (!pre_shared_key_.empty()) { + // TODO(b/154162689) add PSK support to QUIC+TLS. + QUIC_BUG << "QUIC server pre-shared keys not yet supported with TLS"; + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + std::vector<CRYPTO_BUFFER*> certs; certs.resize(chain->certs.size()); for (size_t i = 0; i < certs.size(); i++) { @@ -412,6 +535,8 @@ int TlsServerHandshaker::SelectCertificate(int* out_alert) { return SSL_TLSEXT_ERR_ALERT_FATAL; } OverrideQuicConfigDefaults(session()->config()); + session()->OnConfigNegotiated(); + if (!SetTransportParameters()) { QUIC_LOG(ERROR) << "Failed to set transport parameters"; return SSL_TLSEXT_ERR_ALERT_FATAL; diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.h b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.h index 22ae45df9ed..c62dbbbe47c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.h +++ b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.h @@ -9,6 +9,7 @@ #include "third_party/boringssl/src/include/openssl/pool.h" #include "third_party/boringssl/src/include/openssl/ssl.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h" #include "net/third_party/quiche/src/quic/core/crypto/tls_server_connection.h" #include "net/third_party/quiche/src/quic/core/proto/cached_network_parameters_proto.h" #include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.h" @@ -27,8 +28,7 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker public QuicCryptoServerStreamBase { public: TlsServerHandshaker(QuicSession* session, - SSL_CTX* ssl_ctx, - ProofSource* proof_source); + const QuicCryptoServerConfig& crypto_config); TlsServerHandshaker(const TlsServerHandshaker&) = delete; TlsServerHandshaker& operator=(const TlsServerHandshaker&) = delete; @@ -47,6 +47,9 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker CachedNetworkParameters cached_network_params) override; void OnPacketDecrypted(EncryptionLevel level) override; void OnOneRttPacketAcknowledged() override {} + void OnHandshakePacketSent() override {} + void OnConnectionClosed(QuicErrorCode error, + ConnectionCloseSource source) override; void OnHandshakeDoneReceived() override; bool ShouldSendExpectCTHeader() const override; @@ -106,6 +109,16 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker ssl_private_key_result_t PrivateKeyComplete(uint8_t* out, size_t* out_len, size_t max_out) override; + size_t SessionTicketMaxOverhead() override; + int SessionTicketSeal(uint8_t* out, + size_t* out_len, + size_t max_out_len, + quiche::QuicheStringPiece in) override; + ssl_ticket_aead_result_t SessionTicketOpen( + uint8_t* out, + size_t* out_len, + size_t max_out_len, + quiche::QuicheStringPiece in) override; TlsConnection::Delegate* ConnectionDelegate() override { return this; } private: @@ -124,8 +137,22 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker TlsServerHandshaker* handshaker_; }; + class QUIC_EXPORT_PRIVATE DecryptCallback + : public ProofSource::DecryptCallback { + public: + explicit DecryptCallback(TlsServerHandshaker* handshaker); + void Run(std::vector<uint8_t> plaintext) override; + + // If called, Cancel causes the pending callback to be a no-op. + void Cancel(); + + private: + TlsServerHandshaker* handshaker_; + }; + enum State { STATE_LISTENING, + STATE_TICKET_DECRYPTION_PENDING, STATE_SIGNATURE_PENDING, STATE_SIGNATURE_COMPLETE, STATE_ENCRYPTION_HANDSHAKE_DATA_PROCESSED, @@ -146,10 +173,22 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker ProofSource* proof_source_; SignatureCallback* signature_callback_ = nullptr; + // State to handle potentially asynchronous session ticket decryption. + // |ticket_decryption_callback_| points to the non-owned callback that was + // passed to ProofSource::TicketCrypter::Decrypt but hasn't finished running + // yet. + DecryptCallback* ticket_decryption_callback_ = nullptr; + // |decrypted_session_ticket_| contains the decrypted session ticket after the + // callback has run but before it is passed to BoringSSL. + std::vector<uint8_t> decrypted_session_ticket_; + std::string hostname_; std::string cert_verify_sig_; std::unique_ptr<ProofSource::Details> proof_source_details_; + // Pre-shared key used during the handshake. + std::string pre_shared_key_; + // Used to hold the ENCRYPTION_FORWARD_SECURE read secret until the handshake // is complete. This is temporary until // https://bugs.chromium.org/p/boringssl/issues/detail?id=303 is resolved. diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc new file mode 100644 index 00000000000..a71338c5f5b --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc @@ -0,0 +1,467 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <memory> +#include <utility> +#include <vector> + +#include "net/third_party/quiche/src/quic/core/crypto/proof_source.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" +#include "net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h" +#include "net/third_party/quiche/src/quic/core/quic_session.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/core/quic_versions.h" +#include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/failing_proof_source.h" +#include "net/third_party/quiche/src/quic/test_tools/fake_proof_source.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/simple_session_cache.h" +#include "net/third_party/quiche/src/quic/test_tools/test_ticket_crypter.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" + +namespace quic { +class QuicConnection; +class QuicStream; +} // namespace quic + +using testing::_; +using testing::NiceMock; +using testing::Return; + +namespace quic { +namespace test { + +namespace { + +const char kServerHostname[] = "test.example.com"; +const uint16_t kServerPort = 443; + +class TlsServerHandshakerTest : public QuicTest { + public: + TlsServerHandshakerTest() + : server_compressed_certs_cache_( + QuicCompressedCertsCache::kQuicCompressedCertsCacheSize), + server_id_(kServerHostname, kServerPort, false), + client_crypto_config_(crypto_test_utils::ProofVerifierForTesting(), + std::make_unique<test::SimpleSessionCache>()) { + InitializeServerConfig(); + InitializeServer(); + InitializeFakeClient(); + } + + ~TlsServerHandshakerTest() override { + // Ensure that anything that might reference |helpers_| is destroyed before + // |helpers_| is destroyed. + server_session_.reset(); + client_session_.reset(); + helpers_.clear(); + alarm_factories_.clear(); + } + + void InitializeServerConfig() { + SetQuicReloadableFlag(quic_enable_tls_resumption, true); + auto ticket_crypter = std::make_unique<TestTicketCrypter>(); + ticket_crypter_ = ticket_crypter.get(); + auto proof_source = std::make_unique<FakeProofSource>(); + proof_source_ = proof_source.get(); + proof_source_->SetTicketCrypter(std::move(ticket_crypter)); + server_crypto_config_ = std::make_unique<QuicCryptoServerConfig>( + QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), + std::move(proof_source), KeyExchangeSource::Default()); + } + + void InitializeServerConfigWithFailingProofSource() { + server_crypto_config_ = std::make_unique<QuicCryptoServerConfig>( + QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), + std::make_unique<FailingProofSource>(), KeyExchangeSource::Default()); + } + + // Initializes the crypto server stream state for testing. May be + // called multiple times. + void InitializeServer() { + TestQuicSpdyServerSession* server_session = nullptr; + helpers_.push_back(std::make_unique<NiceMock<MockQuicConnectionHelper>>()); + alarm_factories_.push_back(std::make_unique<MockAlarmFactory>()); + CreateServerSessionForTest( + server_id_, QuicTime::Delta::FromSeconds(100000), supported_versions_, + helpers_.back().get(), alarm_factories_.back().get(), + server_crypto_config_.get(), &server_compressed_certs_cache_, + &server_connection_, &server_session); + CHECK(server_session); + server_session_.reset(server_session); + EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _, _, _)) + .Times(testing::AnyNumber()); + EXPECT_CALL(*server_session_, SelectAlpn(_)) + .WillRepeatedly( + [this](const std::vector<quiche::QuicheStringPiece>& alpns) { + return std::find( + alpns.cbegin(), alpns.cend(), + AlpnForVersion(server_session_->connection()->version())); + }); + crypto_test_utils::SetupCryptoServerConfigForTest( + server_connection_->clock(), server_connection_->random_generator(), + server_crypto_config_.get()); + } + + QuicCryptoServerStreamBase* server_stream() { + return server_session_->GetMutableCryptoStream(); + } + + QuicCryptoClientStream* client_stream() { + return client_session_->GetMutableCryptoStream(); + } + + // Initializes a fake client, and all its associated state, for + // testing. May be called multiple times. + void InitializeFakeClient() { + TestQuicSpdyClientSession* client_session = nullptr; + helpers_.push_back(std::make_unique<NiceMock<MockQuicConnectionHelper>>()); + alarm_factories_.push_back(std::make_unique<MockAlarmFactory>()); + CreateClientSessionForTest( + server_id_, QuicTime::Delta::FromSeconds(100000), supported_versions_, + helpers_.back().get(), alarm_factories_.back().get(), + &client_crypto_config_, &client_connection_, &client_session); + const std::string default_alpn = + AlpnForVersion(client_connection_->version()); + ON_CALL(*client_session, GetAlpnsToOffer()) + .WillByDefault(Return(std::vector<std::string>({default_alpn}))); + CHECK(client_session); + client_session_.reset(client_session); + moved_messages_counts_ = {0, 0}; + } + + void CompleteCryptoHandshake() { + while (!client_stream()->one_rtt_keys_available() || + !server_stream()->one_rtt_keys_available()) { + auto previous_moved_messages_counts = moved_messages_counts_; + AdvanceHandshakeWithFakeClient(); + // Check that the handshake has made forward progress + ASSERT_NE(previous_moved_messages_counts, moved_messages_counts_); + } + } + + // Performs a single round of handshake message-exchange between the + // client and server. + void AdvanceHandshakeWithFakeClient() { + CHECK(server_connection_); + CHECK(client_session_ != nullptr); + + EXPECT_CALL(*client_session_, OnProofValid(_)).Times(testing::AnyNumber()); + EXPECT_CALL(*client_session_, OnProofVerifyDetailsAvailable(_)) + .Times(testing::AnyNumber()); + EXPECT_CALL(*client_connection_, OnCanWrite()).Times(testing::AnyNumber()); + EXPECT_CALL(*server_connection_, OnCanWrite()).Times(testing::AnyNumber()); + // Call CryptoConnect if we haven't moved any client messages yet. + if (moved_messages_counts_.first == 0) { + client_stream()->CryptoConnect(); + } + moved_messages_counts_ = crypto_test_utils::AdvanceHandshake( + client_connection_, client_stream(), moved_messages_counts_.first, + server_connection_, server_stream(), moved_messages_counts_.second); + } + + void ExpectHandshakeSuccessful() { + EXPECT_TRUE(client_stream()->one_rtt_keys_available()); + EXPECT_TRUE(client_stream()->encryption_established()); + EXPECT_TRUE(server_stream()->one_rtt_keys_available()); + EXPECT_TRUE(server_stream()->encryption_established()); + EXPECT_EQ(HANDSHAKE_COMPLETE, client_stream()->GetHandshakeState()); + EXPECT_EQ(HANDSHAKE_CONFIRMED, server_stream()->GetHandshakeState()); + + const auto& client_crypto_params = + client_stream()->crypto_negotiated_params(); + const auto& server_crypto_params = + server_stream()->crypto_negotiated_params(); + // The TLS params should be filled in on the client. + EXPECT_NE(0, client_crypto_params.cipher_suite); + EXPECT_NE(0, client_crypto_params.key_exchange_group); + EXPECT_NE(0, client_crypto_params.peer_signature_algorithm); + + // The cipher suite and key exchange group should match on the client and + // server. + EXPECT_EQ(client_crypto_params.cipher_suite, + server_crypto_params.cipher_suite); + EXPECT_EQ(client_crypto_params.key_exchange_group, + server_crypto_params.key_exchange_group); + // We don't support client certs on the server (yet), so the server + // shouldn't have a peer signature algorithm to report. + EXPECT_EQ(0, server_crypto_params.peer_signature_algorithm); + } + + protected: + // Every connection gets its own MockQuicConnectionHelper and + // MockAlarmFactory, tracked separately from the server and client state so + // their lifetimes persist through the whole test. + std::vector<std::unique_ptr<MockQuicConnectionHelper>> helpers_; + std::vector<std::unique_ptr<MockAlarmFactory>> alarm_factories_; + + // Server state. + PacketSavingConnection* server_connection_; + std::unique_ptr<TestQuicSpdyServerSession> server_session_; + TestTicketCrypter* ticket_crypter_; // owned by proof_source_ + FakeProofSource* proof_source_; // owned by server_crypto_config_ + std::unique_ptr<QuicCryptoServerConfig> server_crypto_config_; + QuicCompressedCertsCache server_compressed_certs_cache_; + QuicServerId server_id_; + + // Client state. + PacketSavingConnection* client_connection_; + QuicCryptoClientConfig client_crypto_config_; + std::unique_ptr<TestQuicSpdyClientSession> client_session_; + + crypto_test_utils::FakeClientOptions client_options_; + // How many handshake messages have been moved from client to server and + // server to client. + std::pair<size_t, size_t> moved_messages_counts_ = {0, 0}; + + // Which QUIC versions the client and server support. + ParsedQuicVersionVector supported_versions_ = AllSupportedVersionsWithTls(); +}; + +TEST_F(TlsServerHandshakerTest, NotInitiallyConected) { + EXPECT_FALSE(server_stream()->encryption_established()); + EXPECT_FALSE(server_stream()->one_rtt_keys_available()); +} + +TEST_F(TlsServerHandshakerTest, ConnectedAfterTlsHandshake) { + CompleteCryptoHandshake(); + EXPECT_EQ(PROTOCOL_TLS1_3, server_stream()->handshake_protocol()); + ExpectHandshakeSuccessful(); +} + +TEST_F(TlsServerHandshakerTest, HandshakeWithAsyncProofSource) { + EXPECT_CALL(*client_connection_, CloseConnection(_, _, _)).Times(0); + EXPECT_CALL(*server_connection_, CloseConnection(_, _, _)).Times(0); + // Enable FakeProofSource to capture call to ComputeTlsSignature and run it + // asynchronously. + proof_source_->Activate(); + + // Start handshake. + AdvanceHandshakeWithFakeClient(); + + ASSERT_EQ(proof_source_->NumPendingCallbacks(), 1); + proof_source_->InvokePendingCallback(0); + + CompleteCryptoHandshake(); + + ExpectHandshakeSuccessful(); +} + +TEST_F(TlsServerHandshakerTest, CancelPendingProofSource) { + EXPECT_CALL(*client_connection_, CloseConnection(_, _, _)).Times(0); + EXPECT_CALL(*server_connection_, CloseConnection(_, _, _)).Times(0); + // Enable FakeProofSource to capture call to ComputeTlsSignature and run it + // asynchronously. + proof_source_->Activate(); + + // Start handshake. + AdvanceHandshakeWithFakeClient(); + + ASSERT_EQ(proof_source_->NumPendingCallbacks(), 1); + server_session_ = nullptr; + + proof_source_->InvokePendingCallback(0); +} + +TEST_F(TlsServerHandshakerTest, ExtractSNI) { + CompleteCryptoHandshake(); + ExpectHandshakeSuccessful(); + + EXPECT_EQ(server_stream()->crypto_negotiated_params().sni, + "test.example.com"); +} + +TEST_F(TlsServerHandshakerTest, ConnectionClosedOnTlsError) { + EXPECT_CALL(*server_connection_, + CloseConnection(QUIC_HANDSHAKE_FAILED, _, _)); + + // Send a zero-length ClientHello from client to server. + char bogus_handshake_message[] = { + // Handshake struct (RFC 8446 appendix B.3) + 1, // HandshakeType client_hello + 0, 0, 0, // uint24 length + }; + server_stream()->crypto_message_parser()->ProcessInput( + quiche::QuicheStringPiece(bogus_handshake_message, + QUICHE_ARRAYSIZE(bogus_handshake_message)), + ENCRYPTION_INITIAL); + + EXPECT_FALSE(server_stream()->one_rtt_keys_available()); +} + +TEST_F(TlsServerHandshakerTest, ClientNotSendingALPN) { + static_cast<TlsClientHandshaker*>( + QuicCryptoClientStreamPeer::GetHandshaker(client_stream())) + ->AllowEmptyAlpnForTests(); + EXPECT_CALL(*client_session_, GetAlpnsToOffer()) + .WillOnce(Return(std::vector<std::string>())); + EXPECT_CALL( + *client_connection_, + CloseConnection(QUIC_HANDSHAKE_FAILED, "Server did not select ALPN", _)); + EXPECT_CALL(*server_connection_, + CloseConnection(QUIC_HANDSHAKE_FAILED, + "Server did not receive a known ALPN", _)); + + // Process two flights of handshake messages. + AdvanceHandshakeWithFakeClient(); + AdvanceHandshakeWithFakeClient(); + + EXPECT_FALSE(client_stream()->one_rtt_keys_available()); + EXPECT_TRUE(client_stream()->encryption_established()); + EXPECT_FALSE(server_stream()->one_rtt_keys_available()); + EXPECT_TRUE(server_stream()->encryption_established()); +} + +TEST_F(TlsServerHandshakerTest, ClientSendingBadALPN) { + const std::string kTestBadClientAlpn = "bad-client-alpn"; + EXPECT_CALL(*client_session_, GetAlpnsToOffer()) + .WillOnce(Return(std::vector<std::string>({kTestBadClientAlpn}))); + EXPECT_CALL( + *client_connection_, + CloseConnection(QUIC_HANDSHAKE_FAILED, "Server did not select ALPN", _)); + EXPECT_CALL(*server_connection_, + CloseConnection(QUIC_HANDSHAKE_FAILED, + "Server did not receive a known ALPN", _)); + + // Process two flights of handshake messages. + AdvanceHandshakeWithFakeClient(); + AdvanceHandshakeWithFakeClient(); + + EXPECT_FALSE(client_stream()->one_rtt_keys_available()); + EXPECT_TRUE(client_stream()->encryption_established()); + EXPECT_FALSE(server_stream()->one_rtt_keys_available()); + EXPECT_TRUE(server_stream()->encryption_established()); +} + +TEST_F(TlsServerHandshakerTest, CustomALPNNegotiation) { + EXPECT_CALL(*client_connection_, CloseConnection(_, _, _)).Times(0); + EXPECT_CALL(*server_connection_, CloseConnection(_, _, _)).Times(0); + + const std::string kTestAlpn = "A Custom ALPN Value"; + const std::vector<std::string> kTestAlpns( + {"foo", "bar", kTestAlpn, "something else"}); + EXPECT_CALL(*client_session_, GetAlpnsToOffer()) + .WillRepeatedly(Return(kTestAlpns)); + EXPECT_CALL(*server_session_, SelectAlpn(_)) + .WillOnce([kTestAlpn, kTestAlpns]( + const std::vector<quiche::QuicheStringPiece>& alpns) { + EXPECT_THAT(alpns, testing::ElementsAreArray(kTestAlpns)); + return std::find(alpns.cbegin(), alpns.cend(), kTestAlpn); + }); + EXPECT_CALL(*client_session_, + OnAlpnSelected(quiche::QuicheStringPiece(kTestAlpn))); + EXPECT_CALL(*server_session_, + OnAlpnSelected(quiche::QuicheStringPiece(kTestAlpn))); + + CompleteCryptoHandshake(); + ExpectHandshakeSuccessful(); +} + +TEST_F(TlsServerHandshakerTest, RejectInvalidSNI) { + SetQuicReloadableFlag(quic_tls_enforce_valid_sni, true); + server_id_ = QuicServerId("invalid!.example.com", kServerPort, false); + InitializeFakeClient(); + static_cast<TlsClientHandshaker*>( + QuicCryptoClientStreamPeer::GetHandshaker(client_stream())) + ->AllowInvalidSNIForTests(); + + // Run the handshake and expect it to fail. + AdvanceHandshakeWithFakeClient(); + EXPECT_FALSE(server_stream()->encryption_established()); + EXPECT_FALSE(server_stream()->one_rtt_keys_available()); +} + +TEST_F(TlsServerHandshakerTest, Resumption) { + // Do the first handshake + InitializeFakeClient(); + CompleteCryptoHandshake(); + ExpectHandshakeSuccessful(); + EXPECT_FALSE(client_stream()->IsResumption()); + + // Now do another handshake + InitializeServer(); + InitializeFakeClient(); + CompleteCryptoHandshake(); + ExpectHandshakeSuccessful(); + EXPECT_TRUE(client_stream()->IsResumption()); +} + +TEST_F(TlsServerHandshakerTest, ResumptionWithAsyncDecryptCallback) { + // Do the first handshake + InitializeFakeClient(); + CompleteCryptoHandshake(); + ExpectHandshakeSuccessful(); + + ticket_crypter_->SetRunCallbacksAsync(true); + // Now do another handshake + InitializeServer(); + InitializeFakeClient(); + + AdvanceHandshakeWithFakeClient(); + // Test that the DecryptCallback will be run asynchronously, and then run it. + ASSERT_EQ(ticket_crypter_->NumPendingCallbacks(), 1u); + ticket_crypter_->RunPendingCallback(0); + + CompleteCryptoHandshake(); + ExpectHandshakeSuccessful(); + EXPECT_TRUE(client_stream()->IsResumption()); +} + +TEST_F(TlsServerHandshakerTest, ResumptionWithFailingDecryptCallback) { + // Do the first handshake + InitializeFakeClient(); + CompleteCryptoHandshake(); + ExpectHandshakeSuccessful(); + + ticket_crypter_->set_fail_decrypt(true); + // Now do another handshake + InitializeServer(); + InitializeFakeClient(); + CompleteCryptoHandshake(); + ExpectHandshakeSuccessful(); + EXPECT_FALSE(client_stream()->IsResumption()); +} + +TEST_F(TlsServerHandshakerTest, ResumptionWithFailingAsyncDecryptCallback) { + // Do the first handshake + InitializeFakeClient(); + CompleteCryptoHandshake(); + ExpectHandshakeSuccessful(); + + ticket_crypter_->set_fail_decrypt(true); + ticket_crypter_->SetRunCallbacksAsync(true); + // Now do another handshake + InitializeServer(); + InitializeFakeClient(); + + AdvanceHandshakeWithFakeClient(); + // Test that the DecryptCallback will be run asynchronously, and then run it. + ASSERT_EQ(ticket_crypter_->NumPendingCallbacks(), 1u); + ticket_crypter_->RunPendingCallback(0); + + CompleteCryptoHandshake(); + ExpectHandshakeSuccessful(); + EXPECT_FALSE(client_stream()->IsResumption()); +} + +TEST_F(TlsServerHandshakerTest, HandshakeFailsWithFailingProofSource) { + InitializeServerConfigWithFailingProofSource(); + InitializeServer(); + InitializeFakeClient(); + + // Attempt handshake. + AdvanceHandshakeWithFakeClient(); + // Check that the server didn't send any handshake messages, because it failed + // to handshake. + EXPECT_EQ(moved_messages_counts_.second, 0u); +} + +} // namespace +} // namespace test +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.cc b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.cc index daa56302145..6951b2cea3f 100644 --- a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.cc +++ b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.cc @@ -20,14 +20,14 @@ UberQuicStreamIdManager::UberQuicStreamIdManager( : bidirectional_stream_id_manager_(delegate, /*unidirectional=*/false, perspective, - version.transport_version, + version, max_open_outgoing_bidirectional_streams, max_open_incoming_bidirectional_streams), unidirectional_stream_id_manager_( delegate, /*unidirectional=*/true, perspective, - version.transport_version, + version, max_open_outgoing_unidirectional_streams, max_open_incoming_unidirectional_streams) {} @@ -96,13 +96,6 @@ bool UberQuicStreamIdManager::OnStreamsBlockedFrame( error_details); } -bool UberQuicStreamIdManager::IsIncomingStream(QuicStreamId id) const { - if (QuicUtils::IsBidirectionalStreamId(id)) { - return bidirectional_stream_id_manager_.IsIncomingStream(id); - } - return unidirectional_stream_id_manager_.IsIncomingStream(id); -} - bool UberQuicStreamIdManager::IsAvailableStream(QuicStreamId id) const { if (QuicUtils::IsBidirectionalStreamId(id)) { return bidirectional_stream_id_manager_.IsAvailableStream(id); diff --git a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h index d3f374a83a5..b1fc1260987 100644 --- a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h @@ -66,9 +66,6 @@ class QUIC_EXPORT_PRIVATE UberQuicStreamIdManager { bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame, std::string* error_details); - // Return true if |id| is peer initiated. - bool IsIncomingStream(QuicStreamId id) const; - // Returns true if |id| is still available. bool IsAvailableStream(QuicStreamId id) const; diff --git a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager_test.cc index 4fc1ccab333..7cae0a6e1de 100644 --- a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager_test.cc @@ -46,8 +46,10 @@ std::vector<TestParams> GetTestParams() { class MockDelegate : public QuicStreamIdManager::DelegateInterface { public: - MOCK_METHOD2(SendMaxStreams, - void(QuicStreamCount stream_count, bool unidirectional)); + MOCK_METHOD(void, + SendMaxStreams, + (QuicStreamCount stream_count, bool unidirectional), + (override)); }; class UberQuicStreamIdManagerTest : public QuicTestWithParam<TestParams> { @@ -64,25 +66,25 @@ class UberQuicStreamIdManagerTest : public QuicTestWithParam<TestParams> { QuicStreamId GetNthClientInitiatedBidirectionalId(int n) { return QuicUtils::GetFirstBidirectionalStreamId(transport_version(), Perspective::IS_CLIENT) + - kV99StreamIdIncrement * n; + QuicUtils::StreamIdDelta(transport_version()) * n; } QuicStreamId GetNthClientInitiatedUnidirectionalId(int n) { return QuicUtils::GetFirstUnidirectionalStreamId(transport_version(), Perspective::IS_CLIENT) + - kV99StreamIdIncrement * n; + QuicUtils::StreamIdDelta(transport_version()) * n; } QuicStreamId GetNthServerInitiatedBidirectionalId(int n) { return QuicUtils::GetFirstBidirectionalStreamId(transport_version(), Perspective::IS_SERVER) + - kV99StreamIdIncrement * n; + QuicUtils::StreamIdDelta(transport_version()) * n; } QuicStreamId GetNthServerInitiatedUnidirectionalId(int n) { return QuicUtils::GetFirstUnidirectionalStreamId(transport_version(), Perspective::IS_SERVER) + - kV99StreamIdIncrement * n; + QuicUtils::StreamIdDelta(transport_version()) * n; } QuicStreamId GetNthPeerInitiatedBidirectionalStreamId(int n) { @@ -300,17 +302,6 @@ TEST_P(UberQuicStreamIdManagerTest, OnStreamsBlockedFrame) { EXPECT_TRUE(manager_.OnStreamsBlockedFrame(frame, nullptr)); } -TEST_P(UberQuicStreamIdManagerTest, IsIncomingStream) { - EXPECT_TRUE( - manager_.IsIncomingStream(GetNthPeerInitiatedBidirectionalStreamId(0))); - EXPECT_TRUE( - manager_.IsIncomingStream(GetNthPeerInitiatedUnidirectionalStreamId(0))); - EXPECT_FALSE( - manager_.IsIncomingStream(GetNthSelfInitiatedBidirectionalStreamId(0))); - EXPECT_FALSE( - manager_.IsIncomingStream(GetNthSelfInitiatedUnidirectionalStreamId(0))); -} - TEST_P(UberQuicStreamIdManagerTest, SetMaxOpenOutgoingStreamsPlusFrame) { const size_t kNumMaxOutgoingStream = 123; // Set the uni- and bi- directional limits to different values to ensure diff --git a/chromium/net/third_party/quiche/src/quic/masque/masque_client_session.h b/chromium/net/third_party/quiche/src/quic/masque/masque_client_session.h index acf21118c59..fee24c908ee 100644 --- a/chromium/net/third_party/quiche/src/quic/masque/masque_client_session.h +++ b/chromium/net/third_party/quiche/src/quic/masque/masque_client_session.h @@ -86,9 +86,9 @@ class QUIC_NO_EXPORT MasqueClientSession : public QuicSpdyClientSession { void UnregisterConnectionId(QuicConnectionId client_connection_id); private: - QuicUnorderedMap<QuicConnectionId, - EncapsulatedClientSession*, - QuicConnectionIdHash> + QuicHashMap<QuicConnectionId, + EncapsulatedClientSession*, + QuicConnectionIdHash> client_connection_id_registrations_; Owner* owner_; // Unowned; MasqueCompressionEngine compression_engine_; diff --git a/chromium/net/third_party/quiche/src/quic/masque/masque_compression_engine.h b/chromium/net/third_party/quiche/src/quic/masque/masque_compression_engine.h index 95328df7acf..5ab88bd9d7e 100644 --- a/chromium/net/third_party/quiche/src/quic/masque/masque_compression_engine.h +++ b/chromium/net/third_party/quiche/src/quic/masque/masque_compression_engine.h @@ -117,7 +117,7 @@ class QUIC_NO_EXPORT MasqueCompressionEngine { bool* version_present); QuicSession* masque_session_; // Unowned. - QuicUnorderedMap<QuicDatagramFlowId, MasqueCompressionContext> contexts_; + QuicHashMap<QuicDatagramFlowId, MasqueCompressionContext> contexts_; QuicDatagramFlowId next_flow_id_; }; diff --git a/chromium/net/third_party/quiche/src/quic/masque/masque_dispatcher.h b/chromium/net/third_party/quiche/src/quic/masque/masque_dispatcher.h index 4817b7bd391..6901a8645b7 100644 --- a/chromium/net/third_party/quiche/src/quic/masque/masque_dispatcher.h +++ b/chromium/net/third_party/quiche/src/quic/masque/masque_dispatcher.h @@ -52,7 +52,7 @@ class QUIC_NO_EXPORT MasqueDispatcher : public QuicSimpleDispatcher, MasqueServerBackend* masque_server_backend_; // Unowned. // Mapping from client connection IDs to server sessions, allows routing // incoming packets to the right MASQUE connection. - QuicUnorderedMap<QuicConnectionId, MasqueServerSession*, QuicConnectionIdHash> + QuicHashMap<QuicConnectionId, MasqueServerSession*, QuicConnectionIdHash> client_connection_id_registrations_; }; diff --git a/chromium/net/third_party/quiche/src/quic/masque/masque_server_backend.h b/chromium/net/third_party/quiche/src/quic/masque/masque_server_backend.h index 78dfbf4105a..481d90dde48 100644 --- a/chromium/net/third_party/quiche/src/quic/masque/masque_server_backend.h +++ b/chromium/net/third_party/quiche/src/quic/masque/masque_server_backend.h @@ -57,9 +57,9 @@ class QUIC_NO_EXPORT MasqueServerBackend : public QuicMemoryCacheBackend { QuicSimpleServerBackend::RequestHandler* request_handler); std::string server_authority_; - QuicUnorderedMap<std::string, std::unique_ptr<QuicBackendResponse>> + QuicHashMap<std::string, std::unique_ptr<QuicBackendResponse>> active_response_map_; - QuicUnorderedMap<QuicConnectionId, BackendClient*, QuicConnectionIdHash> + QuicHashMap<QuicConnectionId, BackendClient*, QuicConnectionIdHash> backend_clients_; }; 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 44c7ab10589..d0c63a53b50 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 @@ -17,10 +17,18 @@ using QuicDefaultHasher = QuicDefaultHasherImpl<Key>; template <typename Key, typename Value, typename Hash = QuicDefaultHasher<Key>> using QuicUnorderedMap = QuicUnorderedMapImpl<Key, Value, Hash>; +// 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>; + // A map which offers insertion-ordered iteration. template <typename Key, typename Value, typename Hash = QuicDefaultHasher<Key>> using QuicLinkedHashMap = QuicLinkedHashMapImpl<Key, Value, Hash>; diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_macros.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_macros.h index 9dee2e987c8..7edeb6aa953 100644 --- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_macros.h +++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_macros.h @@ -9,5 +9,6 @@ #define QUIC_MUST_USE_RESULT QUIC_MUST_USE_RESULT_IMPL #define QUIC_UNUSED QUIC_UNUSED_IMPL +#define QUIC_CONST_INIT QUIC_CONST_INIT_IMPL #endif // QUICHE_QUIC_PLATFORM_API_QUIC_MACROS_H_ diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_socket_address.cc b/chromium/net/third_party/quiche/src/quic/platform/api/quic_socket_address.cc index 72debb950f7..ee3c3beb57e 100644 --- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_socket_address.cc +++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_socket_address.cc @@ -4,6 +4,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" +#include <cstring> #include <limits> #include <string> diff --git a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/mock_icmp_reachable.h b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/mock_icmp_reachable.h index 092845eba7d..b717a604a7f 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/mock_icmp_reachable.h +++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/mock_icmp_reachable.h @@ -12,7 +12,7 @@ namespace quic { class MockIcmpReachable : public IcmpReachableInterface { public: - MOCK_METHOD0(Init, bool()); + MOCK_METHOD(bool, Init, (), (override)); }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/mock_packet_exchanger_stats_interface.h b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/mock_packet_exchanger_stats_interface.h index a265603c18f..f1f8e87cad3 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/bonnet/mock_packet_exchanger_stats_interface.h +++ b/chromium/net/third_party/quiche/src/quic/qbone/bonnet/mock_packet_exchanger_stats_interface.h @@ -13,13 +13,13 @@ namespace quic { class MockPacketExchangerStatsInterface : public TunDevicePacketExchanger::StatsInterface { public: - MOCK_METHOD1(OnPacketRead, void(size_t)); - MOCK_METHOD1(OnPacketWritten, void(size_t)); - MOCK_METHOD1(OnReadError, void(std::string*)); - MOCK_METHOD1(OnWriteError, void(std::string*)); + MOCK_METHOD(void, OnPacketRead, (size_t), (override)); + MOCK_METHOD(void, OnPacketWritten, (size_t), (override)); + MOCK_METHOD(void, OnReadError, (std::string*), (override)); + MOCK_METHOD(void, OnWriteError, (std::string*), (override)); - MOCK_CONST_METHOD0(PacketsRead, int64_t()); - MOCK_CONST_METHOD0(PacketsWritten, int64_t()); + MOCK_METHOD(int64_t, PacketsRead, (), (const, override)); + MOCK_METHOD(int64_t, PacketsWritten, (), (const, override)); }; } // namespace quic 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 37e852af515..14879de24cc 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 @@ -12,13 +12,13 @@ namespace quic { class MockTunDevice : public TunDeviceInterface { public: - MOCK_METHOD0(Init, bool()); + MOCK_METHOD(bool, Init, (), (override)); - MOCK_METHOD0(Up, bool()); + MOCK_METHOD(bool, Up, (), (override)); - MOCK_METHOD0(Down, bool()); + MOCK_METHOD(bool, Down, (), (override)); - MOCK_CONST_METHOD0(GetFileDescriptor, int()); + MOCK_METHOD(int, GetFileDescriptor, (), (const, override)); }; } // namespace quic 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 30ef5edb1cd..f61407d8057 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 @@ -23,8 +23,8 @@ using ::testing::StrictMock; class MockVisitor : public QbonePacketExchanger::Visitor { public: - MOCK_METHOD1(OnReadError, void(const std::string&)); - MOCK_METHOD1(OnWriteError, void(const std::string&)); + MOCK_METHOD(void, OnReadError, (const std::string&), (override)); + MOCK_METHOD(void, OnWriteError, (const std::string&), (override)); }; class TunDevicePacketExchangerTest : public QuicTest { diff --git a/chromium/net/third_party/quiche/src/quic/qbone/mock_qbone_client.h b/chromium/net/third_party/quiche/src/quic/qbone/mock_qbone_client.h index 0a089ea955c..3170b7ed4b1 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/mock_qbone_client.h +++ b/chromium/net/third_party/quiche/src/quic/qbone/mock_qbone_client.h @@ -13,8 +13,10 @@ namespace quic { class MockQboneClient : public QboneClientInterface { public: - MOCK_METHOD1(ProcessPacketFromNetwork, - void(quiche::QuicheStringPiece packet)); + MOCK_METHOD(void, + ProcessPacketFromNetwork, + (quiche::QuicheStringPiece packet), + (override)); }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/qbone/mock_qbone_server_session.h b/chromium/net/third_party/quiche/src/quic/qbone/mock_qbone_server_session.h index 874ad216ca9..0781e7f6b4d 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/mock_qbone_server_session.h +++ b/chromium/net/third_party/quiche/src/quic/qbone/mock_qbone_server_session.h @@ -25,10 +25,16 @@ class MockQboneServerSession : public QboneServerSession { /*client_ip_subnet_length=*/0, /*handler=*/nullptr) {} - MOCK_METHOD1(SendClientRequest, bool(const QboneClientRequest&)); - - MOCK_METHOD1(ProcessPacketFromNetwork, void(quiche::QuicheStringPiece)); - MOCK_METHOD1(ProcessPacketFromPeer, void(quiche::QuicheStringPiece)); + MOCK_METHOD(bool, SendClientRequest, (const QboneClientRequest&), (override)); + + MOCK_METHOD(void, + ProcessPacketFromNetwork, + (quiche::QuicheStringPiece), + (override)); + MOCK_METHOD(void, + ProcessPacketFromPeer, + (quiche::QuicheStringPiece), + (override)); }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/qbone/platform/mock_kernel.h b/chromium/net/third_party/quiche/src/quic/qbone/platform/mock_kernel.h index c01aad1708b..e30bfa1bad9 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/platform/mock_kernel.h +++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/mock_kernel.h @@ -14,31 +14,38 @@ class MockKernel : public KernelInterface { public: MockKernel() {} - MOCK_METHOD3(bind, - int(int fd, const struct sockaddr* addr, socklen_t addr_len)); - MOCK_METHOD1(close, int(int fd)); - MOCK_METHOD3(ioctl, int(int fd, int request, void* argp)); - MOCK_METHOD2(open, int(const char* pathname, int flags)); - MOCK_METHOD3(read, ssize_t(int fd, void* buf, size_t count)); - MOCK_METHOD6(recvfrom, - ssize_t(int sockfd, - void* buf, - size_t len, - int flags, - struct sockaddr* src_addr, - socklen_t* addrlen)); - MOCK_METHOD3(sendmsg, - ssize_t(int sockfd, const struct msghdr* msg, int flags)); - MOCK_METHOD6(sendto, - ssize_t(int sockfd, - const void* buf, - size_t len, - int flags, - const struct sockaddr* dest_addr, - socklen_t addrlen)); - MOCK_METHOD3(socket, int(int domain, int type, int protocol)); - MOCK_METHOD5(setsockopt, int(int, int, int, const void*, socklen_t)); - MOCK_METHOD3(write, ssize_t(int fd, const void* buf, size_t count)); + MOCK_METHOD(int, + bind, + (int fd, const struct sockaddr*, socklen_t addr_len), + (override)); + MOCK_METHOD(int, close, (int fd), (override)); + MOCK_METHOD(int, ioctl, (int fd, int request, void*), (override)); + MOCK_METHOD(int, open, (const char*, int flags), (override)); + MOCK_METHOD(ssize_t, read, (int fd, void*, size_t count), (override)); + MOCK_METHOD( + ssize_t, + recvfrom, + (int sockfd, void*, size_t len, int flags, struct sockaddr*, socklen_t*), + (override)); + MOCK_METHOD(ssize_t, + sendmsg, + (int sockfd, const struct msghdr*, int flags), + (override)); + MOCK_METHOD(ssize_t, + sendto, + (int sockfd, + const void*, + size_t len, + int flags, + const struct sockaddr*, + socklen_t addrlen), + (override)); + MOCK_METHOD(int, socket, (int domain, int type, int protocol), (override)); + MOCK_METHOD(int, + setsockopt, + (int, int, int, const void*, socklen_t), + (override)); + MOCK_METHOD(ssize_t, write, (int fd, const void*, size_t count), (override)); }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/qbone/platform/mock_netlink.h b/chromium/net/third_party/quiche/src/quic/qbone/platform/mock_netlink.h index e9f5d680980..ea5d62e9f61 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/platform/mock_netlink.h +++ b/chromium/net/third_party/quiche/src/quic/qbone/platform/mock_netlink.h @@ -12,33 +12,38 @@ namespace quic { class MockNetlink : public NetlinkInterface { public: - MOCK_METHOD2(GetLinkInfo, bool(const std::string&, LinkInfo*)); + MOCK_METHOD(bool, GetLinkInfo, (const std::string&, LinkInfo*), (override)); - MOCK_METHOD4(GetAddresses, - bool(int, uint8_t, std::vector<AddressInfo>*, int*)); + MOCK_METHOD(bool, + GetAddresses, + (int, uint8_t, std::vector<AddressInfo>*, int*), + (override)); - MOCK_METHOD7(ChangeLocalAddress, - bool(uint32_t, - Verb, - const QuicIpAddress&, - uint8_t, - uint8_t, - uint8_t, - const std::vector<struct rtattr*>&)); + MOCK_METHOD(bool, + ChangeLocalAddress, + (uint32_t, + Verb, + const QuicIpAddress&, + uint8_t, + uint8_t, + uint8_t, + const std::vector<struct rtattr*>&), + (override)); - MOCK_METHOD1(GetRouteInfo, bool(std::vector<RoutingRule>*)); + MOCK_METHOD(bool, GetRouteInfo, (std::vector<RoutingRule>*), (override)); - MOCK_METHOD6( - ChangeRoute, - bool(Verb, uint32_t, const IpRange&, uint8_t, QuicIpAddress, int32_t)); + MOCK_METHOD(bool, + ChangeRoute, + (Verb, uint32_t, const IpRange&, uint8_t, QuicIpAddress, int32_t), + (override)); - MOCK_METHOD1(GetRuleInfo, bool(std::vector<IpRule>*)); + MOCK_METHOD(bool, GetRuleInfo, (std::vector<IpRule>*), (override)); - MOCK_METHOD3(ChangeRule, bool(Verb, uint32_t, IpRange)); + MOCK_METHOD(bool, ChangeRule, (Verb, uint32_t, IpRange), (override)); - MOCK_METHOD2(Send, bool(struct iovec*, size_t)); + MOCK_METHOD(bool, Send, (struct iovec*, size_t), (override)); - MOCK_METHOD2(Recv, bool(uint32_t, NetlinkParserInterface*)); + MOCK_METHOD(bool, Recv, (uint32_t, NetlinkParserInterface*), (override)); }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_session.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_session.cc index 13f8b5fc103..52ba763118f 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_session.cc +++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_session.cc @@ -30,7 +30,8 @@ QboneClientSession::~QboneClientSession() {} std::unique_ptr<QuicCryptoStream> QboneClientSession::CreateCryptoStream() { return std::make_unique<QuicCryptoClientStream>( - server_id_, this, nullptr, quic_crypto_client_config_, this); + server_id_, this, nullptr, quic_crypto_client_config_, this, + /*has_application_state = */ true); } void QboneClientSession::Initialize() { diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_test.cc index a41e6a94eba..cdb611c9209 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_test.cc +++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_test.cc @@ -21,6 +21,7 @@ #include "net/third_party/quiche/src/quic/qbone/qbone_packet_processor_test_tools.h" #include "net/third_party/quiche/src/quic/qbone/qbone_server_session.h" #include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_server_peer.h" #include "net/third_party/quiche/src/quic/test_tools/server_thread.h" #include "net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h" @@ -169,11 +170,6 @@ class QboneTestServer : public QuicServer { std::vector<std::string> data() { return writer_.data(); } - void WaitForDataSize(int n) { - while (data().size() != n) { - } - } - private: quic::QuicMemoryCacheBackend response_cache_; DataSavingQbonePacketWriter writer_; @@ -208,10 +204,19 @@ class QboneTestClient : public QboneClient { } } - void WaitForDataSize(int n) { - while (data().size() != n) { + // Returns true when the data size is reached or false on timeouts. + bool WaitForDataSize(int n, QuicTime::Delta timeout) { + const QuicClock* clock = + quic::test::QuicConnectionPeer::GetHelper(session()->connection()) + ->GetClock(); + const QuicTime deadline = clock->Now() + timeout; + while (data().size() < n) { + if (clock->Now() > deadline) { + return false; + } WaitForEvents(); } + return true; } std::vector<std::string> data() { return qbone_writer_.data(); } @@ -247,24 +252,30 @@ TEST_P(QboneClientTest, SendDataFromClient) { client.SendData(TestPacketIn("hello")); client.SendData(TestPacketIn("world")); client.WaitForWriteToFlush(); - server->WaitForDataSize(2); - EXPECT_THAT(server->data()[0], testing::Eq(TestPacketOut("hello"))); - EXPECT_THAT(server->data()[1], testing::Eq(TestPacketOut("world"))); - auto server_session = - static_cast<QboneServerSession*>(QuicServerPeer::GetDispatcher(server) - ->session_map() - .begin() - ->second.get()); + + // Wait until the server has received at least two packets, timeout after 5s. + ASSERT_TRUE( + server_thread.WaitUntil([&] { return server->data().size() >= 2; }, + QuicTime::Delta::FromSeconds(5))); + std::string long_data( QboneConstants::kMaxQbonePacketBytes - sizeof(ip6_hdr) - 1, 'A'); + // Pretend the server gets data. - server_thread.Schedule([&server_session, &long_data]() { + server_thread.Schedule([&server, &long_data]() { + EXPECT_THAT(server->data()[0], testing::Eq(TestPacketOut("hello"))); + EXPECT_THAT(server->data()[1], testing::Eq(TestPacketOut("world"))); + auto server_session = + static_cast<QboneServerSession*>(QuicServerPeer::GetDispatcher(server) + ->session_map() + .begin() + ->second.get()); server_session->ProcessPacketFromNetwork( TestPacketIn("Somethingsomething")); server_session->ProcessPacketFromNetwork(TestPacketIn(long_data)); server_session->ProcessPacketFromNetwork(TestPacketIn(long_data)); }); - client.WaitForDataSize(3); + ASSERT_TRUE(client.WaitForDataSize(3, QuicTime::Delta::FromSeconds(5))); EXPECT_THAT(client.data()[0], testing::Eq(TestPacketOut("Somethingsomething"))); EXPECT_THAT(client.data()[1], testing::Eq(TestPacketOut(long_data))); diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_exchanger_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_exchanger_test.cc index 1f38910d4cc..9ec9e209a60 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_exchanger_test.cc +++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_exchanger_test.cc @@ -19,8 +19,8 @@ const size_t kMaxPendingPackets = 2; class MockVisitor : public QbonePacketExchanger::Visitor { public: - MOCK_METHOD1(OnReadError, void(const std::string&)); - MOCK_METHOD1(OnWriteError, void(const std::string&)); + MOCK_METHOD(void, OnReadError, (const std::string&), (override)); + MOCK_METHOD(void, OnWriteError, (const std::string&), (override)); }; class FakeQbonePacketExchanger : public QbonePacketExchanger { diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor_test.cc index 77fb5d53231..2820a7a1f70 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor_test.cc +++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor_test.cc @@ -125,12 +125,14 @@ MATCHER_P(IsIcmpMessage, class MockPacketFilter : public QbonePacketProcessor::Filter { public: - MOCK_METHOD5(FilterPacket, - ProcessingResult(Direction, - quiche::QuicheStringPiece, - quiche::QuicheStringPiece, - icmp6_hdr*, - OutputInterface*)); + MOCK_METHOD(ProcessingResult, + FilterPacket, + (Direction, + quiche::QuicheStringPiece, + quiche::QuicheStringPiece, + icmp6_hdr*, + OutputInterface*), + (override)); }; class QbonePacketProcessorTest : public QuicTest { diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor_test_tools.h b/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor_test_tools.h index 809b5422f78..72030506399 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor_test_tools.h +++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_packet_processor_test_tools.h @@ -15,20 +15,40 @@ class MockPacketProcessorOutput : public QbonePacketProcessor::OutputInterface { public: MockPacketProcessorOutput() {} - MOCK_METHOD1(SendPacketToClient, void(quiche::QuicheStringPiece)); - MOCK_METHOD1(SendPacketToNetwork, void(quiche::QuicheStringPiece)); + MOCK_METHOD(void, + SendPacketToClient, + (quiche::QuicheStringPiece), + (override)); + MOCK_METHOD(void, + SendPacketToNetwork, + (quiche::QuicheStringPiece), + (override)); }; class MockPacketProcessorStats : public QbonePacketProcessor::StatsInterface { public: MockPacketProcessorStats() {} - MOCK_METHOD1(OnPacketForwarded, void(QbonePacketProcessor::Direction)); - MOCK_METHOD1(OnPacketDroppedSilently, void(QbonePacketProcessor::Direction)); - MOCK_METHOD1(OnPacketDroppedWithIcmp, void(QbonePacketProcessor::Direction)); - MOCK_METHOD1(OnPacketDroppedWithTcpReset, - void(QbonePacketProcessor::Direction)); - MOCK_METHOD1(OnPacketDeferred, void(QbonePacketProcessor::Direction)); + MOCK_METHOD(void, + OnPacketForwarded, + (QbonePacketProcessor::Direction), + (override)); + MOCK_METHOD(void, + OnPacketDroppedSilently, + (QbonePacketProcessor::Direction), + (override)); + MOCK_METHOD(void, + OnPacketDroppedWithIcmp, + (QbonePacketProcessor::Direction), + (override)); + MOCK_METHOD(void, + OnPacketDroppedWithTcpReset, + (QbonePacketProcessor::Direction), + (override)); + MOCK_METHOD(void, + OnPacketDeferred, + (QbonePacketProcessor::Direction), + (override)); }; std::string PrependIPv6HeaderForTest(const std::string& body, int hops); diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_base.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_base.cc index 68f659c3a6a..81aeda80872 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_base.cc +++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_base.cc @@ -18,6 +18,12 @@ #include "net/third_party/quiche/src/quic/qbone/qbone_constants.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" +ABSL_FLAG( + bool, + qbone_close_ephemeral_frames, + true, + "If true, we'll call CloseStream even when we receive ephemeral frames."); + namespace quic { #define ENDPOINT \ @@ -40,7 +46,7 @@ QboneSessionBase::QboneSessionBase( 1; this->config()->SetMaxBidirectionalStreamsToSend(max_streams); if (VersionHasIetfQuicFrames(transport_version())) { - ConfigureMaxDynamicStreamsToSend(max_streams); + this->config()->SetMaxUnidirectionalStreamsToSend(max_streams); } } @@ -84,6 +90,11 @@ void QboneSessionBase::OnStreamFrame(const QuicStreamFrame& frame) { ProcessPacketFromPeer( quiche::QuicheStringPiece(frame.data_buffer, frame.data_length)); flow_controller()->AddBytesConsumed(frame.data_length); + // TODO(b/147817422): Add a counter for how many streams were actually + // closed here. + if (GetQuicFlag(FLAGS_qbone_close_ephemeral_frames)) { + CloseStream(frame.stream_id); + } return; } QuicSession::OnStreamFrame(frame); diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_base.h b/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_base.h index 241a3c9c6e2..59ca2c4d3f3 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_base.h +++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_base.h @@ -110,8 +110,6 @@ class QUIC_EXPORT_PRIVATE QboneSessionBase : public QuicSession { // Number of times the connection has failed to send packets as MESSAGE frame // and used streams as a fallback. uint64_t num_fallback_to_stream_ = 0; - - QuicUnorderedSet<QuicStreamId> reliable_streams_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_session_test.cc index 7ea1c519dd3..243a5c535d5 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 @@ -17,6 +17,7 @@ #include "net/third_party/quiche/src/quic/qbone/qbone_control_placeholder.pb.h" #include "net/third_party/quiche/src/quic/qbone/qbone_packet_processor_test_tools.h" #include "net/third_party/quiche/src/quic/qbone/qbone_server_session.h" +#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" #include "net/third_party/quiche/src/quic/test_tools/mock_clock.h" #include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_session_peer.h" @@ -59,60 +60,80 @@ ParsedQuicVersionVector GetTestParams() { return test_versions; } -// Used by QuicCryptoServerConfig to provide server credentials, returning a -// canned response equal to |success|. -class FakeProofSource : public ProofSource { +// Used by QuicCryptoServerConfig to provide server credentials, passes +// everything through to ProofSourceForTesting if success is true, +// and fails otherwise. +class IndirectionProofSource : public ProofSource { public: - explicit FakeProofSource(bool success) : success_(success) {} + explicit IndirectionProofSource(bool success) { + if (success) { + proof_source_ = crypto_test_utils::ProofSourceForTesting(); + } + } // ProofSource override. void GetProof(const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, const std::string& hostname, const std::string& server_config, QuicTransportVersion transport_version, quiche::QuicheStringPiece chlo_hash, std::unique_ptr<Callback> callback) override { - QuicReferenceCountedPointer<ProofSource::Chain> chain = - GetCertChain(server_address, hostname); - QuicCryptoProof proof; - if (success_) { - proof.signature = "Signature"; - proof.leaf_cert_scts = "Time"; + if (!proof_source_) { + QuicReferenceCountedPointer<ProofSource::Chain> chain = + GetCertChain(server_address, client_address, hostname); + QuicCryptoProof proof; + callback->Run(/*ok=*/false, chain, proof, /*details=*/nullptr); + return; } - callback->Run(success_, chain, proof, nullptr /* details */); + proof_source_->GetProof(server_address, client_address, hostname, + server_config, transport_version, chlo_hash, + std::move(callback)); } QuicReferenceCountedPointer<Chain> GetCertChain( const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, const std::string& hostname) override { - if (!success_) { + if (!proof_source_) { return QuicReferenceCountedPointer<Chain>(); } - std::vector<std::string> certs; - certs.push_back("Required to establish handshake"); - return QuicReferenceCountedPointer<ProofSource::Chain>( - new ProofSource::Chain(certs)); + return proof_source_->GetCertChain(server_address, client_address, + hostname); } void ComputeTlsSignature( const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, const std::string& hostname, uint16_t signature_algorithm, quiche::QuicheStringPiece in, std::unique_ptr<SignatureCallback> callback) override { - callback->Run(true, "Signature", /*details=*/nullptr); + if (!proof_source_) { + callback->Run(/*ok=*/true, "Signature", /*details=*/nullptr); + return; + } + proof_source_->ComputeTlsSignature(server_address, client_address, hostname, + signature_algorithm, in, + std::move(callback)); } + TicketCrypter* GetTicketCrypter() override { return nullptr; } + private: - // Whether or not obtaining proof source succeeds. - bool success_; + std::unique_ptr<ProofSource> proof_source_; }; -// Used by QuicCryptoClientConfig to verify server credentials, returning a -// canned response of QUIC_SUCCESS if |success| is true. -class FakeProofVerifier : public ProofVerifier { +// Used by QuicCryptoClientConfig to verify server credentials, passes +// everything through to ProofVerifierForTesting is success is true, +// otherwise returns a canned response of QUIC_FAILURE. +class IndirectionProofVerifier : public ProofVerifier { public: - explicit FakeProofVerifier(bool success) : success_(success) {} + explicit IndirectionProofVerifier(bool success) { + if (success) { + proof_verifier_ = crypto_test_utils::ProofVerifierForTesting(); + } + } // ProofVerifier override QuicAsyncStatus VerifyProof( @@ -128,11 +149,18 @@ class FakeProofVerifier : public ProofVerifier { std::string* error_details, std::unique_ptr<ProofVerifyDetails>* verify_details, std::unique_ptr<ProofVerifierCallback> callback) override { - return success_ ? QUIC_SUCCESS : QUIC_FAILURE; + if (!proof_verifier_) { + return QUIC_FAILURE; + } + return proof_verifier_->VerifyProof( + hostname, port, server_config, transport_version, chlo_hash, certs, + cert_sct, signature, context, error_details, verify_details, + std::move(callback)); } QuicAsyncStatus VerifyCertChain( const std::string& hostname, + const uint16_t port, const std::vector<std::string>& certs, const std::string& ocsp_response, const std::string& cert_sct, @@ -140,16 +168,23 @@ class FakeProofVerifier : public ProofVerifier { std::string* error_details, std::unique_ptr<ProofVerifyDetails>* details, std::unique_ptr<ProofVerifierCallback> callback) override { - return success_ ? QUIC_SUCCESS : QUIC_FAILURE; + if (!proof_verifier_) { + return QUIC_FAILURE; + } + return proof_verifier_->VerifyCertChain( + hostname, port, certs, ocsp_response, cert_sct, context, error_details, + details, std::move(callback)); } std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override { - return nullptr; + if (!proof_verifier_) { + return nullptr; + } + return proof_verifier_->CreateDefaultContext(); } private: - // Whether or not proof verification succeeds. - bool success_; + std::unique_ptr<ProofVerifier> proof_verifier_; }; class DataSavingQbonePacketWriter : public QbonePacketWriter { @@ -289,7 +324,7 @@ class QboneSessionTest : public QuicTestWithParam<ParsedQuicVersion> { client_connection_->SetSelfAddress(client_address); QuicConfig config; client_crypto_config_ = std::make_unique<QuicCryptoClientConfig>( - std::make_unique<FakeProofVerifier>(client_handshake_success)); + std::make_unique<IndirectionProofVerifier>(client_handshake_success)); if (send_qbone_alpn) { client_crypto_config_->set_alpn("qbone"); } @@ -308,9 +343,8 @@ class QboneSessionTest : public QuicTestWithParam<ParsedQuicVersion> { server_connection_->SetSelfAddress(server_address); QuicConfig config; server_crypto_config_ = std::make_unique<QuicCryptoServerConfig>( - "TESTING", QuicRandom::GetInstance(), - std::unique_ptr<FakeProofSource>( - new FakeProofSource(server_handshake_success)), + QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), + std::make_unique<IndirectionProofSource>(server_handshake_success), KeyExchangeSource::Default()); QuicCryptoServerConfig::ConfigOptions options; QuicServerConfigProtobuf primary_config = diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_stream_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_stream_test.cc index 42840bebee0..10edaf6650d 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/qbone_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_stream_test.cc @@ -62,8 +62,10 @@ class MockQuicSession : public QboneSessionBase { QuicCryptoStream* GetMutableCryptoStream() override { return nullptr; } // Called by QuicStream when they want to close stream. - MOCK_METHOD3(SendRstStream, - void(QuicStreamId, QuicRstStreamErrorCode, QuicStreamOffset)); + MOCK_METHOD(void, + SendRstStream, + (QuicStreamId, QuicRstStreamErrorCode, QuicStreamOffset), + (override)); // Sets whether data is written to buffer, or else if this is write blocked. void set_writable(bool writable) { writable_ = writable; } @@ -87,8 +89,14 @@ class MockQuicSession : public QboneSessionBase { return nullptr; } - MOCK_METHOD1(ProcessPacketFromPeer, void(quiche::QuicheStringPiece)); - MOCK_METHOD1(ProcessPacketFromNetwork, void(quiche::QuicheStringPiece)); + MOCK_METHOD(void, + ProcessPacketFromPeer, + (quiche::QuicheStringPiece), + (override)); + MOCK_METHOD(void, + ProcessPacketFromNetwork, + (quiche::QuicheStringPiece), + (override)); private: // Whether data is written to write_buffer_. diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.cc index 1a028458ecd..14645f83da0 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.cc +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.cc @@ -11,13 +11,14 @@ namespace quic { void DummyProofSource::GetProof(const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, const std::string& hostname, const std::string& /*server_config*/, QuicTransportVersion /*transport_version*/, quiche::QuicheStringPiece /*chlo_hash*/, std::unique_ptr<Callback> callback) { QuicReferenceCountedPointer<ProofSource::Chain> chain = - GetCertChain(server_address, hostname); + GetCertChain(server_address, client_address, hostname); QuicCryptoProof proof; proof.signature = "Dummy signature"; proof.leaf_cert_scts = "Dummy timestamp"; @@ -26,6 +27,7 @@ void DummyProofSource::GetProof(const QuicSocketAddress& server_address, QuicReferenceCountedPointer<DummyProofSource::Chain> DummyProofSource::GetCertChain(const QuicSocketAddress& /*server_address*/, + const QuicSocketAddress& /*client_address*/, const std::string& /*hostname*/) { std::vector<std::string> certs; certs.push_back(kDummyCertName); @@ -35,6 +37,7 @@ DummyProofSource::GetCertChain(const QuicSocketAddress& /*server_address*/, void DummyProofSource::ComputeTlsSignature( const QuicSocketAddress& /*server_address*/, + const QuicSocketAddress& /*client_address*/, const std::string& /*hostname*/, uint16_t /*signature_algorithm*/, quiche::QuicheStringPiece /*in*/, @@ -60,6 +63,7 @@ QuicAsyncStatus InsecureProofVerifier::VerifyProof( QuicAsyncStatus InsecureProofVerifier::VerifyCertChain( const std::string& /*hostname*/, + const uint16_t /*port*/, const std::vector<std::string>& /*certs*/, const std::string& /*ocsp_response*/, const std::string& /*cert_sct*/, diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h index b1e2e186154..806786f2f3d 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h @@ -44,6 +44,7 @@ class DummyProofSource : public ProofSource { // ProofSource overrides. void GetProof(const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, const std::string& hostname, const std::string& server_config, QuicTransportVersion transport_version, @@ -52,14 +53,18 @@ class DummyProofSource : public ProofSource { QuicReferenceCountedPointer<Chain> GetCertChain( const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, const std::string& hostname) override; void ComputeTlsSignature( const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, const std::string& hostname, uint16_t signature_algorithm, quiche::QuicheStringPiece in, std::unique_ptr<SignatureCallback> callback) override; + + TicketCrypter* GetTicketCrypter() override { return nullptr; } }; // Used by QuicCryptoClientConfig to ignore the peer's credentials @@ -87,6 +92,7 @@ class InsecureProofVerifier : public ProofVerifier { QuicAsyncStatus VerifyCertChain( const std::string& hostname, + const uint16_t port, const std::vector<std::string>& certs, const std::string& ocsp_response, const std::string& cert_sct, diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.cc index ff98761b4c7..280d936b25a 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.cc +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.cc @@ -148,7 +148,6 @@ QuicConfig CreateQuicConfig(const QuartcSessionConfig& quartc_session_config) { } if (quartc_session_config.idle_network_timeout > QuicTime::Delta::Zero()) { quic_config.SetIdleNetworkTimeout( - quartc_session_config.idle_network_timeout, quartc_session_config.idle_network_timeout); } diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer.h index b90026b5495..1e6c2e5dbdf 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer.h +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer.h @@ -89,7 +89,7 @@ class QuartcSendChannel { // to demux sent, acked, and lost messages, the multiplexer assigns a globally // unique id to each message. This map is used to restore the original caller // datagram id before issuing callbacks. - QuicUnorderedMap<int64_t, int64_t> multiplexer_to_user_datagram_ids_; + QuicHashMap<int64_t, int64_t> multiplexer_to_user_datagram_ids_; }; // A single, multiplexed receive channel within a Quartc session. A receive @@ -178,11 +178,11 @@ class QuartcMultiplexer : public QuartcEndpoint::Delegate, QuartcSession* session_ = nullptr; std::vector<std::unique_ptr<QuartcSendChannel>> send_channels_; - QuicUnorderedMap<uint64_t, QuartcReceiveChannel*> receive_channels_; + QuicHashMap<uint64_t, QuartcReceiveChannel*> receive_channels_; QuartcReceiveChannel* default_receive_channel_ = nullptr; int64_t next_datagram_id_ = 1; - QuicUnorderedMap<int64_t, QuartcSendChannel*> send_channels_by_datagram_id_; + QuicHashMap<int64_t, QuartcSendChannel*> send_channels_by_datagram_id_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer_test.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer_test.cc index fcdbe994f24..024b67d8a94 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer_test.cc +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer_test.cc @@ -202,9 +202,7 @@ class QuartcMultiplexerTest : public QuicTest { quic::QuartcSessionConfig())) { // TODO(b/150224094): Re-enable TLS handshake. // TODO(b/150236522): Parametrize by QUIC version. - SetQuicReloadableFlag(quic_enable_version_draft_27, false); - SetQuicReloadableFlag(quic_enable_version_draft_25_v3, false); - SetQuicReloadableFlag(quic_enable_version_t050, false); + quic::test::DisableQuicVersionsWithTls(); } void Connect() { diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.cc index a93f4107ddb..0a7fca933bf 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.cc +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.cc @@ -198,11 +198,11 @@ void QuartcSession::OnOneRttKeysAvailable() { } void QuartcSession::CancelStream(QuicStreamId stream_id) { - ResetStream(stream_id, QuicRstStreamErrorCode::QUIC_STREAM_CANCELLED); + ResetQuartcStream(stream_id, QuicRstStreamErrorCode::QUIC_STREAM_CANCELLED); } -void QuartcSession::ResetStream(QuicStreamId stream_id, - QuicRstStreamErrorCode error) { +void QuartcSession::ResetQuartcStream(QuicStreamId stream_id, + QuicRstStreamErrorCode error) { if (!IsOpenStream(stream_id)) { return; } @@ -418,7 +418,7 @@ void QuartcClientSession::StartCryptoHandshake() { crypto_stream_ = std::make_unique<QuicCryptoClientStream>( server_id, this, client_crypto_config_->proof_verifier()->CreateDefaultContext(), - client_crypto_config_.get(), this); + client_crypto_config_.get(), this, /*has_application_state = */ true); Initialize(); crypto_stream_->CryptoConnect(); } diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.h index db988a06654..66ddfc3617f 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.h +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.h @@ -204,7 +204,7 @@ class QuartcSession : public QuicSession, // returns an unowned pointer to the stream for convenience. QuartcStream* ActivateDataStream(std::unique_ptr<QuartcStream> stream); - void ResetStream(QuicStreamId stream_id, QuicRstStreamErrorCode error); + void ResetQuartcStream(QuicStreamId stream_id, QuicRstStreamErrorCode error); const QuicClock* clock() { return clock_; } @@ -244,7 +244,7 @@ class QuartcSession : public QuicSession, // Maps message ids to datagram ids, so we could translate message ACKs // received from QUIC to datagram ACKs that are propagated up the stack. - QuicUnorderedMap<QuicMessageId, int64_t> message_to_datagram_id_; + QuicHashMap<QuicMessageId, int64_t> message_to_datagram_id_; }; class QuartcClientSession : public QuartcSession, diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session_test.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_session_test.cc index 47312059721..93172e7c55d 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session_test.cc +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_session_test.cc @@ -56,9 +56,7 @@ class QuartcSessionTest : public QuicTest { void Init(bool create_client_endpoint = true) { // TODO(b/150224094): Re-enable TLS handshake. // TODO(b/150236522): Parametrize by QUIC version. - SetQuicReloadableFlag(quic_enable_version_draft_27, false); - SetQuicReloadableFlag(quic_enable_version_draft_25_v3, false); - SetQuicReloadableFlag(quic_enable_version_t050, false); + quic::test::DisableQuicVersionsWithTls(); client_transport_ = std::make_unique<simulator::SimulatedQuartcPacketTransport>( diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.cc index 9edf370120f..01494c5ddf5 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.cc @@ -56,7 +56,7 @@ void QuartcStream::OnClose() { delegate_->OnClose(this); } -void QuartcStream::OnStreamDataConsumed(size_t bytes_consumed) { +void QuartcStream::OnStreamDataConsumed(QuicByteCount bytes_consumed) { QuicStream::OnStreamDataConsumed(bytes_consumed); if (delegate_) { diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.h index 40e8328efea..7f3c28d005c 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.h +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.h @@ -34,7 +34,7 @@ class QuartcStream : public QuicStream { void OnClose() override; - void OnStreamDataConsumed(size_t bytes_consumed) override; + void OnStreamDataConsumed(QuicByteCount bytes_consumed) override; void OnDataBuffered( QuicStreamOffset offset, diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream_test.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream_test.cc index 7a8b22d501b..b387e7f9723 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream_test.cc @@ -398,7 +398,12 @@ TEST_P(QuartcStreamTest, StopReading) { TEST_P(QuartcStreamTest, CloseStream) { CreateReliableQuicStream(); EXPECT_FALSE(mock_stream_delegate_->closed()); - stream_->OnClose(); + if (GetQuicReloadableFlag(quic_break_session_stream_close_loop)) { + stream_->CloseWriteSide(); + stream_->CloseReadSide(); + } else { + stream_->OnClose(); + } EXPECT_TRUE(mock_stream_delegate_->closed()); } diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.cc b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.cc index a35d0841b55..3a8eba1306f 100644 --- a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.cc +++ b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.cc @@ -66,7 +66,7 @@ QuicTransportClientSession::QuicTransportClientSession( crypto_stream_ = std::make_unique<QuicCryptoClientStream>( QuicServerId(url.host(), url.EffectiveIntPort()), this, crypto_config->proof_verifier()->CreateDefaultContext(), crypto_config, - proof_handler); + proof_handler, /*has_application_state = */ true); } void QuicTransportClientSession::OnAlpnSelected( diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_integration_test.cc b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_integration_test.cc index 355f6cc7f8b..f1912e2f33c 100644 --- a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_integration_test.cc +++ b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_integration_test.cc @@ -23,6 +23,7 @@ #include "net/third_party/quiche/src/quic/quic_transport/quic_transport_server_session.h" #include "net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.h" #include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_session_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" #include "net/third_party/quiche/src/quic/test_tools/quic_transport_test_tools.h" #include "net/third_party/quiche/src/quic/test_tools/simulator/link.h" @@ -254,7 +255,8 @@ TEST_F(QuicTransportIntegrationTest, SendOutgoingStreams) { } ASSERT_TRUE(simulator_.RunUntilOrTimeout( [this]() { - return server_->session()->GetNumOpenIncomingStreams() == 10; + return QuicSessionPeer::GetNumOpenDynamicStreams(server_->session()) == + 10; }, kDefaultTimeout)); @@ -262,7 +264,10 @@ TEST_F(QuicTransportIntegrationTest, SendOutgoingStreams) { ASSERT_TRUE(stream->SendFin()); } ASSERT_TRUE(simulator_.RunUntilOrTimeout( - [this]() { return server_->session()->GetNumOpenIncomingStreams() == 0; }, + [this]() { + return QuicSessionPeer::GetNumOpenDynamicStreams(server_->session()) == + 0; + }, kDefaultTimeout)); } @@ -284,7 +289,10 @@ TEST_F(QuicTransportIntegrationTest, EchoBidirectionalStreams) { EXPECT_TRUE(stream->SendFin()); ASSERT_TRUE(simulator_.RunUntilOrTimeout( - [this]() { return server_->session()->GetNumOpenIncomingStreams() == 0; }, + [this]() { + return QuicSessionPeer::GetNumOpenDynamicStreams(server_->session()) == + 0; + }, kDefaultTimeout)); } diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_stream_test.cc b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_stream_test.cc index 6a91702fa58..0f0d770ecc5 100644 --- a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_stream_test.cc @@ -29,7 +29,7 @@ ParsedQuicVersionVector GetVersions() { class MockQuicTransportSessionInterface : public QuicTransportSessionInterface { public: - MOCK_CONST_METHOD0(IsSessionReady, bool()); + MOCK_METHOD(bool, IsSessionReady, (), (const, override)); }; class QuicTransportStreamTest : public QuicTest { 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 bfe4a5e349c..486444183c9 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 @@ -230,7 +230,7 @@ int HandshakeWithFakeServer(QuicConfig* server_quic_config, PacketSavingConnection* client_conn, QuicCryptoClientStream* client, std::string alpn) { - PacketSavingConnection* server_conn = new PacketSavingConnection( + auto* server_conn = new testing::NiceMock<PacketSavingConnection>( helper, alarm_factory, Perspective::IS_SERVER, ParsedVersionOfIndex(client_conn->supported_versions(), 0)); @@ -249,6 +249,8 @@ int HandshakeWithFakeServer(QuicConfig* server_quic_config, .Times(testing::AnyNumber()); EXPECT_CALL(*server_conn, OnCanWrite()).Times(testing::AnyNumber()); EXPECT_CALL(*client_conn, OnCanWrite()).Times(testing::AnyNumber()); + EXPECT_CALL(*server_conn, SendCryptoData(_, _, _)) + .Times(testing::AnyNumber()); EXPECT_CALL(server_session, SelectAlpn(_)) .WillRepeatedly( [alpn](const std::vector<quiche::QuicheStringPiece>& alpns) { @@ -260,7 +262,9 @@ int HandshakeWithFakeServer(QuicConfig* server_quic_config, CommunicateHandshakeMessages(client_conn, client, server_conn, server_session.GetMutableCryptoStream()); - CompareClientAndServerKeys(client, server_session.GetMutableCryptoStream()); + if (client_conn->connected() && server_conn->connected()) { + CompareClientAndServerKeys(client, server_session.GetMutableCryptoStream()); + } return client->num_sent_client_hellos(); } @@ -362,8 +366,9 @@ void CommunicateHandshakeMessages(PacketSavingConnection* client_conn, PacketSavingConnection* server_conn, QuicCryptoStream* server) { size_t client_i = 0, server_i = 0; - while (!client->one_rtt_keys_available() || - !server->one_rtt_keys_available()) { + while (client_conn->connected() && server_conn->connected() && + (!client->one_rtt_keys_available() || + !server->one_rtt_keys_available())) { ASSERT_GT(client_conn->encrypted_packets_.size(), client_i); QUIC_LOG(INFO) << "Processing " << client_conn->encrypted_packets_.size() - client_i @@ -419,6 +424,7 @@ std::string GetValueForTag(const CryptoHandshakeMessage& message, QuicTag tag) { uint64_t LeafCertHashForTesting() { QuicReferenceCountedPointer<ProofSource::Chain> chain; QuicSocketAddress server_address(QuicIpAddress::Any4(), 42); + QuicSocketAddress client_address(QuicIpAddress::Any4(), 43); QuicCryptoProof proof; std::unique_ptr<ProofSource> proof_source(ProofSourceForTesting()); @@ -443,7 +449,8 @@ uint64_t LeafCertHashForTesting() { // Note: relies on the callback being invoked synchronously bool ok = false; proof_source->GetProof( - server_address, "", "", AllSupportedTransportVersions().front(), "", + server_address, client_address, "", "", + AllSupportedTransportVersions().front(), "", std::unique_ptr<ProofSource::Callback>(new Callback(&ok, &chain))); if (!ok || chain->certs.empty()) { DCHECK(false) << "Proof generation failed"; @@ -743,6 +750,7 @@ void MovePackets(PacketSavingConnection* source_conn, if (!framer.ProcessPacket(*source_conn->encrypted_packets_[index])) { // The framer will be unable to decrypt forward-secure packets sent after // the handshake is complete. Don't treat them as handshake packets. + QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer()); break; } QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer()); @@ -755,6 +763,8 @@ void MovePackets(PacketSavingConnection* source_conn, // packets should ever be encrypted with the NullEncrypter, instead // they're encrypted with an obfuscation cipher based on QUIC version and // connection ID. + QUIC_LOG(INFO) << "Attempting to decrypt with NullDecrypter: " + "expect a decryption failure on the next log line."; ASSERT_FALSE(null_encryption_framer.ProcessPacket( *source_conn->encrypted_packets_[index])) << "No TLS packets should be encrypted with the NullEncrypter"; @@ -846,7 +856,7 @@ void GenerateFullCHLO( ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, transport_version), signed_config, compressed_certs_cache, out); crypto_config->ValidateClientHello( - inchoate_chlo, client_addr.host(), server_addr, transport_version, clock, + inchoate_chlo, client_addr, server_addr, transport_version, clock, signed_config, generator.GetValidateClientHelloCallback()); } 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 6e64cb822fd..a21b43ab109 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 @@ -178,7 +178,7 @@ TEST_F(CryptoTestUtilsTest, TestGenerateFullCHLO) { &compressed_certs_cache, ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, transport_version)); crypto_config.ValidateClientHello( - full_chlo, client_addr.host(), server_addr, transport_version, &clock, + full_chlo, client_addr, server_addr, transport_version, &clock, signed_config, shlo_verifier.GetValidateClientHelloCallback()); } diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/failing_proof_source.cc b/chromium/net/third_party/quiche/src/quic/test_tools/failing_proof_source.cc index 1f52476085a..98e18fcea13 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/failing_proof_source.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/failing_proof_source.cc @@ -10,6 +10,7 @@ namespace quic { namespace test { void FailingProofSource::GetProof(const QuicSocketAddress& /*server_address*/, + const QuicSocketAddress& /*client_address*/, const std::string& /*hostname*/, const std::string& /*server_config*/, QuicTransportVersion /*transport_version*/, @@ -20,12 +21,14 @@ void FailingProofSource::GetProof(const QuicSocketAddress& /*server_address*/, QuicReferenceCountedPointer<ProofSource::Chain> FailingProofSource::GetCertChain(const QuicSocketAddress& /*server_address*/, + const QuicSocketAddress& /*client_address*/, const std::string& /*hostname*/) { return QuicReferenceCountedPointer<Chain>(); } void FailingProofSource::ComputeTlsSignature( const QuicSocketAddress& /*server_address*/, + const QuicSocketAddress& /*client_address*/, const std::string& /*hostname*/, uint16_t /*signature_algorithm*/, quiche::QuicheStringPiece /*in*/, diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/failing_proof_source.h b/chromium/net/third_party/quiche/src/quic/test_tools/failing_proof_source.h index 36e23989117..6ea303d1df8 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/failing_proof_source.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/failing_proof_source.h @@ -14,6 +14,7 @@ namespace test { class FailingProofSource : public ProofSource { public: void GetProof(const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, const std::string& hostname, const std::string& server_config, QuicTransportVersion transport_version, @@ -22,14 +23,18 @@ class FailingProofSource : public ProofSource { QuicReferenceCountedPointer<Chain> GetCertChain( const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, const std::string& hostname) override; void ComputeTlsSignature( const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, const std::string& hostname, uint16_t signature_algorithm, quiche::QuicheStringPiece in, std::unique_ptr<SignatureCallback> callback) override; + + TicketCrypter* GetTicketCrypter() override { return nullptr; } }; } // namespace test diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source.cc b/chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source.cc index 0d85b5d450d..9619fad5523 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source.cc @@ -22,6 +22,7 @@ FakeProofSource::PendingOp::~PendingOp() = default; FakeProofSource::GetProofOp::GetProofOp( const QuicSocketAddress& server_addr, + const QuicSocketAddress& client_address, std::string hostname, std::string server_config, QuicTransportVersion transport_version, @@ -29,6 +30,7 @@ FakeProofSource::GetProofOp::GetProofOp( std::unique_ptr<ProofSource::Callback> callback, ProofSource* delegate) : server_address_(server_addr), + client_address_(client_address), hostname_(std::move(hostname)), server_config_(std::move(server_config)), transport_version_(transport_version), @@ -40,18 +42,21 @@ FakeProofSource::GetProofOp::~GetProofOp() = default; void FakeProofSource::GetProofOp::Run() { // Note: relies on the callback being invoked synchronously - delegate_->GetProof(server_address_, hostname_, server_config_, - transport_version_, chlo_hash_, std::move(callback_)); + delegate_->GetProof(server_address_, client_address_, hostname_, + server_config_, transport_version_, chlo_hash_, + std::move(callback_)); } FakeProofSource::ComputeSignatureOp::ComputeSignatureOp( const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, std::string hostname, uint16_t sig_alg, quiche::QuicheStringPiece in, std::unique_ptr<ProofSource::SignatureCallback> callback, ProofSource* delegate) : server_address_(server_address), + client_address_(client_address), hostname_(std::move(hostname)), sig_alg_(sig_alg), in_(in), @@ -61,8 +66,8 @@ FakeProofSource::ComputeSignatureOp::ComputeSignatureOp( FakeProofSource::ComputeSignatureOp::~ComputeSignatureOp() = default; void FakeProofSource::ComputeSignatureOp::Run() { - delegate_->ComputeTlsSignature(server_address_, hostname_, sig_alg_, in_, - std::move(callback_)); + delegate_->ComputeTlsSignature(server_address_, client_address_, hostname_, + sig_alg_, in_, std::move(callback_)); } void FakeProofSource::Activate() { @@ -71,30 +76,34 @@ void FakeProofSource::Activate() { void FakeProofSource::GetProof( const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, const std::string& hostname, const std::string& server_config, QuicTransportVersion transport_version, quiche::QuicheStringPiece chlo_hash, std::unique_ptr<ProofSource::Callback> callback) { if (!active_) { - delegate_->GetProof(server_address, hostname, server_config, + delegate_->GetProof(server_address, client_address, hostname, server_config, transport_version, chlo_hash, std::move(callback)); return; } pending_ops_.push_back(std::make_unique<GetProofOp>( - server_address, hostname, server_config, transport_version, - std::string(chlo_hash), std::move(callback), delegate_.get())); + server_address, client_address, hostname, server_config, + transport_version, std::string(chlo_hash), std::move(callback), + delegate_.get())); } QuicReferenceCountedPointer<ProofSource::Chain> FakeProofSource::GetCertChain( const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, const std::string& hostname) { - return delegate_->GetCertChain(server_address, hostname); + return delegate_->GetCertChain(server_address, client_address, hostname); } void FakeProofSource::ComputeTlsSignature( const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, const std::string& hostname, uint16_t signature_algorithm, quiche::QuicheStringPiece in, @@ -102,15 +111,28 @@ void FakeProofSource::ComputeTlsSignature( QUIC_LOG(INFO) << "FakeProofSource::ComputeTlsSignature"; if (!active_) { QUIC_LOG(INFO) << "Not active - directly calling delegate"; - delegate_->ComputeTlsSignature( - server_address, hostname, signature_algorithm, in, std::move(callback)); + delegate_->ComputeTlsSignature(server_address, client_address, hostname, + signature_algorithm, in, + std::move(callback)); return; } QUIC_LOG(INFO) << "Adding pending op"; pending_ops_.push_back(std::make_unique<ComputeSignatureOp>( - server_address, hostname, signature_algorithm, in, std::move(callback), - delegate_.get())); + server_address, client_address, hostname, signature_algorithm, in, + std::move(callback), delegate_.get())); +} + +ProofSource::TicketCrypter* FakeProofSource::GetTicketCrypter() { + if (ticket_crypter_) { + return ticket_crypter_.get(); + } + return delegate_->GetTicketCrypter(); +} + +void FakeProofSource::SetTicketCrypter( + std::unique_ptr<TicketCrypter> ticket_crypter) { + ticket_crypter_ = std::move(ticket_crypter); } int FakeProofSource::NumPendingCallbacks() const { diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source.h b/chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source.h index 41b761ac119..94dede6b385 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/fake_proof_source.h @@ -15,10 +15,13 @@ namespace quic { namespace test { -// Implementation of ProofSource which delegates to a ProofSourceForTesting, -// except that when the async GetProof is called, it captures the call and -// allows tests to see that a call is pending, which they can then cause to -// complete at a time of their choosing. +// Implementation of ProofSource which delegates to a ProofSourceForTesting, but +// allows for overriding certain functionality. FakeProofSource allows +// intercepting calls to GetProof and ComputeTlsSignature to force them to run +// asynchronously, and allow the caller to see that the call is pending and +// resume the operation at the caller's choosing. FakeProofSource also allows +// the caller to replace the TicketCrypter provided by +// FakeProofSource::GetTicketCrypter. class FakeProofSource : public ProofSource { public: FakeProofSource(); @@ -32,6 +35,7 @@ class FakeProofSource : public ProofSource { // ProofSource interface void GetProof(const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, const std::string& hostname, const std::string& server_config, QuicTransportVersion transport_version, @@ -39,13 +43,20 @@ class FakeProofSource : public ProofSource { std::unique_ptr<ProofSource::Callback> callback) override; QuicReferenceCountedPointer<Chain> GetCertChain( const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, const std::string& hostname) override; void ComputeTlsSignature( const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, const std::string& hostname, uint16_t signature_algorithm, quiche::QuicheStringPiece in, std::unique_ptr<ProofSource::SignatureCallback> callback) override; + TicketCrypter* GetTicketCrypter() override; + + // Sets the TicketCrypter to use. If nullptr, the TicketCrypter from + // ProofSourceForTesting will be returned instead. + void SetTicketCrypter(std::unique_ptr<TicketCrypter> ticket_crypter); // Get the number of callbacks which are pending int NumPendingCallbacks() const; @@ -56,6 +67,7 @@ class FakeProofSource : public ProofSource { private: std::unique_ptr<ProofSource> delegate_; + std::unique_ptr<TicketCrypter> ticket_crypter_; bool active_ = false; class PendingOp { @@ -67,6 +79,7 @@ class FakeProofSource : public ProofSource { class GetProofOp : public PendingOp { public: GetProofOp(const QuicSocketAddress& server_addr, + const QuicSocketAddress& client_address, std::string hostname, std::string server_config, QuicTransportVersion transport_version, @@ -79,6 +92,7 @@ class FakeProofSource : public ProofSource { private: QuicSocketAddress server_address_; + QuicSocketAddress client_address_; std::string hostname_; std::string server_config_; QuicTransportVersion transport_version_; @@ -90,6 +104,7 @@ class FakeProofSource : public ProofSource { class ComputeSignatureOp : public PendingOp { public: ComputeSignatureOp(const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, std::string hostname, uint16_t sig_alg, quiche::QuicheStringPiece in, @@ -101,6 +116,7 @@ class FakeProofSource : public ProofSource { private: QuicSocketAddress server_address_; + QuicSocketAddress client_address_; std::string hostname_; uint16_t sig_alg_; std::string in_; diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/first_flight.cc b/chromium/net/third_party/quiche/src/quic/test_tools/first_flight.cc new file mode 100644 index 00000000000..e4d28161ac2 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/test_tools/first_flight.cc @@ -0,0 +1,140 @@ +// Copyright (c) 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/test_tools/first_flight.h" + +#include <memory> +#include <vector> + +#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h" +#include "net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index.h" +#include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.h" +#include "net/third_party/quiche/src/quic/core/quic_config.h" +#include "net/third_party/quiche/src/quic/core/quic_connection.h" +#include "net/third_party/quiche/src/quic/core/quic_connection_id.h" +#include "net/third_party/quiche/src/quic/core/quic_packet_writer.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/core/quic_versions.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" +#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" + +namespace quic { +namespace test { + +// Utility class that creates a custom HTTP/3 session and QUIC connection in +// order to extract the first flight of packets it sends. This is meant to only +// be used by GetFirstFlightOfPackets() below. +class FirstFlightExtractor : public DelegatedPacketWriter::Delegate { + public: + FirstFlightExtractor(const ParsedQuicVersion& version, + const QuicConfig& config, + const QuicConnectionId& server_connection_id, + const QuicConnectionId& client_connection_id) + : version_(version), + server_connection_id_(server_connection_id), + client_connection_id_(client_connection_id), + writer_(this), + config_(config), + crypto_config_(crypto_test_utils::ProofVerifierForTesting()) { + EXPECT_NE(version_, UnsupportedQuicVersion()); + } + + void GenerateFirstFlight() { + crypto_config_.set_alpn(AlpnForVersion(version_)); + connection_ = + new QuicConnection(server_connection_id_, + QuicSocketAddress(TestPeerIPAddress(), kTestPort), + &connection_helper_, &alarm_factory_, &writer_, + /*owns_writer=*/false, Perspective::IS_CLIENT, + ParsedQuicVersionVector{version_}); + connection_->set_client_connection_id(client_connection_id_); + session_ = std::make_unique<QuicSpdyClientSession>( + config_, ParsedQuicVersionVector{version_}, + connection_, // session_ takes ownership of connection_ here. + TestServerId(), &crypto_config_, &push_promise_index_); + session_->Initialize(); + session_->CryptoConnect(); + } + + void OnDelegatedPacket(const char* buffer, + size_t buf_len, + const QuicIpAddress& /*self_client_address*/, + const QuicSocketAddress& /*peer_client_address*/, + PerPacketOptions* /*options*/) override { + packets_.emplace_back( + QuicReceivedPacket(buffer, buf_len, + connection_helper_.GetClock()->ApproximateNow(), + /*owns_buffer=*/false) + .Clone()); + } + + std::vector<std::unique_ptr<QuicReceivedPacket>>&& ConsumePackets() { + return std::move(packets_); + } + + private: + ParsedQuicVersion version_; + QuicConnectionId server_connection_id_; + QuicConnectionId client_connection_id_; + MockQuicConnectionHelper connection_helper_; + MockAlarmFactory alarm_factory_; + DelegatedPacketWriter writer_; + QuicConfig config_; + QuicCryptoClientConfig crypto_config_; + QuicClientPushPromiseIndex push_promise_index_; + QuicConnection* connection_; // Owned by session_. + std::unique_ptr<QuicSpdyClientSession> session_; + std::vector<std::unique_ptr<QuicReceivedPacket>> packets_; +}; + +std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets( + const ParsedQuicVersion& version, + const QuicConfig& config, + const QuicConnectionId& server_connection_id, + const QuicConnectionId& client_connection_id) { + FirstFlightExtractor first_flight_extractor( + version, config, server_connection_id, client_connection_id); + first_flight_extractor.GenerateFirstFlight(); + return first_flight_extractor.ConsumePackets(); +} + +std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets( + const ParsedQuicVersion& version, + const QuicConfig& config, + const QuicConnectionId& server_connection_id) { + return GetFirstFlightOfPackets(version, config, server_connection_id, + EmptyQuicConnectionId()); +} + +std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets( + const ParsedQuicVersion& version, + const QuicConfig& config) { + return GetFirstFlightOfPackets(version, config, TestConnectionId()); +} + +std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets( + const ParsedQuicVersion& version, + const QuicConnectionId& server_connection_id, + const QuicConnectionId& client_connection_id) { + return GetFirstFlightOfPackets(version, DefaultQuicConfig(), + server_connection_id, client_connection_id); +} + +std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets( + const ParsedQuicVersion& version, + const QuicConnectionId& server_connection_id) { + return GetFirstFlightOfPackets(version, DefaultQuicConfig(), + server_connection_id, EmptyQuicConnectionId()); +} + +std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets( + const ParsedQuicVersion& version) { + return GetFirstFlightOfPackets(version, DefaultQuicConfig(), + TestConnectionId()); +} + +} // namespace test +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/first_flight.h b/chromium/net/third_party/quiche/src/quic/test_tools/first_flight.h new file mode 100644 index 00000000000..b2a4ebd36be --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/test_tools/first_flight.h @@ -0,0 +1,111 @@ +// Copyright (c) 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_TEST_TOOLS_FIRST_FLIGHT_H_ +#define QUICHE_QUIC_TEST_TOOLS_FIRST_FLIGHT_H_ + +#include <memory> +#include <vector> + +#include "net/third_party/quiche/src/quic/core/quic_config.h" +#include "net/third_party/quiche/src/quic/core/quic_connection_id.h" +#include "net/third_party/quiche/src/quic/core/quic_packet_writer.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/core/quic_versions.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" + +namespace quic { +namespace test { + +// Implementation of QuicPacketWriter that sends all packets to a delegate. +class QUIC_NO_EXPORT DelegatedPacketWriter : public QuicPacketWriter { + public: + class QUIC_NO_EXPORT Delegate { + public: + virtual ~Delegate() {} + // Note that |buffer| may be released after this call completes so overrides + // that want to use the data after the call is complete MUST copy it. + virtual void OnDelegatedPacket(const char* buffer, + size_t buf_len, + const QuicIpAddress& self_client_address, + const QuicSocketAddress& peer_client_address, + PerPacketOptions* options) = 0; + }; + + // |delegate| MUST be valid for the duration of the DelegatedPacketWriter's + // lifetime. + explicit DelegatedPacketWriter(Delegate* delegate) : delegate_(delegate) { + CHECK_NE(delegate_, nullptr); + } + + // Overrides for QuicPacketWriter. + bool IsWriteBlocked() const override { return false; } + void SetWritable() override {} + QuicByteCount GetMaxPacketSize( + const QuicSocketAddress& /*peer_address*/) const override { + return kMaxOutgoingPacketSize; + } + bool SupportsReleaseTime() const override { return false; } + bool IsBatchMode() const override { return false; } + char* GetNextWriteLocation( + const QuicIpAddress& /*self_address*/, + const QuicSocketAddress& /*peer_address*/) override { + return nullptr; + } + WriteResult Flush() override { return WriteResult(WRITE_STATUS_OK, 0); } + + WriteResult WritePacket(const char* buffer, + size_t buf_len, + const QuicIpAddress& self_client_address, + const QuicSocketAddress& peer_client_address, + PerPacketOptions* options) override { + delegate_->OnDelegatedPacket(buffer, buf_len, self_client_address, + peer_client_address, options); + return WriteResult(WRITE_STATUS_OK, buf_len); + } + + private: + Delegate* delegate_; // Unowned. +}; + +// Returns an array of packets that represent the first flight of a real +// HTTP/3 connection. In most cases, this array will only contain one packet +// that carries the CHLO. +std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets( + const ParsedQuicVersion& version, + const QuicConfig& config, + const QuicConnectionId& server_connection_id, + const QuicConnectionId& client_connection_id); + +// Below are various convenience overloads that use default values for the +// omitted parameters: +// |config| = DefaultQuicConfig(), +// |server_connection_id| = TestConnectionId(), +// |client_connection_id| = EmptyQuicConnectionId(). +std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets( + const ParsedQuicVersion& version, + const QuicConfig& config, + const QuicConnectionId& server_connection_id); + +std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets( + const ParsedQuicVersion& version, + const QuicConnectionId& server_connection_id, + const QuicConnectionId& client_connection_id); + +std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets( + const ParsedQuicVersion& version, + const QuicConnectionId& server_connection_id); + +std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets( + const ParsedQuicVersion& version, + const QuicConfig& config); + +std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets( + const ParsedQuicVersion& version); + +} // namespace test +} // namespace quic + +#endif // QUICHE_QUIC_TEST_TOOLS_FIRST_FLIGHT_H_ diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_client_promised_info.h b/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_client_promised_info.h index 1cb9019033c..f89d5797d7f 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_client_promised_info.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_client_promised_info.h @@ -21,9 +21,11 @@ class MockQuicClientPromisedInfo : public QuicClientPromisedInfo { std::string url); ~MockQuicClientPromisedInfo() override; - MOCK_METHOD2(HandleClientRequest, - QuicAsyncStatus(const spdy::SpdyHeaderBlock& headers, - QuicClientPushPromiseIndex::Delegate* delegate)); + MOCK_METHOD(QuicAsyncStatus, + HandleClientRequest, + (const spdy::SpdyHeaderBlock& headers, + QuicClientPushPromiseIndex::Delegate*), + (override)); }; } // namespace test diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_dispatcher.h b/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_dispatcher.h index b2ab45329d6..21c3dca7143 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_dispatcher.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_dispatcher.h @@ -30,10 +30,12 @@ class MockQuicDispatcher : public QuicSimpleDispatcher { ~MockQuicDispatcher() override; - MOCK_METHOD3(ProcessPacket, - void(const QuicSocketAddress& server_address, - const QuicSocketAddress& client_address, - const QuicReceivedPacket& packet)); + MOCK_METHOD(void, + ProcessPacket, + (const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, + const QuicReceivedPacket& packet), + (override)); }; } // namespace test diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_session_visitor.h b/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_session_visitor.h index 0cc10d1d3d5..5cc8476fe5e 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_session_visitor.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_session_visitor.h @@ -18,17 +18,26 @@ class MockQuicSessionVisitor : public QuicTimeWaitListManager::Visitor { MockQuicSessionVisitor(const MockQuicSessionVisitor&) = delete; MockQuicSessionVisitor& operator=(const MockQuicSessionVisitor&) = delete; ~MockQuicSessionVisitor() override; - MOCK_METHOD4(OnConnectionClosed, - void(QuicConnectionId connection_id, - QuicErrorCode error, - const std::string& error_details, - ConnectionCloseSource source)); - MOCK_METHOD1(OnWriteBlocked, - void(QuicBlockedWriterInterface* blocked_writer)); - MOCK_METHOD1(OnRstStreamReceived, void(const QuicRstStreamFrame& frame)); - MOCK_METHOD1(OnStopSendingReceived, void(const QuicStopSendingFrame& frame)); - MOCK_METHOD1(OnConnectionAddedToTimeWaitList, - void(QuicConnectionId connection_id)); + MOCK_METHOD(void, + OnConnectionClosed, + (QuicConnectionId connection_id, + QuicErrorCode error, + const std::string& error_details, + ConnectionCloseSource source), + (override)); + MOCK_METHOD(void, OnWriteBlocked, (QuicBlockedWriterInterface*), (override)); + MOCK_METHOD(void, + OnRstStreamReceived, + (const QuicRstStreamFrame& frame), + (override)); + MOCK_METHOD(void, + OnStopSendingReceived, + (const QuicStopSendingFrame& frame), + (override)); + MOCK_METHOD(void, + OnConnectionAddedToTimeWaitList, + (QuicConnectionId connection_id), + (override)); }; class MockQuicCryptoServerStreamHelper @@ -40,12 +49,14 @@ class MockQuicCryptoServerStreamHelper MockQuicCryptoServerStreamHelper& operator=( const MockQuicCryptoServerStreamHelper&) = delete; ~MockQuicCryptoServerStreamHelper() override; - MOCK_CONST_METHOD5(CanAcceptClientHello, - bool(const CryptoHandshakeMessage& message, - const QuicSocketAddress& client_address, - const QuicSocketAddress& peer_address, - const QuicSocketAddress& self_address, - std::string* error_details)); + MOCK_METHOD(bool, + CanAcceptClientHello, + (const CryptoHandshakeMessage& message, + const QuicSocketAddress& client_address, + const QuicSocketAddress& peer_address, + const QuicSocketAddress& self_address, + std::string*), + (const, override)); }; } // namespace test diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_spdy_client_stream.h b/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_spdy_client_stream.h index 02fe74ecb70..f72822ef963 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_spdy_client_stream.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_spdy_client_stream.h @@ -20,12 +20,14 @@ class MockQuicSpdyClientStream : public QuicSpdyClientStream { StreamType type); ~MockQuicSpdyClientStream() override; - MOCK_METHOD1(OnStreamFrame, void(const QuicStreamFrame& frame)); - MOCK_METHOD3(OnPromiseHeaderList, - void(QuicStreamId promised_stream_id, - size_t frame_len, - const QuicHeaderList& list)); - MOCK_METHOD0(OnDataAvailable, void()); + MOCK_METHOD(void, OnStreamFrame, (const QuicStreamFrame& frame), (override)); + MOCK_METHOD(void, + OnPromiseHeaderList, + (QuicStreamId promised_stream_id, + size_t frame_len, + const QuicHeaderList& list), + (override)); + MOCK_METHOD(void, OnDataAvailable, (), (override)); }; } // namespace test diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_time_wait_list_manager.h b/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_time_wait_list_manager.h index b8a9776381a..54bd6d478ff 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_time_wait_list_manager.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_time_wait_list_manager.h @@ -19,13 +19,14 @@ class MockTimeWaitListManager : public QuicTimeWaitListManager { QuicAlarmFactory* alarm_factory); ~MockTimeWaitListManager() override; - MOCK_METHOD5(AddConnectionIdToTimeWait, - void(QuicConnectionId connection_id, - bool ietf_quic, - QuicTimeWaitListManager::TimeWaitAction action, - EncryptionLevel encryption_level, - std::vector<std::unique_ptr<QuicEncryptedPacket>>* - termination_packets)); + MOCK_METHOD(void, + AddConnectionIdToTimeWait, + (QuicConnectionId connection_id, + bool ietf_quic, + QuicTimeWaitListManager::TimeWaitAction action, + EncryptionLevel encryption_level, + std::vector<std::unique_ptr<QuicEncryptedPacket>>*), + (override)); void QuicTimeWaitListManager_AddConnectionIdToTimeWait( QuicConnectionId connection_id, @@ -38,34 +39,42 @@ class MockTimeWaitListManager : public QuicTimeWaitListManager { termination_packets); } - MOCK_METHOD5(ProcessPacket, - void(const QuicSocketAddress& server_address, - const QuicSocketAddress& client_address, - QuicConnectionId connection_id, - PacketHeaderFormat header_format, - std::unique_ptr<QuicPerPacketContext> packet_context)); + MOCK_METHOD(void, + ProcessPacket, + (const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, + QuicConnectionId connection_id, + PacketHeaderFormat header_format, + std::unique_ptr<QuicPerPacketContext> packet_context), + (override)); - MOCK_METHOD8(SendVersionNegotiationPacket, - void(QuicConnectionId server_connection_id, - QuicConnectionId client_connection_id, - bool ietf_quic, - bool has_length_prefix, - const ParsedQuicVersionVector& supported_versions, - const QuicSocketAddress& server_address, - const QuicSocketAddress& client_address, - std::unique_ptr<QuicPerPacketContext> packet_context)); + MOCK_METHOD(void, + SendVersionNegotiationPacket, + (QuicConnectionId server_connection_id, + QuicConnectionId client_connection_id, + bool ietf_quic, + bool has_length_prefix, + const ParsedQuicVersionVector& supported_versions, + const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, + std::unique_ptr<QuicPerPacketContext> packet_context), + (override)); - MOCK_METHOD5(SendPublicReset, - void(const QuicSocketAddress&, - const QuicSocketAddress&, - QuicConnectionId, - bool, - std::unique_ptr<QuicPerPacketContext>)); + MOCK_METHOD(void, + SendPublicReset, + (const QuicSocketAddress&, + const QuicSocketAddress&, + QuicConnectionId, + bool, + std::unique_ptr<QuicPerPacketContext>), + (override)); - MOCK_METHOD3(SendPacket, - void(const QuicSocketAddress&, - const QuicSocketAddress&, - const QuicEncryptedPacket&)); + MOCK_METHOD(void, + SendPacket, + (const QuicSocketAddress&, + const QuicSocketAddress&, + const QuicEncryptedPacket&), + (override)); }; } // namespace test diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.h b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.h index 2bd80ef65ed..9741b05bdf5 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.h @@ -32,8 +32,10 @@ class MockEncoderStreamErrorDelegate public: ~MockEncoderStreamErrorDelegate() override = default; - MOCK_METHOD1(OnEncoderStreamError, - void(quiche::QuicheStringPiece error_message)); + MOCK_METHOD(void, + OnEncoderStreamError, + (quiche::QuicheStringPiece error_message), + (override)); }; // HeadersHandlerInterface implementation that collects decoded headers @@ -74,12 +76,15 @@ class MockHeadersHandler MockHeadersHandler& operator=(const MockHeadersHandler&) = delete; ~MockHeadersHandler() override = default; - MOCK_METHOD2(OnHeaderDecoded, - void(quiche::QuicheStringPiece name, - quiche::QuicheStringPiece value)); - MOCK_METHOD0(OnDecodingCompleted, void()); - MOCK_METHOD1(OnDecodingErrorDetected, - void(quiche::QuicheStringPiece error_message)); + MOCK_METHOD(void, + OnHeaderDecoded, + (quiche::QuicheStringPiece name, quiche::QuicheStringPiece value), + (override)); + MOCK_METHOD(void, OnDecodingCompleted, (), (override)); + MOCK_METHOD(void, + OnDecodingErrorDetected, + (quiche::QuicheStringPiece error_message), + (override)); }; class NoOpHeadersHandler diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_test_utils.h b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_test_utils.h index 0ea978f7b40..9b188150796 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_test_utils.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_test_utils.h @@ -31,8 +31,10 @@ class MockDecoderStreamErrorDelegate public: ~MockDecoderStreamErrorDelegate() override = default; - MOCK_METHOD1(OnDecoderStreamError, - void(quiche::QuicheStringPiece error_message)); + MOCK_METHOD(void, + OnDecoderStreamError, + (quiche::QuicheStringPiece error_message), + (override)); }; } // namespace test diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h index 074095048d7..b9f4adfb6d9 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h @@ -32,7 +32,10 @@ class MockQpackStreamSenderDelegate : public QpackStreamSenderDelegate { public: ~MockQpackStreamSenderDelegate() override = default; - MOCK_METHOD1(WriteStreamData, void(quiche::QuicheStringPiece data)); + MOCK_METHOD(void, + WriteStreamData, + (quiche::QuicheStringPiece data), + (override)); }; class NoopQpackStreamSenderDelegate : public QpackStreamSenderDelegate { diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.cc index 20463ab4592..3e752154f27 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.cc @@ -5,6 +5,7 @@ #include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h" #include "net/third_party/quiche/src/quic/core/quic_config.h" +#include "net/third_party/quiche/src/quic/core/quic_connection_id.h" namespace quic { namespace test { @@ -98,12 +99,22 @@ void QuicConfigPeer::SetReceivedMaxPacketSize(QuicConfig* config, } // static -void QuicConfigPeer::ReceiveIdleNetworkTimeout(QuicConfig* config, - HelloType hello_type, - uint32_t idle_timeout_seconds) { - std::string error_details; - config->idle_network_timeout_seconds_.ReceiveValue( - idle_timeout_seconds, hello_type, &error_details); +void QuicConfigPeer::SetNegotiated(QuicConfig* config, bool negotiated) { + config->negotiated_ = negotiated; +} + +// static +void QuicConfigPeer::SetReceivedOriginalConnectionId( + QuicConfig* config, + const QuicConnectionId& original_connection_id) { + config->received_original_connection_id_ = original_connection_id; +} + +// static +void QuicConfigPeer::SetReceivedMaxDatagramFrameSize( + QuicConfig* config, + uint64_t max_datagram_frame_size) { + config->max_datagram_frame_size_.SetReceivedValue(max_datagram_frame_size); } } // namespace test diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.h index b52bf42085b..c435f2282da 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.h @@ -6,6 +6,7 @@ #define QUICHE_QUIC_TEST_TOOLS_QUIC_CONFIG_PEER_H_ #include "net/third_party/quiche/src/quic/core/quic_config.h" +#include "net/third_party/quiche/src/quic/core/quic_connection_id.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/platform/api/quic_uint128.h" @@ -59,9 +60,14 @@ class QuicConfigPeer { static void SetReceivedMaxPacketSize(QuicConfig* config, uint32_t max_packet_size); - static void ReceiveIdleNetworkTimeout(QuicConfig* config, - HelloType hello_type, - uint32_t idle_timeout_seconds); + static void SetNegotiated(QuicConfig* config, bool negotiated); + + static void SetReceivedOriginalConnectionId( + QuicConfig* config, + const QuicConnectionId& original_connection_id); + + static void SetReceivedMaxDatagramFrameSize(QuicConfig* config, + uint64_t max_datagram_frame_size); }; } // namespace test 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 6b6387f47c1..d276f6327ea 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 @@ -91,12 +91,6 @@ void QuicConnectionPeer::SetEffectivePeerAddress( } // static -bool QuicConnectionPeer::IsSilentCloseEnabled(QuicConnection* connection) { - return connection->idle_timeout_connection_close_behavior_ == - ConnectionCloseBehavior::SILENT_CLOSE; -} - -// static void QuicConnectionPeer::SwapCrypters(QuicConnection* connection, QuicFramer* framer) { QuicFramerPeer::SwapCrypters(framer, &connection->framer_); @@ -160,12 +154,6 @@ QuicAlarm* QuicConnectionPeer::GetMtuDiscoveryAlarm( } // static -QuicAlarm* QuicConnectionPeer::GetPathDegradingAlarm( - QuicConnection* connection) { - return connection->path_degrading_alarm_.get(); -} - -// static QuicAlarm* QuicConnectionPeer::GetProcessUndecryptablePacketsAlarm( QuicConnection* connection) { return connection->process_undecryptable_packets_alarm_.get(); @@ -381,5 +369,13 @@ QuicAlarm* QuicConnectionPeer::GetIdleNetworkDetectorAlarm( return connection->idle_network_detector_.alarm_.get(); } +// static +void QuicConnectionPeer::SetServerConnectionId( + QuicConnection* connection, + const QuicConnectionId& server_connection_id) { + connection->server_connection_id_ = server_connection_id; + connection->InstallInitialCrypters(server_connection_id); +} + } // 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 d6d6b3cc3c0..9882f62ee35 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 @@ -64,8 +64,6 @@ class QuicConnectionPeer { QuicConnection* connection, const QuicSocketAddress& effective_peer_address); - static bool IsSilentCloseEnabled(QuicConnection* connection); - static void SwapCrypters(QuicConnection* connection, QuicFramer* framer); static void SetCurrentPacket(QuicConnection* connection, @@ -83,7 +81,6 @@ class QuicConnectionPeer { static QuicAlarm* GetSendAlarm(QuicConnection* connection); static QuicAlarm* GetTimeoutAlarm(QuicConnection* connection); static QuicAlarm* GetMtuDiscoveryAlarm(QuicConnection* connection); - static QuicAlarm* GetPathDegradingAlarm(QuicConnection* connection); static QuicAlarm* GetProcessUndecryptablePacketsAlarm( QuicConnection* connection); @@ -146,6 +143,10 @@ class QuicConnectionPeer { static QuicTime GetBlackholeDetectionDeadline(QuicConnection* connection); static QuicAlarm* GetIdleNetworkDetectorAlarm(QuicConnection* connection); + + static void SetServerConnectionId( + QuicConnection* connection, + const QuicConnectionId& server_connection_id); }; } // 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 b460165d906..467c689af94 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 @@ -112,5 +112,12 @@ void QuicDispatcherPeer::RestorePerPacketContext( dispatcher->RestorePerPacketContext(std::move(context)); } +// static +std::string QuicDispatcherPeer::SelectAlpn( + QuicDispatcher* dispatcher, + const std::vector<std::string>& alpns) { + return dispatcher->SelectAlpn(alpns); +} + } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_dispatcher_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_dispatcher_peer.h index 7cb4c92c5a9..ec22f94f480 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_dispatcher_peer.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_dispatcher_peer.h @@ -66,6 +66,9 @@ class QuicDispatcherPeer { static void RestorePerPacketContext(QuicDispatcher* dispatcher, std::unique_ptr<QuicPerPacketContext>); + + static std::string SelectAlpn(QuicDispatcher* dispatcher, + const std::vector<std::string>& alpns); }; } // 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 822401272e2..44fed8809ec 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 @@ -119,14 +119,14 @@ SerializedPacket QuicPacketCreatorPeer::SerializeAllFrames( } // static -OwningSerializedPacketPointer +std::unique_ptr<SerializedPacket> QuicPacketCreatorPeer::SerializeConnectivityProbingPacket( QuicPacketCreator* creator) { return creator->SerializeConnectivityProbingPacket(); } // static -OwningSerializedPacketPointer +std::unique_ptr<SerializedPacket> QuicPacketCreatorPeer::SerializePathChallengeConnectivityProbingPacket( QuicPacketCreator* creator, QuicPathFrameBuffer* payload) { @@ -149,5 +149,10 @@ std::string QuicPacketCreatorPeer::GetRetryToken(QuicPacketCreator* creator) { return creator->retry_token_; } +// static +QuicFrames& QuicPacketCreatorPeer::QueuedFrames(QuicPacketCreator* creator) { + return creator->queued_frames_; +} + } // 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 bdadc2b9ad9..2dc941388a0 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 @@ -50,15 +50,16 @@ class QuicPacketCreatorPeer { const QuicFrames& frames, char* buffer, size_t buffer_len); - static OwningSerializedPacketPointer SerializeConnectivityProbingPacket( + static std::unique_ptr<SerializedPacket> SerializeConnectivityProbingPacket( QuicPacketCreator* creator); - static OwningSerializedPacketPointer + static std::unique_ptr<SerializedPacket> SerializePathChallengeConnectivityProbingPacket(QuicPacketCreator* creator, QuicPathFrameBuffer* payload); static EncryptionLevel GetEncryptionLevel(QuicPacketCreator* creator); static QuicFramer* framer(QuicPacketCreator* creator); static std::string GetRetryToken(QuicPacketCreator* creator); + static QuicFrames& QueuedFrames(QuicPacketCreator* creator); }; } // namespace test diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc index cbaf5d62be9..ab28828cc14 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc @@ -143,12 +143,6 @@ QuicSession::ZombieStreamMap& QuicSessionPeer::zombie_streams( } // static -QuicUnorderedSet<QuicStreamId>* QuicSessionPeer::GetDrainingStreams( - QuicSession* session) { - return &session->draining_streams_; -} - -// static void QuicSessionPeer::ActivateStream(QuicSession* session, std::unique_ptr<QuicStream> stream) { return session->ActivateStream(std::move(stream)); @@ -239,5 +233,21 @@ void QuicSessionPeer::SetPerspective(QuicSession* session, session->perspective_ = perspective; } +// static +size_t QuicSessionPeer::GetNumOpenDynamicStreams(QuicSession* session) { + size_t result = 0; + for (const auto& it : session->stream_map_) { + if (!it.second->is_static()) { + ++result; + } + } + // Exclude draining streams. + result -= session->GetNumDrainingStreams(); + // Add locally closed streams. + result += session->locally_closed_streams_highest_offset_.size(); + + return result; +} + } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h index 72caa9135b9..ffb6a46446d 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h @@ -59,8 +59,6 @@ class QuicSessionPeer { static QuicSession::StreamMap& stream_map(QuicSession* session); static const QuicSession::ClosedStreams& closed_streams(QuicSession* session); static QuicSession::ZombieStreamMap& zombie_streams(QuicSession* session); - static QuicUnorderedSet<QuicStreamId>* GetDrainingStreams( - QuicSession* session); static void ActivateStream(QuicSession* session, std::unique_ptr<QuicStream> stream); @@ -83,6 +81,7 @@ class QuicSessionPeer { QuicStreamId stream_id); static void set_is_configured(QuicSession* session, bool value); static void SetPerspective(QuicSession* session, Perspective perspective); + static size_t GetNumOpenDynamicStreams(QuicSession* session); }; } // namespace test diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_peer.cc index 42961984527..50eec57aa6c 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_peer.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_peer.cc @@ -58,5 +58,15 @@ QuicStreamSendBuffer& QuicStreamPeer::SendBuffer(QuicStream* stream) { return stream->send_buffer_; } +// static +void QuicStreamPeer::SetFinReceived(QuicStream* stream) { + stream->fin_received_ = true; +} + +// static +void QuicStreamPeer::SetFinSent(QuicStream* stream) { + stream->fin_sent_ = true; +} + } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_peer.h index f4b1de3165b..e57825f24f9 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_peer.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_peer.h @@ -32,6 +32,8 @@ class QuicStreamPeer { static QuicStreamSequencer* sequencer(QuicStream* stream); static QuicSession* session(QuicStream* stream); + static void SetFinReceived(QuicStream* stream); + static void SetFinSent(QuicStream* stream); static QuicStreamSendBuffer& SendBuffer(QuicStream* stream); }; 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 5ddc879af62..22e65b822ee 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 @@ -74,6 +74,7 @@ class RecordingProofVerifier : public ProofVerifier { QuicAsyncStatus VerifyCertChain( const std::string& /*hostname*/, + const uint16_t /*port*/, const std::vector<std::string>& certs, const std::string& /*ocsp_response*/, const std::string& cert_sct, @@ -357,10 +358,6 @@ void QuicTestClient::Initialize() { num_requests_ = 0; num_responses_ = 0; ClearPerConnectionState(); - // TODO(b/142715651): Figure out how to use QPACK in tests. - // Do not use the QPACK dynamic table in tests to avoid flakiness due to the - // uncertain order of receiving the SETTINGS frame and sending headers. - client_->disable_qpack_dynamic_table(); // As chrome will generally do this, we want it to be the default when it's // not overridden. if (!client_->config()->HasSetBytesForConnectionIdToSend()) { @@ -393,8 +390,13 @@ ssize_t QuicTestClient::SendRequestAndRstTogether(const std::string& uri) { QuicStreamId stream_id = GetNthClientInitiatedBidirectionalStreamId( session->transport_version(), 0); QuicStream* stream = session->GetOrCreateStream(stream_id); - session->SendRstStream(stream_id, QUIC_STREAM_CANCELLED, + if (session->break_close_loop()) { + session->ResetStream(stream_id, QUIC_STREAM_CANCELLED, stream->stream_bytes_written()); + } else { + session->SendRstStream(stream_id, QUIC_STREAM_CANCELLED, + stream->stream_bytes_written()); + } return ret; } diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_server.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_server.cc index d85fe1fdeac..1b6452eb0ec 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_server.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_server.cc @@ -119,11 +119,6 @@ class QuicTestDispatcher : public QuicSimpleDispatcher { config(), connection, this, session_helper(), crypto_config(), compressed_certs_cache(), server_backend()); } - // TODO(b/142715651): Figure out how to use QPACK in tests. - // Do not use the QPACK dynamic table in tests to avoid flakiness due to the - // uncertain order of receiving the SETTINGS frame and sending headers. - session->set_qpack_maximum_dynamic_table_capacity(0); - session->set_qpack_maximum_blocked_streams(0); session->Initialize(); return session; } @@ -240,14 +235,27 @@ void ImmediateGoAwaySession::OnStreamFrame(const QuicStreamFrame& frame) { } void ImmediateGoAwaySession::OnCryptoFrame(const QuicCryptoFrame& frame) { - // In IETF QUIC, GOAWAY lives up in HTTP/3 layer. Even if it's a immediate - // goaway session, goaway shouldn't be sent when crypto frame is received. + // In IETF QUIC, GOAWAY lives up in HTTP/3 layer. It's sent in a QUIC stream + // and requires encryption. Thus the sending is done in + // OnNewEncryptionKeyAvailable(). if (!VersionUsesHttp3(transport_version())) { SendGoAway(QUIC_PEER_GOING_AWAY, ""); } QuicSimpleServerSession::OnCryptoFrame(frame); } +void ImmediateGoAwaySession::OnNewEncryptionKeyAvailable( + EncryptionLevel level, + std::unique_ptr<QuicEncrypter> encrypter) { + QuicSimpleServerSession::OnNewEncryptionKeyAvailable(level, + std::move(encrypter)); + if (VersionUsesHttp3(transport_version())) { + if (IsEncryptionEstablished() && !http3_goaway_sent()) { + SendHttp3GoAway(); + } + } +} + } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_server.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_server.h index d88337a623e..2fa3e2077e9 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_server.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_server.h @@ -105,6 +105,9 @@ class ImmediateGoAwaySession : public QuicSimpleServerSession { // Override to send GoAway. void OnStreamFrame(const QuicStreamFrame& frame) override; void OnCryptoFrame(const QuicCryptoFrame& frame) override; + void OnNewEncryptionKeyAvailable( + EncryptionLevel level, + std::unique_ptr<QuicEncrypter> encrypter) override; }; } // namespace test diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc index d8a043611d1..7d88ccdaae7 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc @@ -17,13 +17,16 @@ #include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h" +#include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.h" #include "net/third_party/quiche/src/quic/core/quic_buffer_allocator.h" +#include "net/third_party/quiche/src/quic/core/quic_config.h" #include "net/third_party/quiche/src/quic/core/quic_data_writer.h" #include "net/third_party/quiche/src/quic/core/quic_framer.h" #include "net/third_party/quiche/src/quic/core/quic_packet_creator.h" #include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/core/quic_versions.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" #include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" @@ -74,6 +77,14 @@ uint64_t TestConnectionIdToUInt64(QuicConnectionId connection_id) { return quiche::QuicheEndian::NetToHost64(connection_id64_net); } +std::string TestHostname() { + return "test.example.org"; +} + +QuicServerId TestServerId() { + return QuicServerId(TestHostname(), kTestPort); +} + QuicAckFrame InitAckFrame(const std::vector<QuicAckBlock>& ack_blocks) { DCHECK_GT(ack_blocks.size(), 0u); @@ -549,14 +560,14 @@ PacketSavingConnection::PacketSavingConnection( PacketSavingConnection::~PacketSavingConnection() {} -void PacketSavingConnection::SendOrQueuePacket(SerializedPacket* packet) { +void PacketSavingConnection::SendOrQueuePacket(SerializedPacket packet) { encrypted_packets_.push_back(std::make_unique<QuicEncryptedPacket>( - CopyBuffer(*packet), packet->encrypted_length, true)); + CopyBuffer(packet), packet.encrypted_length, true)); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10)); // Transfer ownership of the packet to the SentPacketManager and the // ack notifier to the AckNotifierManager. QuicConnectionPeer::GetSentPacketManager(this)->OnPacketSent( - packet, clock_.ApproximateNow(), NOT_RETRANSMISSION, + &packet, clock_.ApproximateNow(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); } @@ -649,6 +660,15 @@ MockQuicSpdySession::MockQuicSpdySession(QuicConnection* connection, ON_CALL(*this, WritevData(_, _, _, _, _, _)) .WillByDefault(testing::Return(QuicConsumedData(0, false))); + + ON_CALL(*this, SendWindowUpdate(_, _)) + .WillByDefault([this](QuicStreamId id, QuicStreamOffset byte_offset) { + return QuicSpdySession::SendWindowUpdate(id, byte_offset); + }); + + ON_CALL(*this, SendBlocked(_)).WillByDefault([this](QuicStreamId id) { + return QuicSpdySession::SendBlocked(id); + }); } MockQuicSpdySession::~MockQuicSpdySession() { @@ -735,9 +755,11 @@ TestQuicSpdyClientSession::TestQuicSpdyClientSession( &push_promise_index_, config, supported_versions) { + // TODO(b/153726130): Consider adding OnApplicationState calls in tests and + // set |has_application_state| to true. crypto_stream_ = std::make_unique<QuicCryptoClientStream>( server_id, this, crypto_test_utils::ProofVerifyContextForTesting(), - crypto_config, this); + crypto_config, this, /*has_application_state = */ false); Initialize(); } @@ -780,6 +802,7 @@ MockPacketWriter::MockPacketWriter() { .WillByDefault(testing::Return(nullptr)); ON_CALL(*this, Flush()) .WillByDefault(testing::Return(WriteResult(WRITE_STATUS_OK, 0))); + ON_CALL(*this, SupportsReleaseTime()).WillByDefault(testing::Return(false)); } MockPacketWriter::~MockPacketWriter() {} @@ -817,6 +840,12 @@ ParsedQuicVersion QuicVersionMin() { return AllSupportedVersions().back(); } +void DisableQuicVersionsWithTls() { + SetQuicReloadableFlag(quic_enable_version_draft_27, false); + SetQuicReloadableFlag(quic_enable_version_draft_25_v3, false); + SetQuicReloadableFlag(quic_enable_version_t050_v2, false); +} + QuicEncryptedPacket* ConstructEncryptedPacket( QuicConnectionId destination_connection_id, QuicConnectionId source_connection_id, @@ -962,6 +991,49 @@ QuicEncryptedPacket* ConstructEncryptedPacket( return new QuicEncryptedPacket(buffer, encrypted_length, true); } +std::unique_ptr<QuicEncryptedPacket> GetUndecryptableEarlyPacket( + const ParsedQuicVersion& version, + const QuicConnectionId& server_connection_id) { + QuicPacketHeader header; + header.destination_connection_id = server_connection_id; + header.destination_connection_id_included = CONNECTION_ID_PRESENT; + header.source_connection_id = EmptyQuicConnectionId(); + header.source_connection_id_included = CONNECTION_ID_PRESENT; + if (!version.SupportsClientConnectionIds()) { + header.source_connection_id_included = CONNECTION_ID_ABSENT; + } + header.version_flag = true; + header.reset_flag = false; + header.packet_number_length = PACKET_4BYTE_PACKET_NUMBER; + header.packet_number = QuicPacketNumber(33); + header.long_packet_type = ZERO_RTT_PROTECTED; + if (version.HasLongHeaderLengths()) { + header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1; + header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; + } + + QuicFrames frames; + frames.push_back(QuicFrame(QuicPingFrame())); + frames.push_back(QuicFrame(QuicPaddingFrame(100))); + QuicFramer framer({version}, QuicTime::Zero(), Perspective::IS_CLIENT, + kQuicDefaultConnectionIdLength); + framer.SetInitialObfuscators(server_connection_id); + + framer.SetEncrypter(ENCRYPTION_ZERO_RTT, + std::make_unique<NullEncrypter>(Perspective::IS_CLIENT)); + std::unique_ptr<QuicPacket> packet( + BuildUnsizedDataPacket(&framer, header, frames)); + EXPECT_TRUE(packet != nullptr); + char* buffer = new char[kMaxOutgoingPacketSize]; + size_t encrypted_length = + framer.EncryptPayload(ENCRYPTION_ZERO_RTT, header.packet_number, *packet, + buffer, kMaxOutgoingPacketSize); + EXPECT_NE(0u, encrypted_length); + DeleteFrames(&frames); + return std::make_unique<QuicEncryptedPacket>(buffer, encrypted_length, + /*owns_buffer=*/true); +} + QuicReceivedPacket* ConstructReceivedPacket( const QuicEncryptedPacket& encrypted_packet, QuicTime receipt_time) { @@ -1085,6 +1157,12 @@ MockPacketCreatorDelegate::~MockPacketCreatorDelegate() {} MockSessionNotifier::MockSessionNotifier() {} MockSessionNotifier::~MockSessionNotifier() {} +// static +QuicCryptoClientStream::HandshakerInterface* +QuicCryptoClientStreamPeer::GetHandshaker(QuicCryptoClientStream* stream) { + return stream->handshaker_.get(); +} + void CreateClientSessionForTest( QuicServerId server_id, QuicTime::Delta connection_start_time, diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.h index e30f484b067..7d1d9db4459 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 @@ -19,9 +19,11 @@ #include "net/third_party/quiche/src/quic/core/http/quic_server_session_base.h" #include "net/third_party/quiche/src/quic/core/http/quic_spdy_session.h" #include "net/third_party/quiche/src/quic/core/quic_connection.h" +#include "net/third_party/quiche/src/quic/core/quic_connection_id.h" #include "net/third_party/quiche/src/quic/core/quic_framer.h" #include "net/third_party/quiche/src/quic/core/quic_packet_writer.h" #include "net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h" +#include "net/third_party/quiche/src/quic/core/quic_server_id.h" #include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage.h" @@ -50,11 +52,17 @@ QuicConnectionId TestConnectionIdNineBytesLong(uint64_t connection_number); // Extracts the connection number passed to TestConnectionId(). uint64_t TestConnectionIdToUInt64(QuicConnectionId connection_id); -static const uint16_t kTestPort = 12345; -static const uint32_t kInitialStreamFlowControlWindowForTest = - 1024 * 1024; // 1 MB -static const uint32_t kInitialSessionFlowControlWindowForTest = - 1536 * 1024; // 1.5 MB +enum : uint16_t { kTestPort = 12345 }; +enum : uint32_t { + kInitialStreamFlowControlWindowForTest = 1024 * 1024, // 1 MB + kInitialSessionFlowControlWindowForTest = 1536 * 1024, // 1.5 MB +}; + +// A hostname useful for testing, returns "test.example.org". +std::string TestHostname(); + +// A server ID useful for testing, returns test.example.org:12345. +QuicServerId TestServerId(); // Returns the test peer IP address. QuicIpAddress TestPeerIPAddress(); @@ -65,6 +73,11 @@ ParsedQuicVersion QuicVersionMax(); // Lower limit on versions we support. ParsedQuicVersion QuicVersionMin(); +// Disables all flags that enable QUIC versions that use TLS. +// This is only meant as a temporary measure to prevent some broken tests +// from running with TLS. +void DisableQuicVersionsWithTls(); + // Create an encrypted packet for testing. // If versions == nullptr, uses &AllSupportedVersions(). // Note that the packet is encrypted with NullEncrypter, so to decrypt the @@ -135,8 +148,13 @@ QuicEncryptedPacket* ConstructEncryptedPacket( uint64_t packet_number, const std::string& data); -// Constructs a received packet for testing. The caller must take ownership of -// the returned pointer. +// Creates a client-to-server ZERO-RTT packet that will fail to decrypt. +std::unique_ptr<QuicEncryptedPacket> GetUndecryptableEarlyPacket( + const ParsedQuicVersion& version, + const QuicConnectionId& server_connection_id); + +// Constructs a received packet for testing. The caller must take ownership +// of the returned pointer. QuicReceivedPacket* ConstructReceivedPacket( const QuicEncryptedPacket& encrypted_packet, QuicTime receipt_time); @@ -251,63 +269,141 @@ class MockFramerVisitor : public QuicFramerVisitorInterface { MockFramerVisitor& operator=(const MockFramerVisitor&) = delete; ~MockFramerVisitor() override; - MOCK_METHOD1(OnError, void(QuicFramer* framer)); + MOCK_METHOD(void, OnError, (QuicFramer*), (override)); // The constructor sets this up to return false by default. - MOCK_METHOD1(OnProtocolVersionMismatch, bool(ParsedQuicVersion version)); - MOCK_METHOD0(OnPacket, void()); - MOCK_METHOD1(OnPublicResetPacket, void(const QuicPublicResetPacket& header)); - MOCK_METHOD1(OnVersionNegotiationPacket, - void(const QuicVersionNegotiationPacket& packet)); - MOCK_METHOD5(OnRetryPacket, - void(QuicConnectionId original_connection_id, - QuicConnectionId new_connection_id, - quiche::QuicheStringPiece retry_token, - quiche::QuicheStringPiece retry_integrity_tag, - quiche::QuicheStringPiece retry_without_tag)); + MOCK_METHOD(bool, + OnProtocolVersionMismatch, + (ParsedQuicVersion version), + (override)); + MOCK_METHOD(void, OnPacket, (), (override)); + MOCK_METHOD(void, + OnPublicResetPacket, + (const QuicPublicResetPacket& header), + (override)); + MOCK_METHOD(void, + OnVersionNegotiationPacket, + (const QuicVersionNegotiationPacket& packet), + (override)); + MOCK_METHOD(void, + OnRetryPacket, + (QuicConnectionId original_connection_id, + QuicConnectionId new_connection_id, + quiche::QuicheStringPiece retry_token, + quiche::QuicheStringPiece retry_integrity_tag, + quiche::QuicheStringPiece retry_without_tag), + (override)); // The constructor sets this up to return true by default. - MOCK_METHOD1(OnUnauthenticatedHeader, bool(const QuicPacketHeader& header)); + MOCK_METHOD(bool, + OnUnauthenticatedHeader, + (const QuicPacketHeader& header), + (override)); // The constructor sets this up to return true by default. - MOCK_METHOD1(OnUnauthenticatedPublicHeader, - bool(const QuicPacketHeader& header)); - MOCK_METHOD1(OnDecryptedPacket, void(EncryptionLevel level)); - MOCK_METHOD1(OnPacketHeader, bool(const QuicPacketHeader& header)); - MOCK_METHOD1(OnCoalescedPacket, void(const QuicEncryptedPacket& packet)); - MOCK_METHOD3(OnUndecryptablePacket, - void(const QuicEncryptedPacket& packet, - EncryptionLevel decryption_level, - bool has_decryption_key)); - MOCK_METHOD1(OnStreamFrame, bool(const QuicStreamFrame& frame)); - MOCK_METHOD1(OnCryptoFrame, bool(const QuicCryptoFrame& frame)); - MOCK_METHOD2(OnAckFrameStart, bool(QuicPacketNumber, QuicTime::Delta)); - MOCK_METHOD2(OnAckRange, bool(QuicPacketNumber, QuicPacketNumber)); - MOCK_METHOD2(OnAckTimestamp, bool(QuicPacketNumber, QuicTime)); - MOCK_METHOD1(OnAckFrameEnd, bool(QuicPacketNumber)); - MOCK_METHOD1(OnStopWaitingFrame, bool(const QuicStopWaitingFrame& frame)); - MOCK_METHOD1(OnPaddingFrame, bool(const QuicPaddingFrame& frame)); - MOCK_METHOD1(OnPingFrame, bool(const QuicPingFrame& frame)); - MOCK_METHOD1(OnRstStreamFrame, bool(const QuicRstStreamFrame& frame)); - MOCK_METHOD1(OnConnectionCloseFrame, - bool(const QuicConnectionCloseFrame& frame)); - MOCK_METHOD1(OnNewConnectionIdFrame, - bool(const QuicNewConnectionIdFrame& frame)); - MOCK_METHOD1(OnRetireConnectionIdFrame, - bool(const QuicRetireConnectionIdFrame& frame)); - MOCK_METHOD1(OnNewTokenFrame, bool(const QuicNewTokenFrame& frame)); - MOCK_METHOD1(OnStopSendingFrame, bool(const QuicStopSendingFrame& frame)); - MOCK_METHOD1(OnPathChallengeFrame, bool(const QuicPathChallengeFrame& frame)); - MOCK_METHOD1(OnPathResponseFrame, bool(const QuicPathResponseFrame& frame)); - MOCK_METHOD1(OnGoAwayFrame, bool(const QuicGoAwayFrame& frame)); - MOCK_METHOD1(OnMaxStreamsFrame, bool(const QuicMaxStreamsFrame& frame)); - MOCK_METHOD1(OnStreamsBlockedFrame, - bool(const QuicStreamsBlockedFrame& frame)); - MOCK_METHOD1(OnWindowUpdateFrame, bool(const QuicWindowUpdateFrame& frame)); - MOCK_METHOD1(OnBlockedFrame, bool(const QuicBlockedFrame& frame)); - MOCK_METHOD1(OnMessageFrame, bool(const QuicMessageFrame& frame)); - MOCK_METHOD1(OnHandshakeDoneFrame, bool(const QuicHandshakeDoneFrame& frame)); - MOCK_METHOD0(OnPacketComplete, void()); - MOCK_CONST_METHOD1(IsValidStatelessResetToken, bool(QuicUint128)); - MOCK_METHOD1(OnAuthenticatedIetfStatelessResetPacket, - void(const QuicIetfStatelessResetPacket&)); + MOCK_METHOD(bool, + OnUnauthenticatedPublicHeader, + (const QuicPacketHeader& header), + (override)); + MOCK_METHOD(void, OnDecryptedPacket, (EncryptionLevel level), (override)); + MOCK_METHOD(bool, + OnPacketHeader, + (const QuicPacketHeader& header), + (override)); + MOCK_METHOD(void, + OnCoalescedPacket, + (const QuicEncryptedPacket& packet), + (override)); + MOCK_METHOD(void, + OnUndecryptablePacket, + (const QuicEncryptedPacket& packet, + EncryptionLevel decryption_level, + bool has_decryption_key), + (override)); + MOCK_METHOD(bool, OnStreamFrame, (const QuicStreamFrame& frame), (override)); + MOCK_METHOD(bool, OnCryptoFrame, (const QuicCryptoFrame& frame), (override)); + MOCK_METHOD(bool, + OnAckFrameStart, + (QuicPacketNumber, QuicTime::Delta), + (override)); + MOCK_METHOD(bool, + OnAckRange, + (QuicPacketNumber, QuicPacketNumber), + (override)); + MOCK_METHOD(bool, OnAckTimestamp, (QuicPacketNumber, QuicTime), (override)); + MOCK_METHOD(bool, OnAckFrameEnd, (QuicPacketNumber), (override)); + MOCK_METHOD(bool, + OnStopWaitingFrame, + (const QuicStopWaitingFrame& frame), + (override)); + MOCK_METHOD(bool, + OnPaddingFrame, + (const QuicPaddingFrame& frame), + (override)); + MOCK_METHOD(bool, OnPingFrame, (const QuicPingFrame& frame), (override)); + MOCK_METHOD(bool, + OnRstStreamFrame, + (const QuicRstStreamFrame& frame), + (override)); + MOCK_METHOD(bool, + OnConnectionCloseFrame, + (const QuicConnectionCloseFrame& frame), + (override)); + MOCK_METHOD(bool, + OnNewConnectionIdFrame, + (const QuicNewConnectionIdFrame& frame), + (override)); + MOCK_METHOD(bool, + OnRetireConnectionIdFrame, + (const QuicRetireConnectionIdFrame& frame), + (override)); + MOCK_METHOD(bool, + OnNewTokenFrame, + (const QuicNewTokenFrame& frame), + (override)); + MOCK_METHOD(bool, + OnStopSendingFrame, + (const QuicStopSendingFrame& frame), + (override)); + MOCK_METHOD(bool, + OnPathChallengeFrame, + (const QuicPathChallengeFrame& frame), + (override)); + MOCK_METHOD(bool, + OnPathResponseFrame, + (const QuicPathResponseFrame& frame), + (override)); + MOCK_METHOD(bool, OnGoAwayFrame, (const QuicGoAwayFrame& frame), (override)); + MOCK_METHOD(bool, + OnMaxStreamsFrame, + (const QuicMaxStreamsFrame& frame), + (override)); + MOCK_METHOD(bool, + OnStreamsBlockedFrame, + (const QuicStreamsBlockedFrame& frame), + (override)); + MOCK_METHOD(bool, + OnWindowUpdateFrame, + (const QuicWindowUpdateFrame& frame), + (override)); + MOCK_METHOD(bool, + OnBlockedFrame, + (const QuicBlockedFrame& frame), + (override)); + MOCK_METHOD(bool, + OnMessageFrame, + (const QuicMessageFrame& frame), + (override)); + MOCK_METHOD(bool, + OnHandshakeDoneFrame, + (const QuicHandshakeDoneFrame& frame), + (override)); + MOCK_METHOD(void, OnPacketComplete, (), (override)); + MOCK_METHOD(bool, + IsValidStatelessResetToken, + (QuicUint128), + (const, override)); + MOCK_METHOD(void, + OnAuthenticatedIetfStatelessResetPacket, + (const QuicIetfStatelessResetPacket&), + (override)); }; class NoOpFramerVisitor : public QuicFramerVisitorInterface { @@ -377,44 +473,70 @@ class MockQuicConnectionVisitor : public QuicConnectionVisitorInterface { delete; ~MockQuicConnectionVisitor() override; - MOCK_METHOD1(OnStreamFrame, void(const QuicStreamFrame& frame)); - MOCK_METHOD1(OnCryptoFrame, void(const QuicCryptoFrame& frame)); - MOCK_METHOD1(OnWindowUpdateFrame, void(const QuicWindowUpdateFrame& frame)); - MOCK_METHOD1(OnBlockedFrame, void(const QuicBlockedFrame& frame)); - MOCK_METHOD1(OnRstStream, void(const QuicRstStreamFrame& frame)); - MOCK_METHOD1(OnGoAway, void(const QuicGoAwayFrame& frame)); - MOCK_METHOD1(OnMessageReceived, void(quiche::QuicheStringPiece message)); - MOCK_METHOD0(OnHandshakeDoneReceived, void()); - MOCK_METHOD2(OnConnectionClosed, - void(const QuicConnectionCloseFrame& frame, - ConnectionCloseSource source)); - MOCK_METHOD0(OnWriteBlocked, void()); - MOCK_METHOD0(OnCanWrite, void()); - MOCK_METHOD0(SendProbingData, bool()); - MOCK_METHOD1(OnCongestionWindowChange, void(QuicTime now)); - MOCK_METHOD1(OnConnectionMigration, void(AddressChangeType type)); - MOCK_METHOD0(OnPathDegrading, void()); - MOCK_CONST_METHOD0(WillingAndAbleToWrite, bool()); - MOCK_CONST_METHOD0(HasPendingHandshake, bool()); - MOCK_CONST_METHOD0(ShouldKeepConnectionAlive, bool()); - MOCK_METHOD1(OnSuccessfulVersionNegotiation, - void(const ParsedQuicVersion& version)); - MOCK_METHOD3(OnPacketReceived, - void(const QuicSocketAddress& self_address, - const QuicSocketAddress& peer_address, - bool is_connectivity_probe)); - MOCK_METHOD0(OnConfigNegotiated, void()); - MOCK_METHOD0(OnAckNeedsRetransmittableFrame, void()); - MOCK_METHOD0(SendPing, void()); - MOCK_CONST_METHOD0(AllowSelfAddressChange, bool()); - MOCK_CONST_METHOD0(GetHandshakeState, HandshakeState()); - MOCK_METHOD0(OnForwardProgressConfirmed, void()); - MOCK_METHOD1(OnMaxStreamsFrame, bool(const QuicMaxStreamsFrame& frame)); - MOCK_METHOD1(OnStreamsBlockedFrame, - bool(const QuicStreamsBlockedFrame& frame)); - MOCK_METHOD1(OnStopSendingFrame, void(const QuicStopSendingFrame& frame)); - MOCK_METHOD1(OnPacketDecrypted, void(EncryptionLevel)); - MOCK_METHOD0(OnOneRttPacketAcknowledged, void()); + MOCK_METHOD(void, OnStreamFrame, (const QuicStreamFrame& frame), (override)); + MOCK_METHOD(void, OnCryptoFrame, (const QuicCryptoFrame& frame), (override)); + MOCK_METHOD(void, + OnWindowUpdateFrame, + (const QuicWindowUpdateFrame& frame), + (override)); + MOCK_METHOD(void, + OnBlockedFrame, + (const QuicBlockedFrame& frame), + (override)); + MOCK_METHOD(void, OnRstStream, (const QuicRstStreamFrame& frame), (override)); + MOCK_METHOD(void, OnGoAway, (const QuicGoAwayFrame& frame), (override)); + MOCK_METHOD(void, + OnMessageReceived, + (quiche::QuicheStringPiece message), + (override)); + MOCK_METHOD(void, OnHandshakeDoneReceived, (), (override)); + MOCK_METHOD(void, + OnConnectionClosed, + (const QuicConnectionCloseFrame& frame, + ConnectionCloseSource source), + (override)); + MOCK_METHOD(void, OnWriteBlocked, (), (override)); + MOCK_METHOD(void, OnCanWrite, (), (override)); + MOCK_METHOD(bool, SendProbingData, (), (override)); + MOCK_METHOD(void, OnCongestionWindowChange, (QuicTime now), (override)); + MOCK_METHOD(void, + OnConnectionMigration, + (AddressChangeType type), + (override)); + MOCK_METHOD(void, OnPathDegrading, (), (override)); + MOCK_METHOD(bool, WillingAndAbleToWrite, (), (const, override)); + MOCK_METHOD(bool, HasPendingHandshake, (), (const, override)); + MOCK_METHOD(bool, ShouldKeepConnectionAlive, (), (const, override)); + MOCK_METHOD(void, + OnSuccessfulVersionNegotiation, + (const ParsedQuicVersion& version), + (override)); + MOCK_METHOD(void, + OnPacketReceived, + (const QuicSocketAddress& self_address, + const QuicSocketAddress& peer_address, + bool is_connectivity_probe), + (override)); + MOCK_METHOD(void, OnAckNeedsRetransmittableFrame, (), (override)); + MOCK_METHOD(void, SendPing, (), (override)); + MOCK_METHOD(bool, AllowSelfAddressChange, (), (const, override)); + MOCK_METHOD(HandshakeState, GetHandshakeState, (), (const, override)); + MOCK_METHOD(void, OnForwardProgressConfirmed, (), (override)); + MOCK_METHOD(bool, + OnMaxStreamsFrame, + (const QuicMaxStreamsFrame& frame), + (override)); + MOCK_METHOD(bool, + OnStreamsBlockedFrame, + (const QuicStreamsBlockedFrame& frame), + (override)); + MOCK_METHOD(void, + OnStopSendingFrame, + (const QuicStopSendingFrame& frame), + (override)); + MOCK_METHOD(void, OnPacketDecrypted, (EncryptionLevel), (override)); + MOCK_METHOD(void, OnOneRttPacketAcknowledged, (), (override)); + MOCK_METHOD(void, OnHandshakePacketSent, (), (override)); }; class MockQuicConnectionHelper : public QuicConnectionHelperInterface { @@ -499,50 +621,53 @@ class MockQuicConnection : public QuicConnection { // will advance the time of the MockClock. void AdvanceTime(QuicTime::Delta delta); - MOCK_METHOD3(ProcessUdpPacket, - void(const QuicSocketAddress& self_address, - const QuicSocketAddress& peer_address, - const QuicReceivedPacket& packet)); - MOCK_METHOD1(SendConnectionClose, void(QuicErrorCode error)); - MOCK_METHOD3(CloseConnection, - void(QuicErrorCode error, - const std::string& details, - ConnectionCloseBehavior connection_close_behavior)); - MOCK_METHOD2(SendConnectionClosePacket, - void(QuicErrorCode error, const std::string& details)); - MOCK_METHOD3(SendRstStream, - void(QuicStreamId id, - QuicRstStreamErrorCode error, - QuicStreamOffset bytes_written)); - MOCK_METHOD3(SendGoAway, - void(QuicErrorCode error, - QuicStreamId last_good_stream_id, - const std::string& reason)); - MOCK_METHOD1(SendBlocked, void(QuicStreamId id)); - MOCK_METHOD2(SendWindowUpdate, - void(QuicStreamId id, QuicStreamOffset byte_offset)); - MOCK_METHOD0(OnCanWrite, void()); - MOCK_METHOD1(SendConnectivityProbingResponsePacket, - void(const QuicSocketAddress& peer_address)); - MOCK_METHOD2(SendConnectivityProbingPacket, - bool(QuicPacketWriter* probing_writer, - const QuicSocketAddress& peer_address)); - - MOCK_METHOD1(OnSendConnectionState, void(const CachedNetworkParameters&)); - MOCK_METHOD2(ResumeConnectionState, - void(const CachedNetworkParameters&, bool)); - MOCK_METHOD1(SetMaxPacingRate, void(QuicBandwidth)); - - MOCK_METHOD2(OnStreamReset, void(QuicStreamId, QuicRstStreamErrorCode)); - MOCK_METHOD1(SendControlFrame, bool(const QuicFrame& frame)); - MOCK_METHOD3(SendMessage, - MessageStatus(QuicMessageId, QuicMemSliceSpan, bool)); - MOCK_METHOD3(OnConnectionClosed, - void(QuicErrorCode error, - const std::string& error_details, - ConnectionCloseSource source)); - - MOCK_METHOD1(OnError, void(QuicFramer* framer)); + MOCK_METHOD(void, + ProcessUdpPacket, + (const QuicSocketAddress& self_address, + const QuicSocketAddress& peer_address, + const QuicReceivedPacket& packet), + (override)); + MOCK_METHOD(void, + CloseConnection, + (QuicErrorCode error, + const std::string& details, + ConnectionCloseBehavior connection_close_behavior), + (override)); + MOCK_METHOD(void, + SendConnectionClosePacket, + (QuicErrorCode error, const std::string& details), + (override)); + MOCK_METHOD(void, OnCanWrite, (), (override)); + MOCK_METHOD(void, + SendConnectivityProbingResponsePacket, + (const QuicSocketAddress& peer_address), + (override)); + MOCK_METHOD(bool, + SendConnectivityProbingPacket, + (QuicPacketWriter*, const QuicSocketAddress& peer_address), + (override)); + + MOCK_METHOD(void, + OnSendConnectionState, + (const CachedNetworkParameters&), + (override)); + MOCK_METHOD(void, + ResumeConnectionState, + (const CachedNetworkParameters&, bool), + (override)); + MOCK_METHOD(void, SetMaxPacingRate, (QuicBandwidth), (override)); + + MOCK_METHOD(void, + OnStreamReset, + (QuicStreamId, QuicRstStreamErrorCode), + (override)); + MOCK_METHOD(bool, SendControlFrame, (const QuicFrame& frame), (override)); + MOCK_METHOD(MessageStatus, + SendMessage, + (QuicMessageId, QuicMemSliceSpan, bool), + (override)); + + MOCK_METHOD(void, OnError, (QuicFramer*), (override)); void QuicConnection_OnError(QuicFramer* framer) { QuicConnection::OnError(framer); } @@ -577,10 +702,18 @@ class MockQuicConnection : public QuicConnection { const QuicSocketAddress& peer_address) { QuicConnection::SendConnectivityProbingResponsePacket(peer_address); } - MOCK_METHOD1(OnPathResponseFrame, bool(const QuicPathResponseFrame&)); - MOCK_METHOD1(OnStopSendingFrame, bool(const QuicStopSendingFrame& frame)); - MOCK_METHOD3(SendCryptoData, - size_t(EncryptionLevel, size_t, QuicStreamOffset)); + MOCK_METHOD(bool, + OnPathResponseFrame, + (const QuicPathResponseFrame&), + (override)); + MOCK_METHOD(bool, + OnStopSendingFrame, + (const QuicStopSendingFrame& frame), + (override)); + MOCK_METHOD(size_t, + SendCryptoData, + (EncryptionLevel, size_t, QuicStreamOffset), + (override)); size_t QuicConnection_SendCryptoData(EncryptionLevel level, size_t write_length, QuicStreamOffset offset) { @@ -603,7 +736,7 @@ class PacketSavingConnection : public MockQuicConnection { ~PacketSavingConnection() override; - void SendOrQueuePacket(SerializedPacket* packet) override; + void SendOrQueuePacket(SerializedPacket packet) override; std::vector<std::unique_ptr<QuicEncryptedPacket>> encrypted_packets_; MockClock clock_; @@ -624,43 +757,47 @@ class MockQuicSession : public QuicSession { const QuicCryptoStream* GetCryptoStream() const override; void SetCryptoStream(QuicCryptoStream* crypto_stream); - MOCK_METHOD2(OnConnectionClosed, - void(const QuicConnectionCloseFrame& frame, - ConnectionCloseSource source)); - MOCK_METHOD1(CreateIncomingStream, QuicStream*(QuicStreamId id)); - MOCK_METHOD1(CreateIncomingStream, QuicSpdyStream*(PendingStream* stream)); - MOCK_METHOD1(ShouldCreateIncomingStream2, bool(QuicStreamId id)); - MOCK_METHOD0(ShouldCreateOutgoingBidirectionalStream, bool()); - MOCK_METHOD0(ShouldCreateOutgoingUnidirectionalStream, bool()); - MOCK_METHOD6(WritevData, - QuicConsumedData(QuicStreamId id, - size_t write_length, - QuicStreamOffset offset, - StreamSendingState state, - TransmissionType type, - quiche::QuicheOptional<EncryptionLevel> level)); - - MOCK_METHOD3(SendRstStream, - void(QuicStreamId stream_id, - QuicRstStreamErrorCode error, - QuicStreamOffset bytes_written)); - - MOCK_METHOD2(OnStreamHeaders, - void(QuicStreamId stream_id, - quiche::QuicheStringPiece headers_data)); - MOCK_METHOD2(OnStreamHeadersPriority, - void(QuicStreamId stream_id, spdy::SpdyPriority priority)); - MOCK_METHOD3(OnStreamHeadersComplete, - void(QuicStreamId stream_id, bool fin, size_t frame_len)); - MOCK_CONST_METHOD0(ShouldKeepConnectionAlive, bool()); - MOCK_METHOD2(SendStopSending, void(uint16_t code, QuicStreamId stream_id)); - MOCK_CONST_METHOD0(GetAlpnsToOffer, std::vector<std::string>()); - MOCK_CONST_METHOD1(SelectAlpn, - std::vector<quiche::QuicheStringPiece>::const_iterator( - const std::vector<quiche::QuicheStringPiece>&)); - MOCK_METHOD1(OnAlpnSelected, void(quiche::QuicheStringPiece)); + MOCK_METHOD(void, + OnConnectionClosed, + (const QuicConnectionCloseFrame& frame, + ConnectionCloseSource source), + (override)); + MOCK_METHOD(QuicStream*, CreateIncomingStream, (QuicStreamId id), (override)); + MOCK_METHOD(QuicSpdyStream*, + CreateIncomingStream, + (PendingStream*), + (override)); + MOCK_METHOD(QuicConsumedData, + WritevData, + (QuicStreamId id, + size_t write_length, + QuicStreamOffset offset, + StreamSendingState state, + TransmissionType type, + quiche::QuicheOptional<EncryptionLevel> level), + (override)); + + MOCK_METHOD(void, + SendRstStream, + (QuicStreamId stream_id, + QuicRstStreamErrorCode error, + QuicStreamOffset bytes_written), + (override)); + + MOCK_METHOD(bool, ShouldKeepConnectionAlive, (), (const, override)); + MOCK_METHOD(void, + SendStopSending, + (uint16_t code, QuicStreamId stream_id), + (override)); + MOCK_METHOD(std::vector<std::string>, GetAlpnsToOffer, (), (const, override)); + MOCK_METHOD(std::vector<quiche::QuicheStringPiece>::const_iterator, + SelectAlpn, + (const std::vector<quiche::QuicheStringPiece>&), + (const, override)); + MOCK_METHOD(void, OnAlpnSelected, (quiche::QuicheStringPiece), (override)); using QuicSession::ActivateStream; + using QuicSession::GetNumDrainingStreams; // Returns a QuicConsumedData that indicates all of |write_length| (and |fin| // if set) has been consumed. @@ -694,6 +831,7 @@ class MockQuicCryptoStream : public QuicCryptoStream { CryptoMessageParser* crypto_message_parser() override; void OnPacketDecrypted(EncryptionLevel /*level*/) override {} void OnOneRttPacketAcknowledged() override {} + void OnHandshakePacketSent() override {} void OnHandshakeDoneReceived() override {} HandshakeState GetHandshakeState() const override { return HANDSHAKE_START; } @@ -723,62 +861,73 @@ class MockQuicSpdySession : public QuicSpdySession { } // From QuicSession. - MOCK_METHOD2(OnConnectionClosed, - void(const QuicConnectionCloseFrame& frame, - ConnectionCloseSource source)); - MOCK_METHOD1(CreateIncomingStream, QuicSpdyStream*(QuicStreamId id)); - MOCK_METHOD1(CreateIncomingStream, QuicSpdyStream*(PendingStream* stream)); - MOCK_METHOD0(CreateOutgoingBidirectionalStream, QuicSpdyStream*()); - MOCK_METHOD0(CreateOutgoingUnidirectionalStream, QuicSpdyStream*()); - MOCK_METHOD1(ShouldCreateIncomingStream, bool(QuicStreamId id)); - MOCK_METHOD0(ShouldCreateOutgoingBidirectionalStream, bool()); - MOCK_METHOD0(ShouldCreateOutgoingUnidirectionalStream, bool()); - MOCK_METHOD6(WritevData, - QuicConsumedData(QuicStreamId id, - size_t write_length, - QuicStreamOffset offset, - StreamSendingState state, - TransmissionType type, - quiche::QuicheOptional<EncryptionLevel> level)); - - MOCK_METHOD3(SendRstStream, - void(QuicStreamId stream_id, - QuicRstStreamErrorCode error, - QuicStreamOffset bytes_written)); - - MOCK_METHOD2(OnStreamHeaders, - void(QuicStreamId stream_id, - quiche::QuicheStringPiece headers_data)); - MOCK_METHOD2(OnStreamHeadersPriority, - void(QuicStreamId stream_id, - const spdy::SpdyStreamPrecedence& precedence)); - MOCK_METHOD3(OnStreamHeadersComplete, - void(QuicStreamId stream_id, bool fin, size_t frame_len)); - MOCK_METHOD4(OnStreamHeaderList, - void(QuicStreamId stream_id, - bool fin, - size_t frame_len, - const QuicHeaderList& header_list)); - MOCK_METHOD2(OnPromiseHeaders, - void(QuicStreamId stream_id, - quiche::QuicheStringPiece headers_data)); - MOCK_METHOD3(OnPromiseHeadersComplete, - void(QuicStreamId stream_id, - QuicStreamId promised_stream_id, - size_t frame_len)); - MOCK_METHOD4(OnPromiseHeaderList, - void(QuicStreamId stream_id, - QuicStreamId promised_stream_id, - size_t frame_len, - const QuicHeaderList& header_list)); - MOCK_METHOD2(OnPriorityFrame, - void(QuicStreamId id, - const spdy::SpdyStreamPrecedence& precedence)); - - MOCK_METHOD1(OnHeadersHeadOfLineBlocking, void(QuicTime::Delta delta)); - MOCK_METHOD4( - OnStreamFrameData, - void(QuicStreamId stream_id, const char* data, size_t len, bool fin)); + MOCK_METHOD(void, + OnConnectionClosed, + (const QuicConnectionCloseFrame& frame, + ConnectionCloseSource source), + (override)); + MOCK_METHOD(QuicSpdyStream*, + CreateIncomingStream, + (QuicStreamId id), + (override)); + MOCK_METHOD(QuicSpdyStream*, + CreateIncomingStream, + (PendingStream*), + (override)); + MOCK_METHOD(QuicSpdyStream*, + CreateOutgoingBidirectionalStream, + (), + (override)); + MOCK_METHOD(QuicSpdyStream*, + CreateOutgoingUnidirectionalStream, + (), + (override)); + MOCK_METHOD(bool, ShouldCreateIncomingStream, (QuicStreamId id), (override)); + MOCK_METHOD(bool, ShouldCreateOutgoingBidirectionalStream, (), (override)); + MOCK_METHOD(bool, ShouldCreateOutgoingUnidirectionalStream, (), (override)); + MOCK_METHOD(QuicConsumedData, + WritevData, + (QuicStreamId id, + size_t write_length, + QuicStreamOffset offset, + StreamSendingState state, + TransmissionType type, + quiche::QuicheOptional<EncryptionLevel> level), + (override)); + MOCK_METHOD(void, + SendRstStream, + (QuicStreamId stream_id, + QuicRstStreamErrorCode error, + QuicStreamOffset bytes_written), + (override)); + MOCK_METHOD(void, + SendWindowUpdate, + (QuicStreamId id, QuicStreamOffset byte_offset), + (override)); + MOCK_METHOD(void, SendBlocked, (QuicStreamId id), (override)); + MOCK_METHOD(void, + OnStreamHeadersPriority, + (QuicStreamId stream_id, + const spdy::SpdyStreamPrecedence& precedence), + (override)); + MOCK_METHOD(void, + OnStreamHeaderList, + (QuicStreamId stream_id, + bool fin, + size_t frame_len, + const QuicHeaderList& header_list), + (override)); + MOCK_METHOD(void, + OnPromiseHeaderList, + (QuicStreamId stream_id, + QuicStreamId promised_stream_id, + size_t frame_len, + const QuicHeaderList& header_list), + (override)); + MOCK_METHOD(void, + OnPriorityFrame, + (QuicStreamId id, const spdy::SpdyStreamPrecedence& precedence), + (override)); // Returns a QuicConsumedData that indicates all of |write_length| (and |fin| // if set) has been consumed. @@ -797,39 +946,79 @@ class MockQuicSpdySession : public QuicSpdySession { class MockHttp3DebugVisitor : public Http3DebugVisitor { public: - MOCK_METHOD1(OnControlStreamCreated, void(QuicStreamId)); - MOCK_METHOD1(OnQpackEncoderStreamCreated, void(QuicStreamId)); - MOCK_METHOD1(OnQpackDecoderStreamCreated, void(QuicStreamId)); - MOCK_METHOD1(OnPeerControlStreamCreated, void(QuicStreamId)); - MOCK_METHOD1(OnPeerQpackEncoderStreamCreated, void(QuicStreamId)); - MOCK_METHOD1(OnPeerQpackDecoderStreamCreated, void(QuicStreamId)); - - MOCK_METHOD1(OnCancelPushFrameReceived, void(const CancelPushFrame&)); - MOCK_METHOD1(OnSettingsFrameReceived, void(const SettingsFrame&)); - MOCK_METHOD1(OnGoAwayFrameReceived, void(const GoAwayFrame&)); - MOCK_METHOD1(OnMaxPushIdFrameReceived, void(const MaxPushIdFrame&)); - MOCK_METHOD1(OnPriorityUpdateFrameReceived, void(const PriorityUpdateFrame&)); - - MOCK_METHOD2(OnDataFrameReceived, void(QuicStreamId, QuicByteCount)); - MOCK_METHOD2(OnHeadersFrameReceived, void(QuicStreamId, QuicByteCount)); - MOCK_METHOD2(OnHeadersDecoded, void(QuicStreamId, QuicHeaderList)); - MOCK_METHOD3(OnPushPromiseFrameReceived, - void(QuicStreamId, QuicStreamId, QuicByteCount)); - MOCK_METHOD3(OnPushPromiseDecoded, - void(QuicStreamId, QuicStreamId, QuicHeaderList)); - MOCK_METHOD3(OnUnknownFrameReceived, - void(QuicStreamId, uint64_t, QuicByteCount)); - - MOCK_METHOD1(OnSettingsFrameSent, void(const SettingsFrame&)); - MOCK_METHOD1(OnGoAwayFrameSent, void(QuicStreamId)); - MOCK_METHOD1(OnMaxPushIdFrameSent, void(const MaxPushIdFrame&)); - MOCK_METHOD1(OnPriorityUpdateFrameSent, void(const PriorityUpdateFrame&)); - - MOCK_METHOD2(OnDataFrameSent, void(QuicStreamId, QuicByteCount)); - MOCK_METHOD2(OnHeadersFrameSent, - void(QuicStreamId, const spdy::SpdyHeaderBlock&)); - MOCK_METHOD3(OnPushPromiseFrameSent, - void(QuicStreamId, QuicStreamId, const spdy::SpdyHeaderBlock&)); + MOCK_METHOD(void, OnControlStreamCreated, (QuicStreamId), (override)); + MOCK_METHOD(void, OnQpackEncoderStreamCreated, (QuicStreamId), (override)); + MOCK_METHOD(void, OnQpackDecoderStreamCreated, (QuicStreamId), (override)); + MOCK_METHOD(void, OnPeerControlStreamCreated, (QuicStreamId), (override)); + MOCK_METHOD(void, + OnPeerQpackEncoderStreamCreated, + (QuicStreamId), + (override)); + MOCK_METHOD(void, + OnPeerQpackDecoderStreamCreated, + (QuicStreamId), + (override)); + + MOCK_METHOD(void, + OnCancelPushFrameReceived, + (const CancelPushFrame&), + (override)); + MOCK_METHOD(void, + OnSettingsFrameReceived, + (const SettingsFrame&), + (override)); + MOCK_METHOD(void, OnGoAwayFrameReceived, (const GoAwayFrame&), (override)); + MOCK_METHOD(void, + OnMaxPushIdFrameReceived, + (const MaxPushIdFrame&), + (override)); + MOCK_METHOD(void, + OnPriorityUpdateFrameReceived, + (const PriorityUpdateFrame&), + (override)); + + MOCK_METHOD(void, + OnDataFrameReceived, + (QuicStreamId, QuicByteCount), + (override)); + MOCK_METHOD(void, + OnHeadersFrameReceived, + (QuicStreamId, QuicByteCount), + (override)); + MOCK_METHOD(void, + OnHeadersDecoded, + (QuicStreamId, QuicHeaderList), + (override)); + MOCK_METHOD(void, + OnPushPromiseFrameReceived, + (QuicStreamId, QuicStreamId, QuicByteCount), + (override)); + MOCK_METHOD(void, + OnPushPromiseDecoded, + (QuicStreamId, QuicStreamId, QuicHeaderList), + (override)); + MOCK_METHOD(void, + OnUnknownFrameReceived, + (QuicStreamId, uint64_t, QuicByteCount), + (override)); + + MOCK_METHOD(void, OnSettingsFrameSent, (const SettingsFrame&), (override)); + MOCK_METHOD(void, OnGoAwayFrameSent, (QuicStreamId), (override)); + MOCK_METHOD(void, OnMaxPushIdFrameSent, (const MaxPushIdFrame&), (override)); + MOCK_METHOD(void, + OnPriorityUpdateFrameSent, + (const PriorityUpdateFrame&), + (override)); + + MOCK_METHOD(void, OnDataFrameSent, (QuicStreamId, QuicByteCount), (override)); + MOCK_METHOD(void, + OnHeadersFrameSent, + (QuicStreamId, const spdy::SpdyHeaderBlock&), + (override)); + MOCK_METHOD(void, + OnPushPromiseFrameSent, + (QuicStreamId, QuicStreamId, const spdy::SpdyHeaderBlock&), + (override)); }; class TestQuicSpdyServerSession : public QuicServerSessionBase { @@ -845,13 +1034,27 @@ class TestQuicSpdyServerSession : public QuicServerSessionBase { delete; ~TestQuicSpdyServerSession() override; - MOCK_METHOD1(CreateIncomingStream, QuicSpdyStream*(QuicStreamId id)); - MOCK_METHOD1(CreateIncomingStream, QuicSpdyStream*(PendingStream* stream)); - MOCK_METHOD0(CreateOutgoingBidirectionalStream, QuicSpdyStream*()); - MOCK_METHOD0(CreateOutgoingUnidirectionalStream, QuicSpdyStream*()); - MOCK_CONST_METHOD1(SelectAlpn, - std::vector<quiche::QuicheStringPiece>::const_iterator( - const std::vector<quiche::QuicheStringPiece>&)); + MOCK_METHOD(QuicSpdyStream*, + CreateIncomingStream, + (QuicStreamId id), + (override)); + MOCK_METHOD(QuicSpdyStream*, + CreateIncomingStream, + (PendingStream*), + (override)); + MOCK_METHOD(QuicSpdyStream*, + CreateOutgoingBidirectionalStream, + (), + (override)); + MOCK_METHOD(QuicSpdyStream*, + CreateOutgoingUnidirectionalStream, + (), + (override)); + MOCK_METHOD(std::vector<quiche::QuicheStringPiece>::const_iterator, + SelectAlpn, + (const std::vector<quiche::QuicheStringPiece>&), + (const, override)); + MOCK_METHOD(void, OnAlpnSelected, (quiche::QuicheStringPiece), (override)); std::unique_ptr<QuicCryptoServerStreamBase> CreateQuicCryptoServerStream( const QuicCryptoServerConfig* crypto_config, QuicCompressedCertsCache* compressed_certs_cache) override; @@ -904,20 +1107,37 @@ class TestQuicSpdyClientSession : public QuicSpdyClientSessionBase { bool IsAuthorized(const std::string& authority) override; // QuicSpdyClientSessionBase - MOCK_METHOD1(OnProofValid, - void(const QuicCryptoClientConfig::CachedState& cached)); - MOCK_METHOD1(OnProofVerifyDetailsAvailable, - void(const ProofVerifyDetails& verify_details)); + MOCK_METHOD(void, + OnProofValid, + (const QuicCryptoClientConfig::CachedState& cached), + (override)); + MOCK_METHOD(void, + OnProofVerifyDetailsAvailable, + (const ProofVerifyDetails& verify_details), + (override)); // TestQuicSpdyClientSession - MOCK_METHOD1(CreateIncomingStream, QuicSpdyStream*(QuicStreamId id)); - MOCK_METHOD1(CreateIncomingStream, QuicSpdyStream*(PendingStream* stream)); - MOCK_METHOD0(CreateOutgoingBidirectionalStream, QuicSpdyStream*()); - MOCK_METHOD0(CreateOutgoingUnidirectionalStream, QuicSpdyStream*()); - MOCK_METHOD1(ShouldCreateIncomingStream, bool(QuicStreamId id)); - MOCK_METHOD0(ShouldCreateOutgoingBidirectionalStream, bool()); - MOCK_METHOD0(ShouldCreateOutgoingUnidirectionalStream, bool()); - MOCK_CONST_METHOD0(GetAlpnsToOffer, std::vector<std::string>()); + MOCK_METHOD(QuicSpdyStream*, + CreateIncomingStream, + (QuicStreamId id), + (override)); + MOCK_METHOD(QuicSpdyStream*, + CreateIncomingStream, + (PendingStream*), + (override)); + MOCK_METHOD(QuicSpdyStream*, + CreateOutgoingBidirectionalStream, + (), + (override)); + MOCK_METHOD(QuicSpdyStream*, + CreateOutgoingUnidirectionalStream, + (), + (override)); + MOCK_METHOD(bool, ShouldCreateIncomingStream, (QuicStreamId id), (override)); + MOCK_METHOD(bool, ShouldCreateOutgoingBidirectionalStream, (), (override)); + MOCK_METHOD(bool, ShouldCreateOutgoingUnidirectionalStream, (), (override)); + MOCK_METHOD(std::vector<std::string>, GetAlpnsToOffer, (), (const, override)); + MOCK_METHOD(void, OnAlpnSelected, (quiche::QuicheStringPiece), (override)); QuicCryptoClientStream* GetMutableCryptoStream() override; const QuicCryptoClientStream* GetCryptoStream() const override; @@ -946,22 +1166,28 @@ class MockPacketWriter : public QuicPacketWriter { MockPacketWriter& operator=(const MockPacketWriter&) = delete; ~MockPacketWriter() override; - MOCK_METHOD5(WritePacket, - WriteResult(const char* buffer, - size_t buf_len, - const QuicIpAddress& self_address, - const QuicSocketAddress& peer_address, - PerPacketOptions* options)); - MOCK_CONST_METHOD0(IsWriteBlocked, bool()); - MOCK_METHOD0(SetWritable, void()); - MOCK_CONST_METHOD1(GetMaxPacketSize, - QuicByteCount(const QuicSocketAddress& peer_address)); - MOCK_CONST_METHOD0(SupportsReleaseTime, bool()); - MOCK_CONST_METHOD0(IsBatchMode, bool()); - MOCK_METHOD2(GetNextWriteLocation, - char*(const QuicIpAddress& self_address, - const QuicSocketAddress& peer_address)); - MOCK_METHOD0(Flush, WriteResult()); + MOCK_METHOD(WriteResult, + WritePacket, + (const char*, + size_t buf_len, + const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address, + PerPacketOptions*), + (override)); + MOCK_METHOD(bool, IsWriteBlocked, (), (const, override)); + MOCK_METHOD(void, SetWritable, (), (override)); + MOCK_METHOD(QuicByteCount, + GetMaxPacketSize, + (const QuicSocketAddress& peer_address), + (const, override)); + MOCK_METHOD(bool, SupportsReleaseTime, (), (const, override)); + MOCK_METHOD(bool, IsBatchMode, (), (const, override)); + MOCK_METHOD(char*, + GetNextWriteLocation, + (const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address), + (override)); + MOCK_METHOD(WriteResult, Flush, (), (override)); }; class MockSendAlgorithm : public SendAlgorithmInterface { @@ -971,45 +1197,59 @@ class MockSendAlgorithm : public SendAlgorithmInterface { MockSendAlgorithm& operator=(const MockSendAlgorithm&) = delete; ~MockSendAlgorithm() override; - MOCK_METHOD2(SetFromConfig, - void(const QuicConfig& config, Perspective perspective)); - MOCK_METHOD1(SetInitialCongestionWindowInPackets, - void(QuicPacketCount packets)); - MOCK_METHOD1(SetMaxCongestionWindow, - void(QuicByteCount max_congestion_window)); - MOCK_METHOD5(OnCongestionEvent, - void(bool rtt_updated, - QuicByteCount bytes_in_flight, - QuicTime event_time, - const AckedPacketVector& acked_packets, - const LostPacketVector& lost_packets)); - MOCK_METHOD5(OnPacketSent, - void(QuicTime, - QuicByteCount, - QuicPacketNumber, - QuicByteCount, - HasRetransmittableData)); - MOCK_METHOD1(OnPacketNeutered, void(QuicPacketNumber)); - MOCK_METHOD1(OnRetransmissionTimeout, void(bool)); - MOCK_METHOD0(OnConnectionMigration, void()); - MOCK_METHOD0(RevertRetransmissionTimeout, void()); - MOCK_METHOD1(CanSend, bool(QuicByteCount)); - MOCK_CONST_METHOD1(PacingRate, QuicBandwidth(QuicByteCount)); - MOCK_CONST_METHOD0(BandwidthEstimate, QuicBandwidth(void)); - MOCK_CONST_METHOD0(HasReliableBandwidthEstimate, bool()); - MOCK_METHOD1(OnRttUpdated, void(QuicPacketNumber)); - MOCK_CONST_METHOD0(GetCongestionWindow, QuicByteCount()); - MOCK_CONST_METHOD0(GetDebugState, std::string()); - MOCK_CONST_METHOD0(InSlowStart, bool()); - MOCK_CONST_METHOD0(InRecovery, bool()); - MOCK_CONST_METHOD0(ShouldSendProbingPacket, bool()); - MOCK_CONST_METHOD0(GetSlowStartThreshold, QuicByteCount()); - MOCK_CONST_METHOD0(GetCongestionControlType, CongestionControlType()); - MOCK_METHOD3(AdjustNetworkParameters, - void(QuicBandwidth, QuicTime::Delta, bool)); - MOCK_METHOD1(AdjustNetworkParameters, void(const NetworkParams&)); - MOCK_METHOD1(OnApplicationLimited, void(QuicByteCount)); - MOCK_CONST_METHOD1(PopulateConnectionStats, void(QuicConnectionStats*)); + MOCK_METHOD(void, + SetFromConfig, + (const QuicConfig& config, Perspective perspective), + (override)); + MOCK_METHOD(void, + ApplyConnectionOptions, + (const QuicTagVector& connection_options), + (override)); + MOCK_METHOD(void, + SetInitialCongestionWindowInPackets, + (QuicPacketCount packets), + (override)); + MOCK_METHOD(void, + OnCongestionEvent, + (bool rtt_updated, + QuicByteCount bytes_in_flight, + QuicTime event_time, + const AckedPacketVector& acked_packets, + const LostPacketVector& lost_packets), + (override)); + MOCK_METHOD(void, + OnPacketSent, + (QuicTime, + QuicByteCount, + QuicPacketNumber, + QuicByteCount, + HasRetransmittableData), + (override)); + MOCK_METHOD(void, OnPacketNeutered, (QuicPacketNumber), (override)); + MOCK_METHOD(void, OnRetransmissionTimeout, (bool), (override)); + MOCK_METHOD(void, OnConnectionMigration, (), (override)); + MOCK_METHOD(bool, CanSend, (QuicByteCount), (override)); + MOCK_METHOD(QuicBandwidth, PacingRate, (QuicByteCount), (const, override)); + MOCK_METHOD(QuicBandwidth, BandwidthEstimate, (), (const, override)); + MOCK_METHOD(QuicByteCount, GetCongestionWindow, (), (const, override)); + MOCK_METHOD(std::string, GetDebugState, (), (const, override)); + MOCK_METHOD(bool, InSlowStart, (), (const, override)); + MOCK_METHOD(bool, InRecovery, (), (const, override)); + MOCK_METHOD(bool, ShouldSendProbingPacket, (), (const, override)); + MOCK_METHOD(QuicByteCount, GetSlowStartThreshold, (), (const, override)); + MOCK_METHOD(CongestionControlType, + GetCongestionControlType, + (), + (const, override)); + MOCK_METHOD(void, + AdjustNetworkParameters, + (const NetworkParams&), + (override)); + MOCK_METHOD(void, OnApplicationLimited, (QuicByteCount), (override)); + MOCK_METHOD(void, + PopulateConnectionStats, + (QuicConnectionStats*), + (const, override)); }; class MockLossAlgorithm : public LossDetectionInterface { @@ -1019,24 +1259,33 @@ class MockLossAlgorithm : public LossDetectionInterface { MockLossAlgorithm& operator=(const MockLossAlgorithm&) = delete; ~MockLossAlgorithm() override; - MOCK_METHOD6(DetectLosses, - void(const QuicUnackedPacketMap& unacked_packets, - QuicTime time, - const RttStats& rtt_stats, - QuicPacketNumber largest_recently_acked, - const AckedPacketVector& packets_acked, - LostPacketVector* packets_lost)); - MOCK_CONST_METHOD0(GetLossTimeout, QuicTime()); - MOCK_METHOD5(SpuriousLossDetected, - void(const QuicUnackedPacketMap&, - const RttStats&, - QuicTime, - QuicPacketNumber, - QuicPacketNumber)); - - MOCK_METHOD0(OnConfigNegotiated, void()); - MOCK_METHOD0(OnMinRttAvailable, void()); - MOCK_METHOD0(OnConnectionClosed, void()); + MOCK_METHOD(void, + SetFromConfig, + (const QuicConfig& config, Perspective perspective), + (override)); + + MOCK_METHOD(DetectionStats, + DetectLosses, + (const QuicUnackedPacketMap& unacked_packets, + QuicTime time, + const RttStats& rtt_stats, + QuicPacketNumber largest_recently_acked, + const AckedPacketVector& packets_acked, + LostPacketVector*), + (override)); + MOCK_METHOD(QuicTime, GetLossTimeout, (), (const, override)); + MOCK_METHOD(void, + SpuriousLossDetected, + (const QuicUnackedPacketMap&, + const RttStats&, + QuicTime, + QuicPacketNumber, + QuicPacketNumber), + (override)); + + MOCK_METHOD(void, OnConfigNegotiated, (), (override)); + MOCK_METHOD(void, OnMinRttAvailable, (), (override)); + MOCK_METHOD(void, OnConnectionClosed, (), (override)); }; class MockAckListener : public QuicAckListenerInterface { @@ -1045,10 +1294,15 @@ class MockAckListener : public QuicAckListenerInterface { MockAckListener(const MockAckListener&) = delete; MockAckListener& operator=(const MockAckListener&) = delete; - MOCK_METHOD2(OnPacketAcked, - void(int acked_bytes, QuicTime::Delta ack_delay_time)); + MOCK_METHOD(void, + OnPacketAcked, + (int acked_bytes, QuicTime::Delta ack_delay_time), + (override)); - MOCK_METHOD1(OnPacketRetransmitted, void(int retransmitted_bytes)); + MOCK_METHOD(void, + OnPacketRetransmitted, + (int retransmitted_bytes), + (override)); protected: // Object is ref counted. @@ -1063,8 +1317,8 @@ class MockNetworkChangeVisitor MockNetworkChangeVisitor& operator=(const MockNetworkChangeVisitor&) = delete; ~MockNetworkChangeVisitor() override; - MOCK_METHOD0(OnCongestionChange, void()); - MOCK_METHOD1(OnPathMtuIncreased, void(QuicPacketLength)); + MOCK_METHOD(void, OnCongestionChange, (), (override)); + MOCK_METHOD(void, OnPathMtuIncreased, (QuicPacketLength), (override)); }; class MockQuicConnectionDebugVisitor : public QuicConnectionDebugVisitor { @@ -1072,66 +1326,95 @@ class MockQuicConnectionDebugVisitor : public QuicConnectionDebugVisitor { MockQuicConnectionDebugVisitor(); ~MockQuicConnectionDebugVisitor() override; - MOCK_METHOD1(OnFrameAddedToPacket, void(const QuicFrame&)); - - MOCK_METHOD3(OnPacketSent, - void(const SerializedPacket&, TransmissionType, QuicTime)); + MOCK_METHOD(void, + OnPacketSent, + (const SerializedPacket&, TransmissionType, QuicTime), + (override)); - MOCK_METHOD2(OnCoalescedPacketSent, void(const QuicCoalescedPacket&, size_t)); + MOCK_METHOD(void, + OnCoalescedPacketSent, + (const QuicCoalescedPacket&, size_t), + (override)); - MOCK_METHOD0(OnPingSent, void()); + MOCK_METHOD(void, OnPingSent, (), (override)); - MOCK_METHOD3(OnPacketReceived, - void(const QuicSocketAddress&, - const QuicSocketAddress&, - const QuicEncryptedPacket&)); + MOCK_METHOD(void, + OnPacketReceived, + (const QuicSocketAddress&, + const QuicSocketAddress&, + const QuicEncryptedPacket&), + (override)); - MOCK_METHOD1(OnIncorrectConnectionId, void(QuicConnectionId)); + MOCK_METHOD(void, OnIncorrectConnectionId, (QuicConnectionId), (override)); - MOCK_METHOD1(OnProtocolVersionMismatch, void(ParsedQuicVersion)); + MOCK_METHOD(void, OnProtocolVersionMismatch, (ParsedQuicVersion), (override)); - MOCK_METHOD1(OnPacketHeader, void(const QuicPacketHeader& header)); + MOCK_METHOD(void, + OnPacketHeader, + (const QuicPacketHeader& header), + (override)); - MOCK_METHOD1(OnSuccessfulVersionNegotiation, void(const ParsedQuicVersion&)); + MOCK_METHOD(void, + OnSuccessfulVersionNegotiation, + (const ParsedQuicVersion&), + (override)); - MOCK_METHOD1(OnStreamFrame, void(const QuicStreamFrame&)); + MOCK_METHOD(void, OnStreamFrame, (const QuicStreamFrame&), (override)); - MOCK_METHOD1(OnCryptoFrame, void(const QuicCryptoFrame&)); + MOCK_METHOD(void, OnCryptoFrame, (const QuicCryptoFrame&), (override)); - MOCK_METHOD1(OnStopWaitingFrame, void(const QuicStopWaitingFrame&)); + MOCK_METHOD(void, + OnStopWaitingFrame, + (const QuicStopWaitingFrame&), + (override)); - MOCK_METHOD1(OnRstStreamFrame, void(const QuicRstStreamFrame&)); + MOCK_METHOD(void, OnRstStreamFrame, (const QuicRstStreamFrame&), (override)); - MOCK_METHOD1(OnConnectionCloseFrame, void(const QuicConnectionCloseFrame&)); + MOCK_METHOD(void, + OnConnectionCloseFrame, + (const QuicConnectionCloseFrame&), + (override)); - MOCK_METHOD1(OnBlockedFrame, void(const QuicBlockedFrame&)); + MOCK_METHOD(void, OnBlockedFrame, (const QuicBlockedFrame&), (override)); - MOCK_METHOD1(OnNewConnectionIdFrame, void(const QuicNewConnectionIdFrame&)); + MOCK_METHOD(void, + OnNewConnectionIdFrame, + (const QuicNewConnectionIdFrame&), + (override)); - MOCK_METHOD1(OnRetireConnectionIdFrame, - void(const QuicRetireConnectionIdFrame&)); + MOCK_METHOD(void, + OnRetireConnectionIdFrame, + (const QuicRetireConnectionIdFrame&), + (override)); - MOCK_METHOD1(OnNewTokenFrame, void(const QuicNewTokenFrame&)); + MOCK_METHOD(void, OnNewTokenFrame, (const QuicNewTokenFrame&), (override)); - MOCK_METHOD1(OnMessageFrame, void(const QuicMessageFrame&)); + MOCK_METHOD(void, OnMessageFrame, (const QuicMessageFrame&), (override)); - MOCK_METHOD1(OnStopSendingFrame, void(const QuicStopSendingFrame&)); + MOCK_METHOD(void, + OnStopSendingFrame, + (const QuicStopSendingFrame&), + (override)); - MOCK_METHOD1(OnPathChallengeFrame, void(const QuicPathChallengeFrame&)); + MOCK_METHOD(void, + OnPathChallengeFrame, + (const QuicPathChallengeFrame&), + (override)); - MOCK_METHOD1(OnPathResponseFrame, void(const QuicPathResponseFrame&)); + MOCK_METHOD(void, + OnPathResponseFrame, + (const QuicPathResponseFrame&), + (override)); - MOCK_METHOD1(OnPublicResetPacket, void(const QuicPublicResetPacket&)); + MOCK_METHOD(void, + OnPublicResetPacket, + (const QuicPublicResetPacket&), + (override)); - MOCK_METHOD1(OnVersionNegotiationPacket, - void(const QuicVersionNegotiationPacket&)); - - MOCK_METHOD5(OnRetryPacket, - void(QuicConnectionId, - QuicConnectionId, - quiche::QuicheStringPiece, - quiche::QuicheStringPiece, - quiche::QuicheStringPiece)); + MOCK_METHOD(void, + OnVersionNegotiationPacket, + (const QuicVersionNegotiationPacket&), + (override)); }; class MockReceivedPacketManager : public QuicReceivedPacketManager { @@ -1139,14 +1422,17 @@ class MockReceivedPacketManager : public QuicReceivedPacketManager { explicit MockReceivedPacketManager(QuicConnectionStats* stats); ~MockReceivedPacketManager() override; - MOCK_METHOD2(RecordPacketReceived, - void(const QuicPacketHeader& header, QuicTime receipt_time)); - MOCK_METHOD1(IsMissing, bool(QuicPacketNumber packet_number)); - MOCK_CONST_METHOD1(IsAwaitingPacket, bool(QuicPacketNumber packet_number)); - MOCK_METHOD1(UpdatePacketInformationSentByPeer, - void(const QuicStopWaitingFrame& stop_waiting)); - MOCK_CONST_METHOD0(HasNewMissingPackets, bool(void)); - MOCK_CONST_METHOD0(ack_frame_updated, bool(void)); + MOCK_METHOD(void, + RecordPacketReceived, + (const QuicPacketHeader& header, QuicTime receipt_time), + (override)); + MOCK_METHOD(bool, IsMissing, (QuicPacketNumber packet_number), (override)); + MOCK_METHOD(bool, + IsAwaitingPacket, + (QuicPacketNumber packet_number), + (const, override)); + MOCK_METHOD(bool, HasNewMissingPackets, (), (const, override)); + MOCK_METHOD(bool, ack_frame_updated, (), (const, override)); }; class MockPacketCreatorDelegate : public QuicPacketCreator::DelegateInterface { @@ -1157,13 +1443,20 @@ class MockPacketCreatorDelegate : public QuicPacketCreator::DelegateInterface { delete; ~MockPacketCreatorDelegate() override; - MOCK_METHOD0(GetPacketBuffer, char*()); - MOCK_METHOD1(OnSerializedPacket, void(SerializedPacket* packet)); - MOCK_METHOD2(OnUnrecoverableError, void(QuicErrorCode, const std::string&)); - MOCK_METHOD2(ShouldGeneratePacket, - bool(HasRetransmittableData retransmittable, - IsHandshake handshake)); - MOCK_METHOD0(MaybeBundleAckOpportunistically, const QuicFrames()); + MOCK_METHOD(char*, GetPacketBuffer, (), (override)); + MOCK_METHOD(void, OnSerializedPacket, (SerializedPacket), (override)); + MOCK_METHOD(void, + OnUnrecoverableError, + (QuicErrorCode, const std::string&), + (override)); + MOCK_METHOD(bool, + ShouldGeneratePacket, + (HasRetransmittableData retransmittable, IsHandshake handshake), + (override)); + MOCK_METHOD(const QuicFrames, + MaybeBundleAckOpportunistically, + (), + (override)); }; class MockSessionNotifier : public SessionNotifierInterface { @@ -1171,14 +1464,30 @@ class MockSessionNotifier : public SessionNotifierInterface { MockSessionNotifier(); ~MockSessionNotifier() override; - MOCK_METHOD3(OnFrameAcked, bool(const QuicFrame&, QuicTime::Delta, QuicTime)); - MOCK_METHOD1(OnStreamFrameRetransmitted, void(const QuicStreamFrame&)); - MOCK_METHOD1(OnFrameLost, void(const QuicFrame&)); - MOCK_METHOD2(RetransmitFrames, - void(const QuicFrames&, TransmissionType type)); - MOCK_CONST_METHOD1(IsFrameOutstanding, bool(const QuicFrame&)); - MOCK_CONST_METHOD0(HasUnackedCryptoData, bool()); - MOCK_CONST_METHOD0(HasUnackedStreamData, bool()); + MOCK_METHOD(bool, + OnFrameAcked, + (const QuicFrame&, QuicTime::Delta, QuicTime), + (override)); + MOCK_METHOD(void, + OnStreamFrameRetransmitted, + (const QuicStreamFrame&), + (override)); + MOCK_METHOD(void, OnFrameLost, (const QuicFrame&), (override)); + MOCK_METHOD(void, + RetransmitFrames, + (const QuicFrames&, TransmissionType type), + (override)); + MOCK_METHOD(bool, IsFrameOutstanding, (const QuicFrame&), (const, override)); + MOCK_METHOD(bool, HasUnackedCryptoData, (), (const, override)); + MOCK_METHOD(bool, HasUnackedStreamData, (), (const, override)); +}; + +class QuicCryptoClientStreamPeer { + public: + QuicCryptoClientStreamPeer() = delete; + + static QuicCryptoClientStream::HandshakerInterface* GetHandshaker( + QuicCryptoClientStream* stream); }; // Creates a client session for testing. @@ -1321,12 +1630,12 @@ MATCHER_P2(InRange, min, max, "") { // A GMock matcher that prints expected and actual QuicErrorCode strings // upon failure. Example usage: -// EXPECT_THAT(stream_->connection_error()), IsError(QUIC_INTERNAL_ERROR)); +// EXPECT_THAT(stream_->connection_error(), IsError(QUIC_INTERNAL_ERROR)); MATCHER_P(IsError, expected, quiche::QuicheStrCat(negation ? "isn't equal to " : "is equal to ", QuicErrorCodeToString(expected))) { - *result_listener << QuicErrorCodeToString(arg); + *result_listener << QuicErrorCodeToString(static_cast<QuicErrorCode>(arg)); return arg == expected; } diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_transport_test_tools.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_transport_test_tools.h index e7e01f78377..50db80aec5d 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_transport_test_tools.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_transport_test_tools.h @@ -14,25 +14,28 @@ namespace test { class MockClientVisitor : public QuicTransportClientSession::ClientVisitor { public: - MOCK_METHOD0(OnSessionReady, void()); - MOCK_METHOD0(OnIncomingBidirectionalStreamAvailable, void()); - MOCK_METHOD0(OnIncomingUnidirectionalStreamAvailable, void()); - MOCK_METHOD1(OnDatagramReceived, void(quiche::QuicheStringPiece)); - MOCK_METHOD0(OnCanCreateNewOutgoingBidirectionalStream, void()); - MOCK_METHOD0(OnCanCreateNewOutgoingUnidirectionalStream, void()); + MOCK_METHOD(void, OnSessionReady, (), (override)); + MOCK_METHOD(void, OnIncomingBidirectionalStreamAvailable, (), (override)); + MOCK_METHOD(void, OnIncomingUnidirectionalStreamAvailable, (), (override)); + MOCK_METHOD(void, + OnDatagramReceived, + (quiche::QuicheStringPiece), + (override)); + MOCK_METHOD(void, OnCanCreateNewOutgoingBidirectionalStream, (), (override)); + MOCK_METHOD(void, OnCanCreateNewOutgoingUnidirectionalStream, (), (override)); }; class MockServerVisitor : public QuicTransportServerSession::ServerVisitor { public: - MOCK_METHOD1(CheckOrigin, bool(url::Origin)); - MOCK_METHOD1(ProcessPath, bool(const GURL&)); + MOCK_METHOD(bool, CheckOrigin, (url::Origin), (override)); + MOCK_METHOD(bool, ProcessPath, (const GURL&), (override)); }; class MockStreamVisitor : public QuicTransportStream::Visitor { public: - MOCK_METHOD0(OnCanRead, void()); - MOCK_METHOD0(OnFinRead, void()); - MOCK_METHOD0(OnCanWrite, void()); + MOCK_METHOD(void, OnCanRead, (), (override)); + MOCK_METHOD(void, OnFinRead, (), (override)); + MOCK_METHOD(void, OnCanWrite, (), (override)); }; } // namespace test 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 be0d8469fb6..626d1e991ea 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 @@ -59,12 +59,12 @@ class SimpleDataProducer : public QuicStreamFrameDataProducer { private: using SendBufferMap = - QuicUnorderedMap<QuicStreamId, std::unique_ptr<QuicStreamSendBuffer>>; + QuicHashMap<QuicStreamId, std::unique_ptr<QuicStreamSendBuffer>>; using CryptoBufferMap = - QuicUnorderedMap<std::pair<EncryptionLevel, QuicStreamOffset>, - quiche::QuicheStringPiece, - PairHash>; + QuicHashMap<std::pair<EncryptionLevel, QuicStreamOffset>, + quiche::QuicheStringPiece, + PairHash>; SimpleBufferAllocator allocator_; diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.cc index 7787fbeb059..6a0cafb4177 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.cc @@ -3,13 +3,28 @@ // found in the LICENSE file. #include "net/third_party/quiche/src/quic/test_tools/simple_session_cache.h" +#include <memory> +#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h" namespace quic { namespace test { void SimpleSessionCache::Insert(const QuicServerId& server_id, - std::unique_ptr<QuicResumptionState> state) { - cache_entries_.insert(std::make_pair(server_id, std::move(state))); + bssl::UniquePtr<SSL_SESSION> session, + const TransportParameters& params, + const ApplicationState* application_state) { + auto it = cache_entries_.find(server_id); + if (it == cache_entries_.end()) { + it = cache_entries_.insert(std::make_pair(server_id, Entry())).first; + } + if (session != nullptr) { + it->second.session = std::move(session); + } + if (application_state != nullptr) { + it->second.application_state = + std::make_unique<ApplicationState>(*application_state); + } + it->second.params = std::make_unique<TransportParameters>(params); } std::unique_ptr<QuicResumptionState> SimpleSessionCache::Lookup( @@ -19,8 +34,10 @@ std::unique_ptr<QuicResumptionState> SimpleSessionCache::Lookup( if (it == cache_entries_.end()) { return nullptr; } - std::unique_ptr<QuicResumptionState> state = std::move(it->second); - cache_entries_.erase(it); + auto state = std::make_unique<QuicResumptionState>(); + state->tls_session = std::move(it->second.session); + state->application_state = it->second.application_state.get(); + state->transport_params = it->second.params.get(); return state; } diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.h b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.h index 40a6946dfde..cfe3f4a5454 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.h @@ -5,7 +5,9 @@ #ifndef QUICHE_QUIC_TEST_TOOLS_SIMPLE_SESSION_CACHE_H_ #define QUICHE_QUIC_TEST_TOOLS_SIMPLE_SESSION_CACHE_H_ +#include <memory> #include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h" +#include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h" namespace quic { namespace test { @@ -21,12 +23,19 @@ class SimpleSessionCache : public SessionCache { ~SimpleSessionCache() override = default; void Insert(const QuicServerId& server_id, - std::unique_ptr<QuicResumptionState> state) override; + bssl::UniquePtr<SSL_SESSION> session, + const TransportParameters& params, + const ApplicationState* application_state) override; std::unique_ptr<QuicResumptionState> Lookup(const QuicServerId& server_id, const SSL_CTX* ctx) override; private: - std::map<QuicServerId, std::unique_ptr<QuicResumptionState>> cache_entries_; + struct Entry { + bssl::UniquePtr<SSL_SESSION> session; + std::unique_ptr<TransportParameters> params; + std::unique_ptr<ApplicationState> application_state; + }; + std::map<QuicServerId, Entry> cache_entries_; }; } // namespace test 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 7366ed8df12..1237f424499 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 @@ -101,7 +101,7 @@ class SimpleSessionNotifier : public SessionNotifierInterface { friend std::ostream& operator<<(std::ostream& os, const StreamState& s); - using StreamMap = QuicUnorderedMap<QuicStreamId, StreamState>; + using StreamMap = QuicHashMap<QuicStreamId, StreamState>; void OnStreamDataConsumed(QuicStreamId id, QuicStreamOffset offset, diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier_test.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier_test.cc index 4dc48a7c1d5..b72a9522036 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier_test.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier_test.cc @@ -29,11 +29,13 @@ class MockQuicConnectionWithSendStreamData : public MockQuicConnection { Perspective perspective) : MockQuicConnection(helper, alarm_factory, perspective) {} - MOCK_METHOD4(SendStreamData, - QuicConsumedData(QuicStreamId id, - size_t write_length, - QuicStreamOffset offset, - StreamSendingState state)); + MOCK_METHOD(QuicConsumedData, + SendStreamData, + (QuicStreamId id, + size_t write_length, + QuicStreamOffset offset, + StreamSendingState state), + (override)); }; class SimpleSessionNotifierTest : public QuicTest { diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h index f3a9f029c85..8b9fd1f480d 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h @@ -87,6 +87,7 @@ class QuicEndpoint : public QuicEndpointBase, void OnStopSendingFrame(const QuicStopSendingFrame& /*frame*/) override {} void OnPacketDecrypted(EncryptionLevel /*level*/) override {} void OnOneRttPacketAcknowledged() override {} + void OnHandshakePacketSent() override {} // End QuicConnectionVisitorInterface implementation. diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.h b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.h index ae9f69b95fc..f4fe33be429 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.h @@ -149,7 +149,7 @@ class QuicEndpointMultiplexer : public Endpoint, void Act() override {} private: - QuicUnorderedMap<std::string, QuicEndpointBase*> mapping_; + QuicHashMap<std::string, QuicEndpointBase*> mapping_; }; } // namespace simulator diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_test.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_test.cc index 0989a3bc0f7..967a9b157ad 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_test.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_test.cc @@ -155,8 +155,6 @@ TEST_F(QuicEndpointTest, TwoWayTransmission) { // Simulate three hosts trying to send data to a fourth one simultaneously. TEST_F(QuicEndpointTest, Competition) { - // TODO(63765788): Turn back on this flag when the issue if fixed. - SetQuicReloadableFlag(quic_bbr_one_mss_conservation, false); auto endpoint_a = std::make_unique<QuicEndpoint>( &simulator_, "Endpoint A", "Endpoint D (A)", Perspective::IS_CLIENT, test::TestConnectionId(42)); diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/simulator.h b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/simulator.h index 46f80778fd4..c1ce07397fc 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/simulator.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/simulator.h @@ -130,8 +130,8 @@ class Simulator : public QuicConnectionHelperInterface { std::multimap<QuicTime, Actor*> schedule_; // For each actor, maintain the time it is scheduled at. The value for // unscheduled actors is QuicTime::Infinite(). - QuicUnorderedMap<Actor*, QuicTime> scheduled_times_; - QuicUnorderedSet<std::string> actor_names_; + QuicHashMap<Actor*, QuicTime> scheduled_times_; + QuicHashSet<std::string> actor_names_; }; template <class TerminationPredicate> diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/simulator_test.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/simulator_test.cc index 06ef4b235b0..0bfce16c433 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/simulator_test.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/simulator_test.cc @@ -595,7 +595,7 @@ class MockPacketFilter : public PacketFilter { public: MockPacketFilter(Simulator* simulator, std::string name, Endpoint* endpoint) : PacketFilter(simulator, name, endpoint) {} - MOCK_METHOD1(FilterPacket, bool(const Packet&)); + MOCK_METHOD(bool, FilterPacket, (const Packet&), (override)); }; // Set up two trivial packet filters, one allowing any packets, and one dropping 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 dea8a860969..3e4cc205bd7 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 @@ -80,7 +80,7 @@ class Switch { // This can not be a QuicCircularDeque since pointers into this are // assumed to be stable. std::deque<Port> ports_; - QuicUnorderedMap<std::string, Port*> switching_table_; + QuicHashMap<std::string, Port*> switching_table_; }; } // namespace simulator diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/traffic_policer.h b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/traffic_policer.h index 1696d5d884c..e33f51b6c23 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/traffic_policer.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/traffic_policer.h @@ -44,7 +44,7 @@ class TrafficPolicer : public PacketFilter { QuicTime last_refill_time_; // Maps each destination to the number of tokens it has left. - QuicUnorderedMap<std::string, QuicByteCount> token_buckets_; + QuicHashMap<std::string, QuicByteCount> token_buckets_; }; } // namespace simulator diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/test_certificates.cc b/chromium/net/third_party/quiche/src/quic/test_tools/test_certificates.cc new file mode 100644 index 00000000000..2a733b43ae9 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/test_tools/test_certificates.cc @@ -0,0 +1,696 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/test_tools/test_certificates.h" + +namespace quic { +namespace test { + +// A test certificate generated by //net/tools/quic/certs/generate-certs.sh. +QUIC_CONST_INIT const char kTestCertificateRaw[] = { + '\x30', '\x82', '\x03', '\xb4', '\x30', '\x82', '\x02', '\x9c', '\xa0', + '\x03', '\x02', '\x01', '\x02', '\x02', '\x01', '\x01', '\x30', '\x0d', + '\x06', '\x09', '\x2a', '\x86', '\x48', '\x86', '\xf7', '\x0d', '\x01', + '\x01', '\x0b', '\x05', '\x00', '\x30', '\x1e', '\x31', '\x1c', '\x30', + '\x1a', '\x06', '\x03', '\x55', '\x04', '\x03', '\x0c', '\x13', '\x51', + '\x55', '\x49', '\x43', '\x20', '\x53', '\x65', '\x72', '\x76', '\x65', + '\x72', '\x20', '\x52', '\x6f', '\x6f', '\x74', '\x20', '\x43', '\x41', + '\x30', '\x1e', '\x17', '\x0d', '\x32', '\x30', '\x30', '\x31', '\x33', + '\x30', '\x31', '\x38', '\x31', '\x33', '\x35', '\x39', '\x5a', '\x17', + '\x0d', '\x32', '\x30', '\x30', '\x32', '\x30', '\x32', '\x31', '\x38', + '\x31', '\x33', '\x35', '\x39', '\x5a', '\x30', '\x64', '\x31', '\x0b', + '\x30', '\x09', '\x06', '\x03', '\x55', '\x04', '\x06', '\x13', '\x02', + '\x55', '\x53', '\x31', '\x13', '\x30', '\x11', '\x06', '\x03', '\x55', + '\x04', '\x08', '\x0c', '\x0a', '\x43', '\x61', '\x6c', '\x69', '\x66', + '\x6f', '\x72', '\x6e', '\x69', '\x61', '\x31', '\x16', '\x30', '\x14', + '\x06', '\x03', '\x55', '\x04', '\x07', '\x0c', '\x0d', '\x4d', '\x6f', + '\x75', '\x6e', '\x74', '\x61', '\x69', '\x6e', '\x20', '\x56', '\x69', + '\x65', '\x77', '\x31', '\x14', '\x30', '\x12', '\x06', '\x03', '\x55', + '\x04', '\x0a', '\x0c', '\x0b', '\x51', '\x55', '\x49', '\x43', '\x20', + '\x53', '\x65', '\x72', '\x76', '\x65', '\x72', '\x31', '\x12', '\x30', + '\x10', '\x06', '\x03', '\x55', '\x04', '\x03', '\x0c', '\x09', '\x31', + '\x32', '\x37', '\x2e', '\x30', '\x2e', '\x30', '\x2e', '\x31', '\x30', + '\x82', '\x01', '\x22', '\x30', '\x0d', '\x06', '\x09', '\x2a', '\x86', + '\x48', '\x86', '\xf7', '\x0d', '\x01', '\x01', '\x01', '\x05', '\x00', + '\x03', '\x82', '\x01', '\x0f', '\x00', '\x30', '\x82', '\x01', '\x0a', + '\x02', '\x82', '\x01', '\x01', '\x00', '\xc5', '\xe2', '\x51', '\x6d', + '\x3f', '\xd6', '\x28', '\xf2', '\xad', '\x34', '\x73', '\x87', '\x64', + '\xca', '\x33', '\x19', '\x33', '\xb7', '\x75', '\x91', '\xab', '\x31', + '\x19', '\x2b', '\xe3', '\xa4', '\x26', '\x09', '\x29', '\x8b', '\x2d', + '\xf7', '\x52', '\x75', '\xa7', '\x55', '\x15', '\xf0', '\x11', '\xc7', + '\xc2', '\xc4', '\xed', '\x18', '\x1b', '\x33', '\x0b', '\x71', '\x32', + '\xe6', '\x35', '\x89', '\xcd', '\x2d', '\x5a', '\x05', '\x57', '\x4e', + '\xc2', '\x78', '\x75', '\x65', '\x72', '\x2d', '\x8a', '\x17', '\x83', + '\xd6', '\x32', '\x90', '\x85', '\xf8', '\x22', '\xe2', '\x65', '\xa9', + '\xe0', '\xa0', '\xfe', '\x19', '\xb2', '\x39', '\x2d', '\x14', '\x03', + '\x10', '\x2f', '\xcc', '\x8b', '\x5e', '\xaa', '\x25', '\x27', '\x0d', + '\xa3', '\x37', '\x10', '\x0c', '\x17', '\xec', '\xf0', '\x8b', '\xc5', + '\x6b', '\xed', '\x6b', '\x5e', '\xb2', '\xe2', '\x35', '\x3e', '\x46', + '\x3b', '\xf7', '\xf6', '\x59', '\xb1', '\xe0', '\x16', '\xa6', '\xfb', + '\x03', '\xbf', '\x84', '\x4f', '\xce', '\x64', '\x15', '\x0d', '\x59', + '\x99', '\xa6', '\xf0', '\x7f', '\x8a', '\x33', '\x4b', '\xbb', '\x0b', + '\xb8', '\xf2', '\xd1', '\x27', '\x90', '\x8f', '\x38', '\xf8', '\x5a', + '\x41', '\x82', '\x07', '\x9b', '\x0d', '\xd9', '\x52', '\xe0', '\x70', + '\xff', '\xde', '\xda', '\xd8', '\x25', '\x4e', '\x2f', '\x2d', '\x9f', + '\xaf', '\x92', '\x63', '\xc7', '\x42', '\xb4', '\xdc', '\x16', '\x95', + '\x23', '\x05', '\x02', '\x6b', '\xb0', '\xe8', '\xc5', '\xfe', '\x15', + '\x9a', '\xe8', '\x7d', '\x2f', '\xdc', '\x43', '\xf4', '\x70', '\x91', + '\x1a', '\x93', '\xbe', '\x71', '\xaf', '\x85', '\x84', '\xdb', '\xcf', + '\x6b', '\x5c', '\x80', '\xb2', '\xd3', '\xf3', '\x42', '\x6e', '\x24', + '\xec', '\x2a', '\x62', '\x99', '\xc6', '\x3c', '\xe5', '\x32', '\xe5', + '\x72', '\x37', '\x30', '\x9b', '\x0b', '\xe4', '\x06', '\xb4', '\x64', + '\x26', '\x95', '\x59', '\xba', '\xf1', '\x53', '\x83', '\x3d', '\x99', + '\x6d', '\xf0', '\x80', '\xe2', '\xdb', '\x6b', '\x34', '\x52', '\x06', + '\x77', '\x3c', '\x73', '\xbe', '\xc6', '\xe3', '\xce', '\xb2', '\x11', + '\x02', '\x03', '\x01', '\x00', '\x01', '\xa3', '\x81', '\xb6', '\x30', + '\x81', '\xb3', '\x30', '\x0c', '\x06', '\x03', '\x55', '\x1d', '\x13', + '\x01', '\x01', '\xff', '\x04', '\x02', '\x30', '\x00', '\x30', '\x1d', + '\x06', '\x03', '\x55', '\x1d', '\x0e', '\x04', '\x16', '\x04', '\x14', + '\xc8', '\x54', '\x28', '\xf6', '\xd2', '\xd5', '\x12', '\x35', '\x89', + '\x15', '\x75', '\xb8', '\xbf', '\xdd', '\xfb', '\x4a', '\xfc', '\x6c', + '\x89', '\xde', '\x30', '\x1f', '\x06', '\x03', '\x55', '\x1d', '\x23', + '\x04', '\x18', '\x30', '\x16', '\x80', '\x14', '\x50', '\xe4', '\x1d', + '\xc3', '\x1a', '\xfb', '\xfd', '\x38', '\xdd', '\xa2', '\x05', '\xfd', + '\xc8', '\xfa', '\x57', '\x0a', '\xc1', '\x06', '\x0f', '\xae', '\x30', + '\x1d', '\x06', '\x03', '\x55', '\x1d', '\x25', '\x04', '\x16', '\x30', + '\x14', '\x06', '\x08', '\x2b', '\x06', '\x01', '\x05', '\x05', '\x07', + '\x03', '\x01', '\x06', '\x08', '\x2b', '\x06', '\x01', '\x05', '\x05', + '\x07', '\x03', '\x02', '\x30', '\x44', '\x06', '\x03', '\x55', '\x1d', + '\x11', '\x04', '\x3d', '\x30', '\x3b', '\x82', '\x0f', '\x77', '\x77', + '\x77', '\x2e', '\x65', '\x78', '\x61', '\x6d', '\x70', '\x6c', '\x65', + '\x2e', '\x6f', '\x72', '\x67', '\x82', '\x10', '\x6d', '\x61', '\x69', + '\x6c', '\x2e', '\x65', '\x78', '\x61', '\x6d', '\x70', '\x6c', '\x65', + '\x2e', '\x6f', '\x72', '\x67', '\x82', '\x10', '\x6d', '\x61', '\x69', + '\x6c', '\x2e', '\x65', '\x78', '\x61', '\x6d', '\x70', '\x6c', '\x65', + '\x2e', '\x63', '\x6f', '\x6d', '\x87', '\x04', '\x7f', '\x00', '\x00', + '\x01', '\x30', '\x0d', '\x06', '\x09', '\x2a', '\x86', '\x48', '\x86', + '\xf7', '\x0d', '\x01', '\x01', '\x0b', '\x05', '\x00', '\x03', '\x82', + '\x01', '\x01', '\x00', '\x45', '\x41', '\x7a', '\x68', '\xe0', '\xa7', + '\x59', '\xa1', '\x62', '\x54', '\x73', '\x74', '\x14', '\x4f', '\xde', + '\x9c', '\x51', '\xac', '\x25', '\x97', '\x70', '\xf7', '\x09', '\x51', + '\x39', '\x72', '\x39', '\x3c', '\xd0', '\x31', '\xe1', '\xc3', '\x02', + '\x91', '\x14', '\x4d', '\x8f', '\x1d', '\x31', '\xab', '\x98', '\x7e', + '\xe6', '\xbb', '\xab', '\x6a', '\xd9', '\xc5', '\x86', '\xaa', '\x4e', + '\x6a', '\x48', '\xe9', '\xf8', '\xd7', '\xb3', '\x1d', '\xa0', '\xc5', + '\xe6', '\xbf', '\x4c', '\x5a', '\x9b', '\xb5', '\x78', '\x01', '\xa3', + '\x39', '\x7b', '\x5f', '\xbc', '\xb8', '\xa7', '\xc2', '\x71', '\xb0', + '\x7b', '\xdd', '\xa1', '\x87', '\xa6', '\x54', '\x9c', '\xf6', '\x59', + '\x81', '\xb1', '\x2c', '\xde', '\xc5', '\x8a', '\xa2', '\x06', '\x89', + '\xb5', '\xc1', '\x7a', '\xbe', '\x0c', '\x9f', '\x3d', '\xde', '\x81', + '\x48', '\x53', '\x71', '\x7b', '\x8d', '\xc7', '\xea', '\x87', '\xd7', + '\xd1', '\xda', '\x94', '\xb4', '\xc5', '\xac', '\x1e', '\x83', '\xa3', + '\x42', '\x7d', '\xe6', '\xab', '\x3f', '\xd6', '\x1c', '\xd6', '\x65', + '\xc3', '\x60', '\xe9', '\x76', '\x54', '\x79', '\x3f', '\xeb', '\x65', + '\x85', '\x4f', '\x60', '\x7d', '\xbb', '\x96', '\x03', '\x54', '\x2e', + '\xd0', '\x1b', '\xe2', '\x6c', '\x2d', '\x91', '\xae', '\x33', '\x9c', + '\x04', '\xc4', '\x44', '\x0a', '\x7d', '\x5f', '\xbb', '\x80', '\xa2', + '\x01', '\xbc', '\x90', '\x81', '\xa5', '\xdc', '\x4a', '\xc8', '\x77', + '\xc9', '\x8d', '\x34', '\x17', '\xe6', '\x2a', '\x7d', '\x02', '\x1e', + '\x32', '\x3f', '\x7d', '\xd7', '\x0c', '\x80', '\x5b', '\xc6', '\x94', + '\x6a', '\x42', '\x36', '\x05', '\x9f', '\x9e', '\xc5', '\x85', '\x9f', + '\x60', '\xe3', '\x72', '\x73', '\x34', '\x39', '\x44', '\x75', '\x55', + '\x60', '\x24', '\x7a', '\x8b', '\x09', '\x74', '\x84', '\x72', '\xfd', + '\x91', '\x68', '\x93', '\x57', '\x9e', '\x70', '\x46', '\x4d', '\xe4', + '\x30', '\x84', '\x5f', '\x20', '\x07', '\xad', '\xfd', '\x86', '\x32', + '\xd3', '\xfb', '\xba', '\xaf', '\xd9', '\x61', '\x14', '\x3c', '\xe0', + '\xa1', '\xa9', '\x51', '\x51', '\x0f', '\xad', '\x60'}; + +QUIC_CONST_INIT const quiche::QuicheStringPiece kTestCertificate( + kTestCertificateRaw, + sizeof(kTestCertificateRaw)); + +QUIC_CONST_INIT const char kTestCertificatePem[] = + R"(Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN=QUIC Server Root CA + Validity + Not Before: Jan 30 18:13:59 2020 GMT + Not After : Feb 2 18:13:59 2020 GMT + Subject: C=US, ST=California, L=Mountain View, O=QUIC Server, CN=127.0.0.1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:c5:e2:51:6d:3f:d6:28:f2:ad:34:73:87:64:ca: + 33:19:33:b7:75:91:ab:31:19:2b:e3:a4:26:09:29: + 8b:2d:f7:52:75:a7:55:15:f0:11:c7:c2:c4:ed:18: + 1b:33:0b:71:32:e6:35:89:cd:2d:5a:05:57:4e:c2: + 78:75:65:72:2d:8a:17:83:d6:32:90:85:f8:22:e2: + 65:a9:e0:a0:fe:19:b2:39:2d:14:03:10:2f:cc:8b: + 5e:aa:25:27:0d:a3:37:10:0c:17:ec:f0:8b:c5:6b: + ed:6b:5e:b2:e2:35:3e:46:3b:f7:f6:59:b1:e0:16: + a6:fb:03:bf:84:4f:ce:64:15:0d:59:99:a6:f0:7f: + 8a:33:4b:bb:0b:b8:f2:d1:27:90:8f:38:f8:5a:41: + 82:07:9b:0d:d9:52:e0:70:ff:de:da:d8:25:4e:2f: + 2d:9f:af:92:63:c7:42:b4:dc:16:95:23:05:02:6b: + b0:e8:c5:fe:15:9a:e8:7d:2f:dc:43:f4:70:91:1a: + 93:be:71:af:85:84:db:cf:6b:5c:80:b2:d3:f3:42: + 6e:24:ec:2a:62:99:c6:3c:e5:32:e5:72:37:30:9b: + 0b:e4:06:b4:64:26:95:59:ba:f1:53:83:3d:99:6d: + f0:80:e2:db:6b:34:52:06:77:3c:73:be:c6:e3:ce: + b2:11 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:FALSE + X509v3 Subject Key Identifier: + C8:54:28:F6:D2:D5:12:35:89:15:75:B8:BF:DD:FB:4A:FC:6C:89:DE + X509v3 Authority Key Identifier: + keyid:50:E4:1D:C3:1A:FB:FD:38:DD:A2:05:FD:C8:FA:57:0A:C1:06:0F:AE + + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + X509v3 Subject Alternative Name: + DNS:www.example.org, DNS:mail.example.org, DNS:mail.example.com, IP Address:127.0.0.1 + Signature Algorithm: sha256WithRSAEncryption + 45:41:7a:68:e0:a7:59:a1:62:54:73:74:14:4f:de:9c:51:ac: + 25:97:70:f7:09:51:39:72:39:3c:d0:31:e1:c3:02:91:14:4d: + 8f:1d:31:ab:98:7e:e6:bb:ab:6a:d9:c5:86:aa:4e:6a:48:e9: + f8:d7:b3:1d:a0:c5:e6:bf:4c:5a:9b:b5:78:01:a3:39:7b:5f: + bc:b8:a7:c2:71:b0:7b:dd:a1:87:a6:54:9c:f6:59:81:b1:2c: + de:c5:8a:a2:06:89:b5:c1:7a:be:0c:9f:3d:de:81:48:53:71: + 7b:8d:c7:ea:87:d7:d1:da:94:b4:c5:ac:1e:83:a3:42:7d:e6: + ab:3f:d6:1c:d6:65:c3:60:e9:76:54:79:3f:eb:65:85:4f:60: + 7d:bb:96:03:54:2e:d0:1b:e2:6c:2d:91:ae:33:9c:04:c4:44: + 0a:7d:5f:bb:80:a2:01:bc:90:81:a5:dc:4a:c8:77:c9:8d:34: + 17:e6:2a:7d:02:1e:32:3f:7d:d7:0c:80:5b:c6:94:6a:42:36: + 05:9f:9e:c5:85:9f:60:e3:72:73:34:39:44:75:55:60:24:7a: + 8b:09:74:84:72:fd:91:68:93:57:9e:70:46:4d:e4:30:84:5f: + 20:07:ad:fd:86:32:d3:fb:ba:af:d9:61:14:3c:e0:a1:a9:51: + 51:0f:ad:60 +-----BEGIN CERTIFICATE----- +MIIDtDCCApygAwIBAgIBATANBgkqhkiG9w0BAQsFADAeMRwwGgYDVQQDDBNRVUlD +IFNlcnZlciBSb290IENBMB4XDTIwMDEzMDE4MTM1OVoXDTIwMDIwMjE4MTM1OVow +ZDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1v +dW50YWluIFZpZXcxFDASBgNVBAoMC1FVSUMgU2VydmVyMRIwEAYDVQQDDAkxMjcu +MC4wLjEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDF4lFtP9Yo8q00 +c4dkyjMZM7d1kasxGSvjpCYJKYst91J1p1UV8BHHwsTtGBszC3Ey5jWJzS1aBVdO +wnh1ZXItiheD1jKQhfgi4mWp4KD+GbI5LRQDEC/Mi16qJScNozcQDBfs8IvFa+1r +XrLiNT5GO/f2WbHgFqb7A7+ET85kFQ1Zmabwf4ozS7sLuPLRJ5CPOPhaQYIHmw3Z +UuBw/97a2CVOLy2fr5Jjx0K03BaVIwUCa7Doxf4Vmuh9L9xD9HCRGpO+ca+FhNvP +a1yAstPzQm4k7CpimcY85TLlcjcwmwvkBrRkJpVZuvFTgz2ZbfCA4ttrNFIGdzxz +vsbjzrIRAgMBAAGjgbYwgbMwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUyFQo9tLV +EjWJFXW4v937Svxsid4wHwYDVR0jBBgwFoAUUOQdwxr7/TjdogX9yPpXCsEGD64w +HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMEQGA1UdEQQ9MDuCD3d3dy5l +eGFtcGxlLm9yZ4IQbWFpbC5leGFtcGxlLm9yZ4IQbWFpbC5leGFtcGxlLmNvbYcE +fwAAATANBgkqhkiG9w0BAQsFAAOCAQEARUF6aOCnWaFiVHN0FE/enFGsJZdw9wlR +OXI5PNAx4cMCkRRNjx0xq5h+5ruratnFhqpOakjp+NezHaDF5r9MWpu1eAGjOXtf +vLinwnGwe92hh6ZUnPZZgbEs3sWKogaJtcF6vgyfPd6BSFNxe43H6ofX0dqUtMWs +HoOjQn3mqz/WHNZlw2DpdlR5P+tlhU9gfbuWA1Qu0BvibC2RrjOcBMRECn1fu4Ci +AbyQgaXcSsh3yY00F+YqfQIeMj991wyAW8aUakI2BZ+exYWfYONyczQ5RHVVYCR6 +iwl0hHL9kWiTV55wRk3kMIRfIAet/YYy0/u6r9lhFDzgoalRUQ+tYA== +-----END CERTIFICATE-----)"; + +// Same leaf as above, but with an intermediary attached. +QUIC_CONST_INIT const char kTestCertificateChainPem[] = + R"(-----BEGIN CERTIFICATE----- +MIIDtDCCApygAwIBAgIBATANBgkqhkiG9w0BAQsFADAeMRwwGgYDVQQDDBNRVUlD +IFNlcnZlciBSb290IENBMB4XDTIwMDEzMDE4MTM1OVoXDTIwMDIwMjE4MTM1OVow +ZDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1v +dW50YWluIFZpZXcxFDASBgNVBAoMC1FVSUMgU2VydmVyMRIwEAYDVQQDDAkxMjcu +MC4wLjEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDF4lFtP9Yo8q00 +c4dkyjMZM7d1kasxGSvjpCYJKYst91J1p1UV8BHHwsTtGBszC3Ey5jWJzS1aBVdO +wnh1ZXItiheD1jKQhfgi4mWp4KD+GbI5LRQDEC/Mi16qJScNozcQDBfs8IvFa+1r +XrLiNT5GO/f2WbHgFqb7A7+ET85kFQ1Zmabwf4ozS7sLuPLRJ5CPOPhaQYIHmw3Z +UuBw/97a2CVOLy2fr5Jjx0K03BaVIwUCa7Doxf4Vmuh9L9xD9HCRGpO+ca+FhNvP +a1yAstPzQm4k7CpimcY85TLlcjcwmwvkBrRkJpVZuvFTgz2ZbfCA4ttrNFIGdzxz +vsbjzrIRAgMBAAGjgbYwgbMwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUyFQo9tLV +EjWJFXW4v937Svxsid4wHwYDVR0jBBgwFoAUUOQdwxr7/TjdogX9yPpXCsEGD64w +HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMEQGA1UdEQQ9MDuCD3d3dy5l +eGFtcGxlLm9yZ4IQbWFpbC5leGFtcGxlLm9yZ4IQbWFpbC5leGFtcGxlLmNvbYcE +fwAAATANBgkqhkiG9w0BAQsFAAOCAQEARUF6aOCnWaFiVHN0FE/enFGsJZdw9wlR +OXI5PNAx4cMCkRRNjx0xq5h+5ruratnFhqpOakjp+NezHaDF5r9MWpu1eAGjOXtf +vLinwnGwe92hh6ZUnPZZgbEs3sWKogaJtcF6vgyfPd6BSFNxe43H6ofX0dqUtMWs +HoOjQn3mqz/WHNZlw2DpdlR5P+tlhU9gfbuWA1Qu0BvibC2RrjOcBMRECn1fu4Ci +AbyQgaXcSsh3yY00F+YqfQIeMj991wyAW8aUakI2BZ+exYWfYONyczQ5RHVVYCR6 +iwl0hHL9kWiTV55wRk3kMIRfIAet/YYy0/u6r9lhFDzgoalRUQ+tYA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDDDCCAfSgAwIBAgIUfVS7RH+aVGqZhrjyuyD4qCnTS+MwDQYJKoZIhvcNAQEL +BQAwHjEcMBoGA1UEAwwTUVVJQyBTZXJ2ZXIgUm9vdCBDQTAeFw0yMDAxMzAxODEz +NTlaFw0yMDAyMDIxODEzNTlaMB4xHDAaBgNVBAMME1FVSUMgU2VydmVyIFJvb3Qg +Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCc3k0GGpCBf6jXHxia +QM4ntB6pWkT+NbaZUNHb1SkG2Cp9dN5dEKOXiqOi9306j4WNWTq/q0Ku9lCPPPFs +JTIVC3tKY8Nbiczw+mohgW4rwLgpAP5rjjVzTxSFpDWZlgkH54HpqLjJFVl4Fklg +vzSj+rYfqP+ueesi7z7KwPwzd30jjsJlpr2rlkZkidWT5vRTD3uYhNOW7IIT0lRP +MDTwdxTEU5unyxESAsZyckNuJDeNF0y1Aw5Xiw/Bww+CyRH+tX6OUcWNtA+ZSDU8 +oVH5m4rxYK/DaHAZrA672/ywvUcPQaNaRxsAWRVjhktgyGPT3pjqiHDCN8+42uhH +SgrbAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFDkHcMa+/04 +3aIF/cj6VwrBBg+uMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEA +iX+tn1Zfxx4M5YqZlPgXFB219agrJP2vM0fzW0E4zqDvA2ALaQN+lwdnFueN3tDk +3IJvxd2W5k1Qh7LqWFUbBghDAP43XffW/yNy0+nuR2n3nRYdNStSMrGQm7oywhBd +5jQl0GQUyYf1jcbD76HA5JraBjEXnQyJe6gJYHiRiMaMURWyzcngOPv5w3XBzIe3 +sRM0Rk/TTZP1Qx7fDY3ikFe1w9LzAMGbKDTKfc1+F0GZByJ3pdWakUNXZvtGFhIF +hTXMooR/wD7an6gtnXD8ixCh7bP0TyPiBhNsUb12WrvSEAm/UyciQbQlR7P+K0Z7 +Cmn1Mj4hQ+pT0t+pw/DMOw== +-----END CERTIFICATE-----)"; + +QUIC_CONST_INIT const char kTestCertificatePrivateKeyRaw[] = { + '\x30', '\x82', '\x04', '\xbc', '\x02', '\x01', '\x00', '\x30', '\x0d', + '\x06', '\x09', '\x2a', '\x86', '\x48', '\x86', '\xf7', '\x0d', '\x01', + '\x01', '\x01', '\x05', '\x00', '\x04', '\x82', '\x04', '\xa6', '\x30', + '\x82', '\x04', '\xa2', '\x02', '\x01', '\x00', '\x02', '\x82', '\x01', + '\x01', '\x00', '\xc5', '\xe2', '\x51', '\x6d', '\x3f', '\xd6', '\x28', + '\xf2', '\xad', '\x34', '\x73', '\x87', '\x64', '\xca', '\x33', '\x19', + '\x33', '\xb7', '\x75', '\x91', '\xab', '\x31', '\x19', '\x2b', '\xe3', + '\xa4', '\x26', '\x09', '\x29', '\x8b', '\x2d', '\xf7', '\x52', '\x75', + '\xa7', '\x55', '\x15', '\xf0', '\x11', '\xc7', '\xc2', '\xc4', '\xed', + '\x18', '\x1b', '\x33', '\x0b', '\x71', '\x32', '\xe6', '\x35', '\x89', + '\xcd', '\x2d', '\x5a', '\x05', '\x57', '\x4e', '\xc2', '\x78', '\x75', + '\x65', '\x72', '\x2d', '\x8a', '\x17', '\x83', '\xd6', '\x32', '\x90', + '\x85', '\xf8', '\x22', '\xe2', '\x65', '\xa9', '\xe0', '\xa0', '\xfe', + '\x19', '\xb2', '\x39', '\x2d', '\x14', '\x03', '\x10', '\x2f', '\xcc', + '\x8b', '\x5e', '\xaa', '\x25', '\x27', '\x0d', '\xa3', '\x37', '\x10', + '\x0c', '\x17', '\xec', '\xf0', '\x8b', '\xc5', '\x6b', '\xed', '\x6b', + '\x5e', '\xb2', '\xe2', '\x35', '\x3e', '\x46', '\x3b', '\xf7', '\xf6', + '\x59', '\xb1', '\xe0', '\x16', '\xa6', '\xfb', '\x03', '\xbf', '\x84', + '\x4f', '\xce', '\x64', '\x15', '\x0d', '\x59', '\x99', '\xa6', '\xf0', + '\x7f', '\x8a', '\x33', '\x4b', '\xbb', '\x0b', '\xb8', '\xf2', '\xd1', + '\x27', '\x90', '\x8f', '\x38', '\xf8', '\x5a', '\x41', '\x82', '\x07', + '\x9b', '\x0d', '\xd9', '\x52', '\xe0', '\x70', '\xff', '\xde', '\xda', + '\xd8', '\x25', '\x4e', '\x2f', '\x2d', '\x9f', '\xaf', '\x92', '\x63', + '\xc7', '\x42', '\xb4', '\xdc', '\x16', '\x95', '\x23', '\x05', '\x02', + '\x6b', '\xb0', '\xe8', '\xc5', '\xfe', '\x15', '\x9a', '\xe8', '\x7d', + '\x2f', '\xdc', '\x43', '\xf4', '\x70', '\x91', '\x1a', '\x93', '\xbe', + '\x71', '\xaf', '\x85', '\x84', '\xdb', '\xcf', '\x6b', '\x5c', '\x80', + '\xb2', '\xd3', '\xf3', '\x42', '\x6e', '\x24', '\xec', '\x2a', '\x62', + '\x99', '\xc6', '\x3c', '\xe5', '\x32', '\xe5', '\x72', '\x37', '\x30', + '\x9b', '\x0b', '\xe4', '\x06', '\xb4', '\x64', '\x26', '\x95', '\x59', + '\xba', '\xf1', '\x53', '\x83', '\x3d', '\x99', '\x6d', '\xf0', '\x80', + '\xe2', '\xdb', '\x6b', '\x34', '\x52', '\x06', '\x77', '\x3c', '\x73', + '\xbe', '\xc6', '\xe3', '\xce', '\xb2', '\x11', '\x02', '\x03', '\x01', + '\x00', '\x01', '\x02', '\x82', '\x01', '\x00', '\x39', '\x75', '\xac', + '\x1b', '\x43', '\x0c', '\x16', '\xbb', '\xd0', '\xdb', '\x88', '\x28', + '\x6a', '\x75', '\xe4', '\x3c', '\x8f', '\x2d', '\xd8', '\x6f', '\xc1', + '\xfb', '\xf1', '\xc9', '\x32', '\xc2', '\xb9', '\x60', '\xb3', '\xb5', + '\x7c', '\x55', '\x72', '\x96', '\x43', '\x4e', '\x8b', '\x9e', '\x38', + '\x2b', '\x7f', '\x3c', '\xdb', '\x73', '\xc2', '\x82', '\x21', '\xf2', + '\x6e', '\xcb', '\x36', '\x04', '\x9b', '\x95', '\x6d', '\xac', '\x5b', + '\x5b', '\xbd', '\x50', '\x69', '\x16', '\x59', '\xff', '\x2b', '\x38', + '\x04', '\xca', '\x2f', '\xc8', '\x93', '\x7e', '\x27', '\xf3', '\x01', + '\x7e', '\x40', '\x81', '\xbf', '\x07', '\x0b', '\x1f', '\x5b', '\x1d', + '\x92', '\x7e', '\x22', '\xc3', '\x0c', '\x3d', '\x22', '\xbe', '\xc3', + '\x06', '\x4c', '\xbc', '\x72', '\x66', '\x70', '\x94', '\x16', '\x8d', + '\x1f', '\x78', '\x65', '\x6a', '\x66', '\x07', '\x1f', '\x74', '\x42', + '\x6e', '\xf6', '\x7e', '\xdc', '\x03', '\xd3', '\x88', '\xb4', '\x4b', + '\x2c', '\x5c', '\x3c', '\x42', '\x59', '\x42', '\x1f', '\x01', '\x13', + '\x31', '\xc5', '\x22', '\xe7', '\x6a', '\x96', '\xf2', '\xfb', '\x66', + '\xfe', '\xc8', '\xa1', '\x7e', '\x24', '\x96', '\x5f', '\x02', '\xee', + '\x38', '\x21', '\xa5', '\x14', '\xd2', '\xa6', '\x35', '\x70', '\x6c', + '\x8d', '\xa6', '\xd8', '\x2a', '\xd2', '\x45', '\x31', '\x5f', '\x67', + '\x9e', '\x35', '\x57', '\x6a', '\xc4', '\x15', '\xe7', '\xba', '\x60', + '\x2f', '\x8e', '\x52', '\x4e', '\xfc', '\x6f', '\xa0', '\x08', '\x91', + '\x31', '\x71', '\x06', '\x68', '\x19', '\x48', '\xc7', '\x81', '\x0d', + '\x5e', '\x52', '\x93', '\x57', '\xcc', '\xfe', '\x46', '\xac', '\xa9', + '\x4f', '\xe2', '\x96', '\x4f', '\xaf', '\x12', '\xfb', '\xc2', '\x4b', + '\xc4', '\x8d', '\x3b', '\xb0', '\x38', '\xe4', '\xbb', '\x8d', '\x19', + '\x81', '\xe4', '\x74', '\x63', '\x9c', '\x8d', '\xaa', '\x84', '\x82', + '\x91', '\xdf', '\xdc', '\x45', '\xf0', '\x39', '\xb2', '\xb4', '\xac', + '\x45', '\xda', '\x3f', '\x30', '\x4d', '\x46', '\xb1', '\xe1', '\xb2', + '\x9d', '\xdf', '\xd8', '\xc4', '\xa2', '\xef', '\xe9', '\x1a', '\x97', + '\x79', '\x02', '\x81', '\x81', '\x00', '\xe5', '\x23', '\xb8', '\xd7', + '\x09', '\x54', '\x54', '\x3b', '\xb6', '\x78', '\x78', '\x67', '\x57', + '\x65', '\xc5', '\xd4', '\x74', '\xaf', '\x05', '\x4f', '\xb5', '\xc8', + '\x8c', '\x1b', '\xd1', '\x9a', '\x2c', '\xd6', '\xe4', '\x68', '\xd1', + '\xaf', '\x3d', '\x72', '\x42', '\x50', '\xc8', '\xdd', '\xb1', '\xee', + '\x77', '\x52', '\xb8', '\xb1', '\x31', '\xbe', '\xf0', '\x74', '\x78', + '\x42', '\x59', '\xea', '\x13', '\x8b', '\x82', '\x00', '\x54', '\x22', + '\xd2', '\x0a', '\x24', '\xb0', '\x1f', '\x1e', '\x76', '\x27', '\xae', + '\x63', '\xc6', '\x6b', '\x59', '\x28', '\x1d', '\xa0', '\x9f', '\x42', + '\x30', '\xf1', '\xe3', '\x59', '\x1c', '\x4f', '\x31', '\x49', '\xff', + '\x45', '\x7e', '\x6b', '\xef', '\xe9', '\x6f', '\xde', '\xaf', '\x1e', + '\x04', '\x96', '\x61', '\x4e', '\x9f', '\x58', '\xf5', '\x0d', '\x64', + '\x08', '\x48', '\x0a', '\xae', '\xac', '\xe4', '\x76', '\x91', '\xdd', + '\x6e', '\x33', '\x97', '\xc5', '\x96', '\xda', '\xff', '\xbc', '\x42', + '\x5b', '\x71', '\xb5', '\x76', '\xae', '\x01', '\xb3', '\x02', '\x81', + '\x81', '\x00', '\xdd', '\x14', '\xa5', '\x6c', '\x89', '\x2b', '\x80', + '\x78', '\xf6', '\xc3', '\x80', '\x4d', '\x53', '\x54', '\xb3', '\x2b', + '\x40', '\xce', '\x98', '\x16', '\xa0', '\xbf', '\x72', '\xf1', '\xe3', + '\xdc', '\xe9', '\x0b', '\x45', '\x23', '\x86', '\x38', '\x4c', '\x29', + '\xf1', '\xa0', '\xe0', '\x2c', '\xfa', '\x86', '\x3f', '\x01', '\x90', + '\xc5', '\x1b', '\x96', '\x10', '\x44', '\x84', '\xfb', '\xec', '\x3c', + '\x74', '\x6c', '\x0d', '\xcc', '\xc3', '\xcd', '\x1b', '\x28', '\x12', + '\xaa', '\xb4', '\x67', '\x80', '\xc8', '\xd9', '\x1b', '\x7d', '\xe7', + '\x54', '\x39', '\x03', '\x6d', '\xba', '\xaa', '\x6f', '\xf7', '\x93', + '\x1f', '\x94', '\x76', '\xd6', '\xab', '\x9b', '\xda', '\x3d', '\x89', + '\x37', '\x83', '\xfe', '\x72', '\x2a', '\xbb', '\x6f', '\x36', '\xc5', + '\xe0', '\xae', '\x65', '\xf9', '\xbb', '\xc6', '\xe2', '\x98', '\x0f', + '\xbd', '\xf6', '\x22', '\xf8', '\x35', '\x5b', '\x99', '\xe6', '\xff', + '\x6d', '\x6e', '\xb2', '\x92', '\x93', '\x64', '\x25', '\xc1', '\xe8', + '\x9c', '\x6b', '\x73', '\x2b', '\x02', '\x81', '\x80', '\x13', '\x30', + '\x1a', '\x9a', '\x67', '\x3d', '\x98', '\x90', '\x27', '\x87', '\x8f', + '\x0d', '\x98', '\x53', '\xfd', '\x6c', '\xfd', '\x18', '\x6a', '\xe9', + '\x71', '\xdf', '\x89', '\x5c', '\x0b', '\x01', '\x4e', '\x1f', '\xf0', + '\xa0', '\x96', '\x6e', '\x86', '\x46', '\xbb', '\x26', '\xe8', '\xab', + '\x27', '\xeb', '\x40', '\x32', '\xbd', '\x24', '\x99', '\x75', '\xd3', + '\xcc', '\xed', '\x05', '\x21', '\x62', '\x68', '\xa0', '\x96', '\x12', + '\x50', '\xf9', '\x59', '\x7d', '\x5f', '\xf5', '\x1f', '\xa5', '\xfd', + '\x5e', '\xf5', '\x4b', '\x85', '\xa2', '\x17', '\xa5', '\x34', '\x55', + '\xef', '\x00', '\x2b', '\xf9', '\x15', '\x80', '\xb0', '\xce', '\x30', + '\xe2', '\x71', '\x6d', '\xf0', '\x58', '\x39', '\x8e', '\xe2', '\xbf', + '\x53', '\x0a', '\xc0', '\x77', '\x97', '\x4e', '\x6e', '\x29', '\x94', + '\xdb', '\xba', '\x34', '\xb7', '\x53', '\xad', '\xac', '\xec', '\xb4', + '\xc1', '\x22', '\x39', '\xc8', '\x38', '\x3d', '\x63', '\x94', '\x93', + '\x35', '\xc0', '\x98', '\xc7', '\xbc', '\xda', '\x63', '\x57', '\xe1', + '\x02', '\x81', '\x80', '\x51', '\x71', '\x7c', '\xab', '\x6a', '\x30', + '\xe3', '\x68', '\x2c', '\x87', '\xc2', '\xe9', '\x39', '\x8c', '\x97', + '\x60', '\x94', '\xc4', '\x46', '\xd4', '\xf7', '\x2c', '\xf0', '\x1c', + '\x5a', '\x34', '\x14', '\x89', '\xf9', '\x53', '\x67', '\xeb', '\xaf', + '\x6b', '\x38', '\x3f', '\x6a', '\xb6', '\x47', '\x28', '\x53', '\x67', + '\xb1', '\x3c', '\x5b', '\xb8', '\x41', '\x8f', '\xec', '\x69', '\x9e', + '\x12', '\x7b', '\x55', '\x1f', '\x14', '\x53', '\x01', '\x69', '\x42', + '\xae', '\xf5', '\xc1', '\xf5', '\xeb', '\x44', '\x92', '\x6e', '\x85', + '\x48', '\x46', '\x07', '\xa6', '\xd2', '\xb2', '\x94', '\x7d', '\x20', + '\xf8', '\x4b', '\x06', '\xf7', '\x6c', '\x87', '\xd5', '\xa7', '\x65', + '\x49', '\xfa', '\x70', '\x9e', '\xb8', '\xd2', '\x33', '\x30', '\x7a', + '\x3e', '\x15', '\x52', '\x49', '\xf0', '\xe1', '\x13', '\x18', '\x80', + '\xaa', '\x33', '\xf1', '\xcb', '\xda', '\x22', '\x55', '\xf7', '\x71', + '\x58', '\xa1', '\xa8', '\xc9', '\x12', '\x24', '\x48', '\x1d', '\x7c', + '\xbc', '\xc3', '\x7a', '\xf5', '\xf7', '\x02', '\x81', '\x80', '\x41', + '\x7c', '\xae', '\x6e', '\x48', '\x3f', '\xb5', '\x0b', '\x99', '\xaa', + '\xc5', '\xea', '\x81', '\xad', '\x84', '\x6b', '\x29', '\x78', '\x4b', + '\x18', '\xdb', '\x0e', '\xd3', '\x3e', '\x60', '\x8b', '\xef', '\x65', + '\x4d', '\x58', '\x25', '\x3a', '\x08', '\xb5', '\x21', '\xb6', '\x61', + '\x0c', '\xfa', '\xf0', '\x69', '\x78', '\x4e', '\x68', '\x36', '\xdb', + '\x41', '\x4b', '\x50', '\xd8', '\xd3', '\x8e', '\x3d', '\x74', '\x80', + '\x8e', '\xa0', '\xe6', '\xda', '\xec', '\x70', '\x89', '\x77', '\xb2', + '\x9d', '\xd6', '\x6e', '\x0a', '\xc4', '\xbd', '\xf6', '\x9a', '\x07', + '\x15', '\xba', '\x55', '\x9f', '\xd4', '\x4d', '\x3a', '\x0f', '\x51', + '\x12', '\xa4', '\xd9', '\xc2', '\x98', '\x76', '\xc5', '\xb7', '\x29', + '\x40', '\xca', '\xf4', '\xbb', '\x74', '\x2d', '\x71', '\x03', '\x4d', + '\xe7', '\x05', '\x75', '\xc0', '\x8d', '\x96', '\x7e', '\x59', '\xa1', + '\x8b', '\x3b', '\xa3', '\x2b', '\xa5', '\xa3', '\xc8', '\xf7', '\xd3', + '\x3e', '\x6b', '\x2e', '\xfa', '\x4f', '\x4d', '\xe6', '\xbe', '\xd3', + '\x59'}; + +QUIC_CONST_INIT const quiche::QuicheStringPiece kTestCertificatePrivateKey( + kTestCertificatePrivateKeyRaw, + sizeof(kTestCertificatePrivateKeyRaw)); + +QUIC_CONST_INIT const char kTestCertificatePrivateKeyPem[] = + R"(-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDF4lFtP9Yo8q00 +c4dkyjMZM7d1kasxGSvjpCYJKYst91J1p1UV8BHHwsTtGBszC3Ey5jWJzS1aBVdO +wnh1ZXItiheD1jKQhfgi4mWp4KD+GbI5LRQDEC/Mi16qJScNozcQDBfs8IvFa+1r +XrLiNT5GO/f2WbHgFqb7A7+ET85kFQ1Zmabwf4ozS7sLuPLRJ5CPOPhaQYIHmw3Z +UuBw/97a2CVOLy2fr5Jjx0K03BaVIwUCa7Doxf4Vmuh9L9xD9HCRGpO+ca+FhNvP +a1yAstPzQm4k7CpimcY85TLlcjcwmwvkBrRkJpVZuvFTgz2ZbfCA4ttrNFIGdzxz +vsbjzrIRAgMBAAECggEAOXWsG0MMFrvQ24goanXkPI8t2G/B+/HJMsK5YLO1fFVy +lkNOi544K38823PCgiHybss2BJuVbaxbW71QaRZZ/ys4BMovyJN+J/MBfkCBvwcL +H1sdkn4iwww9Ir7DBky8cmZwlBaNH3hlamYHH3RCbvZ+3APTiLRLLFw8QllCHwET +McUi52qW8vtm/sihfiSWXwLuOCGlFNKmNXBsjabYKtJFMV9nnjVXasQV57pgL45S +TvxvoAiRMXEGaBlIx4ENXlKTV8z+RqypT+KWT68S+8JLxI07sDjku40ZgeR0Y5yN +qoSCkd/cRfA5srSsRdo/ME1GseGynd/YxKLv6RqXeQKBgQDlI7jXCVRUO7Z4eGdX +ZcXUdK8FT7XIjBvRmizW5GjRrz1yQlDI3bHud1K4sTG+8HR4QlnqE4uCAFQi0gok +sB8edieuY8ZrWSgdoJ9CMPHjWRxPMUn/RX5r7+lv3q8eBJZhTp9Y9Q1kCEgKrqzk +dpHdbjOXxZba/7xCW3G1dq4BswKBgQDdFKVsiSuAePbDgE1TVLMrQM6YFqC/cvHj +3OkLRSOGOEwp8aDgLPqGPwGQxRuWEESE++w8dGwNzMPNGygSqrRngMjZG33nVDkD +bbqqb/eTH5R21qub2j2JN4P+ciq7bzbF4K5l+bvG4pgPvfYi+DVbmeb/bW6ykpNk +JcHonGtzKwKBgBMwGppnPZiQJ4ePDZhT/Wz9GGrpcd+JXAsBTh/woJZuhka7Juir +J+tAMr0kmXXTzO0FIWJooJYSUPlZfV/1H6X9XvVLhaIXpTRV7wAr+RWAsM4w4nFt +8Fg5juK/UwrAd5dObimU27o0t1OtrOy0wSI5yDg9Y5STNcCYx7zaY1fhAoGAUXF8 +q2ow42gsh8LpOYyXYJTERtT3LPAcWjQUiflTZ+uvazg/arZHKFNnsTxbuEGP7Gme +EntVHxRTAWlCrvXB9etEkm6FSEYHptKylH0g+EsG92yH1adlSfpwnrjSMzB6PhVS +SfDhExiAqjPxy9oiVfdxWKGoyRIkSB18vMN69fcCgYBBfK5uSD+1C5mqxeqBrYRr +KXhLGNsO0z5gi+9lTVglOgi1IbZhDPrwaXhOaDbbQUtQ2NOOPXSAjqDm2uxwiXey +ndZuCsS99poHFbpVn9RNOg9REqTZwph2xbcpQMr0u3QtcQNN5wV1wI2Wflmhizuj +K6WjyPfTPmsu+k9N5r7TWQ== +-----END PRIVATE KEY-----)"; + +// The legacy version was manually generated from the one above using der2ascii. +QUIC_CONST_INIT const char kTestCertificatePrivateKeyLegacyPem[] = + R"(-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAxeJRbT/WKPKtNHOHZMozGTO3dZGrMRkr46QmCSmLLfdSdadVFfARx8LE7Rgb +MwtxMuY1ic0tWgVXTsJ4dWVyLYoXg9YykIX4IuJlqeCg/hmyOS0UAxAvzIteqiUnDaM3EAwX7PCL +xWvta16y4jU+Rjv39lmx4Bam+wO/hE/OZBUNWZmm8H+KM0u7C7jy0SeQjzj4WkGCB5sN2VLgcP/e +2tglTi8tn6+SY8dCtNwWlSMFAmuw6MX+FZrofS/cQ/RwkRqTvnGvhYTbz2tcgLLT80JuJOwqYpnG +POUy5XI3MJsL5Aa0ZCaVWbrxU4M9mW3wgOLbazRSBnc8c77G486yEQIDAQABAoIBADl1rBtDDBa7 +0NuIKGp15DyPLdhvwfvxyTLCuWCztXxVcpZDToueOCt/PNtzwoIh8m7LNgSblW2sW1u9UGkWWf8r +OATKL8iTfifzAX5Agb8HCx9bHZJ+IsMMPSK+wwZMvHJmcJQWjR94ZWpmBx90Qm72ftwD04i0Syxc +PEJZQh8BEzHFIudqlvL7Zv7IoX4kll8C7jghpRTSpjVwbI2m2CrSRTFfZ541V2rEFee6YC+OUk78 +b6AIkTFxBmgZSMeBDV5Sk1fM/kasqU/ilk+vEvvCS8SNO7A45LuNGYHkdGOcjaqEgpHf3EXwObK0 +rEXaPzBNRrHhsp3f2MSi7+kal3kCgYEA5SO41wlUVDu2eHhnV2XF1HSvBU+1yIwb0Zos1uRo0a89 +ckJQyN2x7ndSuLExvvB0eEJZ6hOLggBUItIKJLAfHnYnrmPGa1koHaCfQjDx41kcTzFJ/0V+a+/p +b96vHgSWYU6fWPUNZAhICq6s5HaR3W4zl8WW2v+8QltxtXauAbMCgYEA3RSlbIkrgHj2w4BNU1Sz +K0DOmBagv3Lx49zpC0UjhjhMKfGg4Cz6hj8BkMUblhBEhPvsPHRsDczDzRsoEqq0Z4DI2Rt951Q5 +A226qm/3kx+Udtarm9o9iTeD/nIqu282xeCuZfm7xuKYD732Ivg1W5nm/21uspKTZCXB6JxrcysC +gYATMBqaZz2YkCeHjw2YU/1s/Rhq6XHfiVwLAU4f8KCWboZGuyboqyfrQDK9JJl108ztBSFiaKCW +ElD5WX1f9R+l/V71S4WiF6U0Ve8AK/kVgLDOMOJxbfBYOY7iv1MKwHeXTm4plNu6NLdTrazstMEi +Ocg4PWOUkzXAmMe82mNX4QKBgFFxfKtqMONoLIfC6TmMl2CUxEbU9yzwHFo0FIn5U2frr2s4P2q2 +RyhTZ7E8W7hBj+xpnhJ7VR8UUwFpQq71wfXrRJJuhUhGB6bSspR9IPhLBvdsh9WnZUn6cJ640jMw +ej4VUknw4RMYgKoz8cvaIlX3cVihqMkSJEgdfLzDevX3AoGAQXyubkg/tQuZqsXqga2Eayl4Sxjb +DtM+YIvvZU1YJToItSG2YQz68Gl4Tmg220FLUNjTjj10gI6g5trscIl3sp3WbgrEvfaaBxW6VZ/U +TToPURKk2cKYdsW3KUDK9Lt0LXEDTecFdcCNln5ZoYs7oyulo8j30z5rLvpPTea+01k= +-----END RSA PRIVATE KEY-----)"; + +QUIC_CONST_INIT const char kWildcardCertificateRaw[] = { + '\x30', '\x82', '\x03', '\x5f', '\x30', '\x82', '\x02', '\x47', '\xa0', + '\x03', '\x02', '\x01', '\x02', '\x02', '\x14', '\x36', '\x1d', '\xe3', + '\xd2', '\x39', '\x35', '\x20', '\xb1', '\xae', '\x18', '\xdd', '\x71', + '\xc9', '\x5b', '\x4a', '\x17', '\xbe', '\x00', '\xb4', '\x15', '\x30', + '\x0d', '\x06', '\x09', '\x2a', '\x86', '\x48', '\x86', '\xf7', '\x0d', + '\x01', '\x01', '\x0b', '\x05', '\x00', '\x30', '\x24', '\x31', '\x0b', + '\x30', '\x09', '\x06', '\x03', '\x55', '\x04', '\x06', '\x13', '\x02', + '\x55', '\x53', '\x31', '\x15', '\x30', '\x13', '\x06', '\x03', '\x55', + '\x04', '\x03', '\x0c', '\x0c', '\x77', '\x77', '\x77', '\x2e', '\x66', + '\x6f', '\x6f', '\x2e', '\x74', '\x65', '\x73', '\x74', '\x30', '\x1e', + '\x17', '\x0d', '\x32', '\x30', '\x30', '\x34', '\x32', '\x31', '\x30', + '\x32', '\x31', '\x38', '\x34', '\x35', '\x5a', '\x17', '\x0d', '\x32', + '\x31', '\x30', '\x34', '\x32', '\x31', '\x30', '\x32', '\x31', '\x38', + '\x34', '\x35', '\x5a', '\x30', '\x24', '\x31', '\x0b', '\x30', '\x09', + '\x06', '\x03', '\x55', '\x04', '\x06', '\x13', '\x02', '\x55', '\x53', + '\x31', '\x15', '\x30', '\x13', '\x06', '\x03', '\x55', '\x04', '\x03', + '\x0c', '\x0c', '\x77', '\x77', '\x77', '\x2e', '\x66', '\x6f', '\x6f', + '\x2e', '\x74', '\x65', '\x73', '\x74', '\x30', '\x82', '\x01', '\x22', + '\x30', '\x0d', '\x06', '\x09', '\x2a', '\x86', '\x48', '\x86', '\xf7', + '\x0d', '\x01', '\x01', '\x01', '\x05', '\x00', '\x03', '\x82', '\x01', + '\x0f', '\x00', '\x30', '\x82', '\x01', '\x0a', '\x02', '\x82', '\x01', + '\x01', '\x00', '\xcc', '\xd5', '\x5d', '\xa0', '\x4a', '\x03', '\x9d', + '\x89', '\xa2', '\xae', '\x7a', '\x59', '\x15', '\xf7', '\x27', '\x67', + '\x49', '\xa4', '\xc1', '\x87', '\xcd', '\x9c', '\x02', '\x9e', '\xb9', + '\x2f', '\xd1', '\xa1', '\x0d', '\x57', '\xff', '\xd6', '\xc0', '\x6a', + '\x7b', '\xaa', '\x52', '\xb2', '\x6e', '\xa6', '\x12', '\x34', '\xcf', + '\xdc', '\xd3', '\x1e', '\x32', '\xc1', '\x8d', '\x42', '\xa3', '\x0b', + '\xd6', '\xaf', '\xe9', '\x37', '\x42', '\xf8', '\x78', '\xdc', '\xcb', + '\x2d', '\x0e', '\x42', '\x5a', '\xe2', '\xbf', '\xd2', '\xe4', '\x9c', + '\xb4', '\x34', '\x38', '\x97', '\x5e', '\x4d', '\x5e', '\x8a', '\x0b', + '\xd8', '\x42', '\x11', '\x88', '\x19', '\xa2', '\x23', '\x4b', '\xec', + '\x3b', '\x0a', '\xc9', '\x67', '\x49', '\x2c', '\x8e', '\x1c', '\x5e', + '\x7f', '\x42', '\xe7', '\x73', '\x0b', '\x86', '\x68', '\xf0', '\xaa', + '\x3f', '\x1e', '\x17', '\x3e', '\x29', '\xc4', '\x57', '\x6e', '\x34', + '\x78', '\xaf', '\x15', '\x03', '\x39', '\x32', '\x27', '\x80', '\x76', + '\xb1', '\xda', '\x08', '\xe5', '\x4d', '\x3f', '\x4c', '\xfc', '\x1e', + '\x23', '\x5a', '\xb3', '\xd4', '\x99', '\xdc', '\x5c', '\x2b', '\xf1', + '\xa8', '\xe3', '\x02', '\x0a', '\xc8', '\x4d', '\x63', '\x27', '\xb9', + '\x0d', '\x6c', '\xc2', '\x34', '\x82', '\x82', '\x5d', '\x56', '\xa8', + '\x93', '\x44', '\x8b', '\xf4', '\x8b', '\xf0', '\x63', '\xe5', '\x23', + '\x7f', '\x8d', '\x5f', '\x3a', '\x4a', '\xa5', '\x50', '\xb9', '\xc6', + '\x5c', '\xe6', '\x33', '\xe3', '\xfc', '\xc8', '\x96', '\x88', '\x88', + '\xe9', '\x53', '\xaf', '\x0d', '\xbb', '\x80', '\x9c', '\xbb', '\xed', + '\x4d', '\x06', '\xfa', '\xe9', '\x7c', '\x25', '\x1c', '\x59', '\xee', + '\x19', '\xcc', '\xa9', '\x7c', '\x1d', '\x86', '\xd9', '\x95', '\x78', + '\x2d', '\x3a', '\x95', '\x49', '\x11', '\x45', '\xfa', '\xd6', '\xef', + '\xd5', '\x07', '\x1c', '\x23', '\xeb', '\xad', '\xd3', '\x3b', '\x95', + '\xcf', '\x53', '\xa3', '\x47', '\xa9', '\xa7', '\x90', '\xde', '\x34', + '\xa4', '\xbb', '\x05', '\xdc', '\x54', '\x87', '\x97', '\x30', '\xea', + '\x25', '\xf0', '\xfd', '\xba', '\xa1', '\x1b', '\x02', '\x03', '\x01', + '\x00', '\x01', '\xa3', '\x81', '\x88', '\x30', '\x81', '\x85', '\x30', + '\x1d', '\x06', '\x03', '\x55', '\x1d', '\x0e', '\x04', '\x16', '\x04', + '\x14', '\x09', '\xfb', '\x77', '\xbb', '\xc8', '\x8f', '\xd6', '\xa4', + '\xf0', '\x74', '\xb2', '\x90', '\x46', '\x0a', '\x8d', '\x09', '\x4b', + '\x89', '\x2e', '\x41', '\x30', '\x1f', '\x06', '\x03', '\x55', '\x1d', + '\x23', '\x04', '\x18', '\x30', '\x16', '\x80', '\x14', '\x09', '\xfb', + '\x77', '\xbb', '\xc8', '\x8f', '\xd6', '\xa4', '\xf0', '\x74', '\xb2', + '\x90', '\x46', '\x0a', '\x8d', '\x09', '\x4b', '\x89', '\x2e', '\x41', + '\x30', '\x0f', '\x06', '\x03', '\x55', '\x1d', '\x13', '\x01', '\x01', + '\xff', '\x04', '\x05', '\x30', '\x03', '\x01', '\x01', '\xff', '\x30', + '\x32', '\x06', '\x03', '\x55', '\x1d', '\x11', '\x04', '\x2b', '\x30', + '\x29', '\x82', '\x08', '\x66', '\x6f', '\x6f', '\x2e', '\x74', '\x65', + '\x73', '\x74', '\x82', '\x0c', '\x77', '\x77', '\x77', '\x2e', '\x66', + '\x6f', '\x6f', '\x2e', '\x74', '\x65', '\x73', '\x74', '\x82', '\x0f', + '\x2a', '\x2e', '\x77', '\x69', '\x6c', '\x64', '\x63', '\x61', '\x72', + '\x64', '\x2e', '\x74', '\x65', '\x73', '\x74', '\x30', '\x0d', '\x06', + '\x09', '\x2a', '\x86', '\x48', '\x86', '\xf7', '\x0d', '\x01', '\x01', + '\x0b', '\x05', '\x00', '\x03', '\x82', '\x01', '\x01', '\x00', '\x93', + '\xbc', '\x33', '\x4c', '\xa4', '\xdf', '\xdc', '\xed', '\x4b', '\x4d', + '\x5e', '\xdb', '\xdd', '\x4a', '\xb7', '\xbc', '\x50', '\x1f', '\xca', + '\x66', '\x4d', '\x28', '\x96', '\x42', '\x4e', '\x84', '\x44', '\x80', + '\x25', '\x17', '\x2c', '\x05', '\x93', '\xe0', '\x2a', '\x29', '\xef', + '\xe4', '\x26', '\x19', '\x63', '\xdf', '\xb2', '\x72', '\xb1', '\x82', + '\x7e', '\x5f', '\xce', '\x82', '\x41', '\xad', '\x96', '\x78', '\x94', + '\xa8', '\x21', '\xee', '\xf2', '\x4a', '\xf5', '\x41', '\xa8', '\xfb', + '\xe0', '\xe1', '\x22', '\x89', '\xf1', '\x40', '\x85', '\x86', '\x53', + '\x61', '\x57', '\x0f', '\x31', '\xae', '\x0c', '\xc3', '\x8d', '\xe8', + '\x29', '\xac', '\xe0', '\x03', '\x2d', '\x69', '\x44', '\x3d', '\xd6', + '\x3b', '\x2b', '\x0f', '\xb3', '\xf5', '\x83', '\x1b', '\x4e', '\x65', + '\x60', '\x6b', '\xa2', '\x01', '\x03', '\x1e', '\x98', '\xca', '\xca', + '\x32', '\xd4', '\x5b', '\xde', '\x45', '\xe2', '\x35', '\xd2', '\x54', + '\x1a', '\x2a', '\x38', '\xa7', '\x42', '\xa0', '\xf3', '\xef', '\x28', + '\xe3', '\x6e', '\x23', '\x77', '\x07', '\xd5', '\xef', '\xfd', '\x30', + '\xd6', '\x31', '\xfa', '\xf2', '\x94', '\x95', '\x2f', '\x03', '\x7a', + '\x43', '\xe0', '\xb3', '\x82', '\xca', '\x7e', '\xb4', '\x00', '\xc9', + '\x08', '\x15', '\x7b', '\x2e', '\x51', '\xec', '\xab', '\x68', '\xca', + '\xc2', '\xca', '\x44', '\xe1', '\xbe', '\xe4', '\x06', '\x98', '\x87', + '\x9b', '\x58', '\xbc', '\xf1', '\xea', '\x55', '\xf6', '\x64', '\x92', + '\xe6', '\x73', '\xc9', '\xf6', '\xc5', '\x7a', '\x90', '\x42', '\x83', + '\x39', '\x9e', '\xd0', '\xca', '\x85', '\x6c', '\x53', '\x99', '\x64', + '\xbb', '\x49', '\xdc', '\xae', '\x1c', '\xe5', '\x00', '\x65', '\x13', + '\xdd', '\xdc', '\xde', '\x3f', '\xf9', '\x14', '\x91', '\x0d', '\xe6', + '\xba', '\xc1', '\x7d', '\x5f', '\xd5', '\x6d', '\xe8', '\x65', '\x9c', + '\xfb', '\xda', '\x82', '\xf7', '\x4d', '\x45', '\x81', '\x8c', '\x54', + '\xec', '\x50', '\xbb', '\x14', '\xe9', '\x06', '\xda', '\x76', '\xb3', + '\xf0', '\xb7', '\xbb', '\x58', '\x4c', '\x8f', '\x6a', '\x5d', '\x8e', + '\x93', '\x5f', '\x35'}; + +QUIC_CONST_INIT const quiche::QuicheStringPiece kWildcardCertificate( + kWildcardCertificateRaw, + sizeof(kWildcardCertificateRaw)); + +QUIC_CONST_INIT const char kWildcardCertificatePrivateKeyRaw[] = { + '\x30', '\x82', '\x04', '\xbe', '\x02', '\x01', '\x00', '\x30', '\x0d', + '\x06', '\x09', '\x2a', '\x86', '\x48', '\x86', '\xf7', '\x0d', '\x01', + '\x01', '\x01', '\x05', '\x00', '\x04', '\x82', '\x04', '\xa8', '\x30', + '\x82', '\x04', '\xa4', '\x02', '\x01', '\x00', '\x02', '\x82', '\x01', + '\x01', '\x00', '\xcc', '\xd5', '\x5d', '\xa0', '\x4a', '\x03', '\x9d', + '\x89', '\xa2', '\xae', '\x7a', '\x59', '\x15', '\xf7', '\x27', '\x67', + '\x49', '\xa4', '\xc1', '\x87', '\xcd', '\x9c', '\x02', '\x9e', '\xb9', + '\x2f', '\xd1', '\xa1', '\x0d', '\x57', '\xff', '\xd6', '\xc0', '\x6a', + '\x7b', '\xaa', '\x52', '\xb2', '\x6e', '\xa6', '\x12', '\x34', '\xcf', + '\xdc', '\xd3', '\x1e', '\x32', '\xc1', '\x8d', '\x42', '\xa3', '\x0b', + '\xd6', '\xaf', '\xe9', '\x37', '\x42', '\xf8', '\x78', '\xdc', '\xcb', + '\x2d', '\x0e', '\x42', '\x5a', '\xe2', '\xbf', '\xd2', '\xe4', '\x9c', + '\xb4', '\x34', '\x38', '\x97', '\x5e', '\x4d', '\x5e', '\x8a', '\x0b', + '\xd8', '\x42', '\x11', '\x88', '\x19', '\xa2', '\x23', '\x4b', '\xec', + '\x3b', '\x0a', '\xc9', '\x67', '\x49', '\x2c', '\x8e', '\x1c', '\x5e', + '\x7f', '\x42', '\xe7', '\x73', '\x0b', '\x86', '\x68', '\xf0', '\xaa', + '\x3f', '\x1e', '\x17', '\x3e', '\x29', '\xc4', '\x57', '\x6e', '\x34', + '\x78', '\xaf', '\x15', '\x03', '\x39', '\x32', '\x27', '\x80', '\x76', + '\xb1', '\xda', '\x08', '\xe5', '\x4d', '\x3f', '\x4c', '\xfc', '\x1e', + '\x23', '\x5a', '\xb3', '\xd4', '\x99', '\xdc', '\x5c', '\x2b', '\xf1', + '\xa8', '\xe3', '\x02', '\x0a', '\xc8', '\x4d', '\x63', '\x27', '\xb9', + '\x0d', '\x6c', '\xc2', '\x34', '\x82', '\x82', '\x5d', '\x56', '\xa8', + '\x93', '\x44', '\x8b', '\xf4', '\x8b', '\xf0', '\x63', '\xe5', '\x23', + '\x7f', '\x8d', '\x5f', '\x3a', '\x4a', '\xa5', '\x50', '\xb9', '\xc6', + '\x5c', '\xe6', '\x33', '\xe3', '\xfc', '\xc8', '\x96', '\x88', '\x88', + '\xe9', '\x53', '\xaf', '\x0d', '\xbb', '\x80', '\x9c', '\xbb', '\xed', + '\x4d', '\x06', '\xfa', '\xe9', '\x7c', '\x25', '\x1c', '\x59', '\xee', + '\x19', '\xcc', '\xa9', '\x7c', '\x1d', '\x86', '\xd9', '\x95', '\x78', + '\x2d', '\x3a', '\x95', '\x49', '\x11', '\x45', '\xfa', '\xd6', '\xef', + '\xd5', '\x07', '\x1c', '\x23', '\xeb', '\xad', '\xd3', '\x3b', '\x95', + '\xcf', '\x53', '\xa3', '\x47', '\xa9', '\xa7', '\x90', '\xde', '\x34', + '\xa4', '\xbb', '\x05', '\xdc', '\x54', '\x87', '\x97', '\x30', '\xea', + '\x25', '\xf0', '\xfd', '\xba', '\xa1', '\x1b', '\x02', '\x03', '\x01', + '\x00', '\x01', '\x02', '\x82', '\x01', '\x01', '\x00', '\xa3', '\xb3', + '\x01', '\x98', '\x50', '\x8e', '\x83', '\x20', '\xb4', '\x3a', '\xec', + '\xdc', '\xb5', '\x89', '\x48', '\x9c', '\x6b', '\x66', '\x98', '\xa4', + '\x87', '\xd5', '\xde', '\xe2', '\x2a', '\xed', '\xe4', '\x82', '\xe9', + '\xbf', '\x22', '\x5f', '\xe6', '\x77', '\x33', '\x4d', '\xf3', '\xb9', + '\x56', '\x64', '\xb2', '\xb8', '\x32', '\x47', '\x31', '\x12', '\x39', + '\x4e', '\x26', '\x2e', '\xd3', '\x4f', '\x6a', '\xcc', '\x3b', '\x7e', + '\x46', '\xaf', '\x7d', '\x28', '\x37', '\xd8', '\x52', '\x45', '\x05', + '\x8d', '\xa1', '\xf0', '\x51', '\x74', '\x4b', '\x30', '\x50', '\xe9', + '\xe8', '\x1b', '\xbd', '\x2a', '\x66', '\x3c', '\xf6', '\xd0', '\x3c', + '\x0d', '\x00', '\x5f', '\x65', '\x15', '\xee', '\x39', '\xb8', '\xac', + '\x2a', '\xf6', '\xc8', '\xbc', '\x33', '\x69', '\x51', '\x76', '\xd7', + '\xa2', '\xa6', '\x50', '\xc7', '\xc5', '\xc7', '\x9b', '\xac', '\xc7', + '\xa9', '\x69', '\x98', '\xd6', '\x22', '\x69', '\x30', '\xc3', '\x82', + '\x47', '\xfb', '\xa5', '\x46', '\x2d', '\x96', '\x05', '\xc2', '\x84', + '\xd1', '\x1d', '\xd5', '\xa7', '\x5c', '\xdb', '\x6d', '\x35', '\x7b', + '\x1b', '\x80', '\xe4', '\x42', '\x1f', '\x4d', '\x68', '\x2e', '\xbc', + '\x58', '\xb6', '\x7c', '\x7e', '\xc5', '\x07', '\xe1', '\xf5', '\x30', + '\xa9', '\x8f', '\x14', '\x76', '\xad', '\xe2', '\xdf', '\xaf', '\xd3', + '\xf1', '\xba', '\xd5', '\x98', '\xf3', '\x5e', '\x30', '\x79', '\xcb', + '\xe7', '\x7a', '\x83', '\xba', '\xf7', '\x71', '\xb0', '\xb2', '\xd1', + '\xf4', '\x34', '\x5b', '\xe1', '\xe8', '\x60', '\x39', '\x96', '\x12', + '\xdc', '\xb4', '\x0d', '\xf9', '\x8d', '\x8c', '\xd8', '\xbb', '\xb7', + '\xd2', '\x1b', '\x83', '\x10', '\xbd', '\x86', '\xef', '\x5c', '\x6c', + '\xe3', '\xb1', '\x96', '\x7f', '\xab', '\x58', '\xce', '\x87', '\xc9', + '\x48', '\x69', '\xbb', '\xb1', '\xec', '\xa4', '\x3a', '\x06', '\xa3', + '\x33', '\xad', '\x7a', '\xe5', '\x88', '\x6d', '\x32', '\x67', '\x1c', + '\x03', '\xda', '\x9d', '\x3c', '\x73', '\xe0', '\xd7', '\x6c', '\x00', + '\xe4', '\x8d', '\x7d', '\xf2', '\xac', '\xa5', '\xb8', '\x35', '\xb9', + '\xac', '\x81', '\x02', '\x81', '\x81', '\x00', '\xe8', '\xd5', '\x5b', + '\xd0', '\x4f', '\x7c', '\xfc', '\x4b', '\xe6', '\xe8', '\x3c', '\x4c', + '\x24', '\xce', '\x68', '\x73', '\x3b', '\x4b', '\xa0', '\xfb', '\x79', + '\xa5', '\x72', '\x1d', '\x77', '\xb2', '\xdf', '\x2b', '\x0a', '\x11', + '\x28', '\xe8', '\x02', '\x7f', '\x26', '\x40', '\x34', '\x8f', '\x78', + '\x18', '\xad', '\xf4', '\x11', '\x78', '\x45', '\x9f', '\x66', '\x4e', + '\x78', '\x71', '\x60', '\x40', '\xeb', '\x64', '\x28', '\x06', '\xae', + '\x9b', '\x32', '\x73', '\xb5', '\xe1', '\x7e', '\x3c', '\x07', '\x31', + '\x8d', '\x82', '\xed', '\x6a', '\xe6', '\x1e', '\x65', '\x9e', '\x81', + '\x29', '\x08', '\x56', '\x17', '\x4b', '\x31', '\xc3', '\xf5', '\x27', + '\xef', '\xb8', '\xda', '\x58', '\xff', '\x36', '\x47', '\x12', '\xb0', + '\xef', '\x14', '\x20', '\x5c', '\x48', '\xb3', '\x84', '\x0d', '\x64', + '\x22', '\x3e', '\xfe', '\x94', '\x17', '\x6c', '\x45', '\xe7', '\x3f', + '\x4c', '\x90', '\x67', '\x13', '\x1a', '\xa8', '\xbc', '\x5b', '\xd0', + '\xc1', '\x8a', '\xa9', '\x42', '\xbe', '\xe4', '\x0e', '\x59', '\x02', + '\x81', '\x81', '\x00', '\xe1', '\x36', '\xcd', '\x86', '\x1e', '\xcb', + '\x8b', '\x68', '\x65', '\x6b', '\x42', '\xec', '\x50', '\x29', '\xa0', + '\xab', '\x3a', '\xe5', '\x6f', '\xe1', '\x13', '\xe8', '\xa3', '\x6b', + '\x7c', '\x2b', '\xd3', '\x69', '\x89', '\x47', '\x07', '\x39', '\xb2', + '\x0f', '\x03', '\x4e', '\x6f', '\x28', '\x94', '\x1d', '\x1f', '\x22', + '\x47', '\xf9', '\x95', '\xff', '\x3e', '\xa4', '\x26', '\x38', '\x07', + '\x5b', '\xdd', '\xef', '\x0a', '\xa5', '\xe8', '\x99', '\xad', '\x91', + '\x68', '\x83', '\xf2', '\xf5', '\xa5', '\x3d', '\x21', '\x88', '\xa5', + '\x6a', '\x39', '\x3b', '\xca', '\x4c', '\xc9', '\xd1', '\x9a', '\x74', + '\xb2', '\xe3', '\x73', '\x5d', '\xfe', '\xbd', '\x05', '\x1b', '\x9a', + '\x13', '\x98', '\x39', '\x93', '\xf3', '\x88', '\x55', '\x61', '\x85', + '\x7a', '\x53', '\x5a', '\xd9', '\x2c', '\xdb', '\x15', '\x69', '\xa6', + '\x31', '\x09', '\xbb', '\xd1', '\xe8', '\x6e', '\x8c', '\x47', '\x77', + '\x1e', '\x9b', '\xbe', '\xb7', '\x57', '\xd4', '\xaa', '\xd5', '\x92', + '\xa1', '\xd5', '\x55', '\x04', '\x93', '\x02', '\x81', '\x80', '\x06', + '\x84', '\x01', '\xff', '\xc0', '\x59', '\xb5', '\x0d', '\xc2', '\xb6', + '\x79', '\x09', '\x80', '\x76', '\x2e', '\x42', '\x1b', '\x44', '\xb0', + '\x8a', '\x99', '\x0a', '\xe2', '\x38', '\xa4', '\xe2', '\xe2', '\x8f', + '\xe7', '\xc6', '\x37', '\x28', '\xd6', '\xf9', '\x0b', '\xee', '\xfc', + '\x09', '\x8f', '\xc8', '\xd1', '\x05', '\x65', '\x7f', '\xc2', '\x23', + '\x05', '\xcf', '\xe8', '\x5a', '\xf3', '\xe0', '\x9d', '\x35', '\xbe', + '\x51', '\x01', '\x8d', '\xe2', '\x49', '\x8e', '\xab', '\x72', '\xc6', + '\xe7', '\x44', '\xa1', '\xbb', '\x2a', '\x3d', '\xb5', '\x96', '\xe0', + '\x2d', '\x21', '\x5c', '\x2e', '\x99', '\x8a', '\x29', '\x56', '\x89', + '\x2f', '\x51', '\x20', '\xca', '\x41', '\x82', '\x00', '\x12', '\x5a', + '\xc6', '\xd1', '\x20', '\xbf', '\xa5', '\x70', '\x2f', '\xb0', '\xa6', + '\x5f', '\x61', '\x8f', '\xfb', '\xc7', '\x50', '\x09', '\x9f', '\xc4', + '\x0d', '\x06', '\x9e', '\x73', '\xe4', '\x0e', '\x8a', '\xce', '\x72', + '\x06', '\xf7', '\xbe', '\x92', '\xcc', '\xcd', '\xcb', '\x5d', '\xc2', + '\x71', '\x02', '\x81', '\x80', '\x26', '\xf3', '\xba', '\x92', '\x52', + '\xeb', '\x33', '\x7e', '\x67', '\xe4', '\x28', '\x5c', '\x04', '\xf5', + '\x5e', '\x33', '\x9f', '\x69', '\x25', '\x73', '\x91', '\x64', '\xf0', + '\x36', '\xdb', '\xf0', '\x1c', '\x8d', '\xa9', '\x4f', '\x9e', '\xa1', + '\x4c', '\xf9', '\xa9', '\xc1', '\xbc', '\x1a', '\x11', '\x9c', '\x03', + '\xd1', '\x83', '\x0f', '\x58', '\xf1', '\x1f', '\x9d', '\x76', '\x7a', + '\xc4', '\x53', '\x10', '\x4c', '\x92', '\xd3', '\xe5', '\x2a', '\x07', + '\x4a', '\x1a', '\x00', '\x90', '\x5a', '\x0a', '\x2d', '\x4b', '\x8a', + '\x7d', '\xc9', '\xa4', '\x82', '\x81', '\xd7', '\xcc', '\x24', '\x33', + '\x89', '\xb1', '\x93', '\x03', '\x56', '\x23', '\x83', '\xff', '\xc9', + '\x29', '\x59', '\xf0', '\x3f', '\x2d', '\x26', '\xb6', '\xd2', '\xc5', + '\x9e', '\x37', '\x6d', '\x09', '\x4e', '\x7c', '\xa2', '\x9b', '\xce', + '\x7d', '\x0f', '\x08', '\x36', '\xf2', '\xf4', '\x37', '\x82', '\x8d', + '\xad', '\xbd', '\x9e', '\x84', '\x5a', '\xe3', '\x97', '\x05', '\xc1', + '\x10', '\xae', '\x6a', '\xde', '\x5c', '\x7f', '\x02', '\x81', '\x81', + '\x00', '\x9b', '\x8e', '\xa4', '\x2b', '\xcf', '\xb6', '\x30', '\x1c', + '\xb5', '\x82', '\x50', '\x08', '\xc0', '\x0b', '\x57', '\xf4', '\x2d', + '\x82', '\x39', '\x11', '\x1b', '\x02', '\xe6', '\xbe', '\x14', '\x26', + '\x77', '\xd7', '\x26', '\x1f', '\x0d', '\x92', '\xc6', '\x67', '\xa0', + '\x01', '\x6c', '\xd9', '\x7a', '\xdf', '\xc3', '\x3d', '\x50', '\x8d', + '\x43', '\xef', '\x95', '\x50', '\x72', '\x25', '\x06', '\x28', '\x7a', + '\x7e', '\x99', '\xea', '\x4d', '\xe8', '\x87', '\xe5', '\xca', '\x71', + '\x36', '\x8a', '\xce', '\x18', '\x55', '\xe4', '\x87', '\x39', '\x3d', + '\xea', '\x9a', '\x22', '\x99', '\x1a', '\xab', '\xe3', '\x6f', '\x48', + '\x78', '\x49', '\x8f', '\xf6', '\xfa', '\xb1', '\xb8', '\x68', '\xae', + '\xc3', '\x47', '\x1d', '\x8f', '\x1d', '\x11', '\xa1', '\x06', '\xf5', + '\xc0', '\x0d', '\xcf', '\x7b', '\x33', '\xfe', '\x0c', '\x69', '\xca', + '\x46', '\xfe', '\x2c', '\xac', '\xd8', '\x4d', '\x02', '\x79', '\xfe', + '\x47', '\xca', '\x21', '\x30', '\x65', '\xa4', '\xe5', '\xaa', '\x4e', + '\x9c', '\xbc', '\xa5'}; + +QUIC_CONST_INIT const quiche::QuicheStringPiece kWildcardCertificatePrivateKey( + kWildcardCertificatePrivateKeyRaw, + sizeof(kWildcardCertificatePrivateKeyRaw)); + +} // namespace test +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/test_certificates.h b/chromium/net/third_party/quiche/src/quic/test_tools/test_certificates.h new file mode 100644 index 00000000000..ec4a4d407d5 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/test_tools/test_certificates.h @@ -0,0 +1,45 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_TEST_TOOLS_TEST_CERTIFICATES_H_ +#define QUICHE_QUIC_TEST_TOOLS_TEST_CERTIFICATES_H_ + +#include "net/third_party/quiche/src/quic/platform/api/quic_macros.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" + +namespace quic { +namespace test { + +// A test certificate generated by //net/tools/quic/certs/generate-certs.sh. +QUIC_CONST_INIT extern const quiche::QuicheStringPiece kTestCertificate; + +// PEM-encoded version of |kTestCertificate|. +QUIC_CONST_INIT extern const char kTestCertificatePem[]; + +// |kTestCertificatePem| with a PEM-encoded root appended to the end. +QUIC_CONST_INIT extern const char kTestCertificateChainPem[]; + +// DER-encoded private key for |kTestCertificate|. +QUIC_CONST_INIT extern const quiche::QuicheStringPiece + kTestCertificatePrivateKey; + +// PEM-encoded version of |kTestCertificatePrivateKey|. +QUIC_CONST_INIT extern const char kTestCertificatePrivateKeyPem[]; + +// The legacy PEM-encoded version of |kTestCertificatePrivateKey| manually +// generated from the one above using der2ascii. +QUIC_CONST_INIT extern const char kTestCertificatePrivateKeyLegacyPem[]; + +// Another DER-encoded test certificate, valid for foo.test, www.foo.test and +// *.wildcard.test. +QUIC_CONST_INIT extern const quiche::QuicheStringPiece kWildcardCertificate; + +// DER-encoded private key for |kWildcardCertificate|. +QUIC_CONST_INIT extern const quiche::QuicheStringPiece + kWildcardCertificatePrivateKey; + +} // namespace test +} // namespace quic + +#endif // QUICHE_QUIC_TEST_TOOLS_TEST_CERTIFICATES_H_ diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/test_ticket_crypter.cc b/chromium/net/third_party/quiche/src/quic/test_tools/test_ticket_crypter.cc new file mode 100644 index 00000000000..4d0d93e8f17 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/test_tools/test_ticket_crypter.cc @@ -0,0 +1,74 @@ +// Copyright (c) 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/test_tools/test_ticket_crypter.h" + +#include <cstring> + +#include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h" + +namespace quic { +namespace test { + +namespace { + +// A TicketCrypter implementation is supposed to encrypt and decrypt session +// tickets. However, the only requirement that is needed of a test +// implementation is that calling Decrypt(Encrypt(input), callback) results in +// callback being called with input. (The output of Encrypt must also not exceed +// the overhead specified by MaxOverhead.) This test implementation encrypts +// tickets by prepending kTicketPrefix to generate the ciphertext. The decrypt +// function checks that the prefix is present and strips it; otherwise it +// returns an empty vector to signal failure. +constexpr char kTicketPrefix[] = "TEST TICKET"; + +} // namespace + +size_t TestTicketCrypter::MaxOverhead() { + return QUICHE_ARRAYSIZE(kTicketPrefix); +} + +std::vector<uint8_t> TestTicketCrypter::Encrypt(quiche::QuicheStringPiece in) { + size_t prefix_len = QUICHE_ARRAYSIZE(kTicketPrefix); + std::vector<uint8_t> out(prefix_len + in.size()); + memcpy(out.data(), kTicketPrefix, prefix_len); + memcpy(out.data() + prefix_len, in.data(), in.size()); + return out; +} + +std::vector<uint8_t> TestTicketCrypter::Decrypt(quiche::QuicheStringPiece in) { + size_t prefix_len = QUICHE_ARRAYSIZE(kTicketPrefix); + if (fail_decrypt_ || in.size() < prefix_len || + memcmp(kTicketPrefix, in.data(), prefix_len) != 0) { + return std::vector<uint8_t>(); + } + return std::vector<uint8_t>(in.begin() + prefix_len, in.end()); +} + +void TestTicketCrypter::Decrypt( + quiche::QuicheStringPiece in, + std::unique_ptr<ProofSource::DecryptCallback> callback) { + auto decrypted_ticket = Decrypt(in); + if (run_async_) { + pending_callbacks_.push_back({std::move(callback), decrypted_ticket}); + } else { + callback->Run(decrypted_ticket); + } +} + +void TestTicketCrypter::SetRunCallbacksAsync(bool run_async) { + run_async_ = run_async; +} + +size_t TestTicketCrypter::NumPendingCallbacks() { + return pending_callbacks_.size(); +} + +void TestTicketCrypter::RunPendingCallback(size_t n) { + const PendingCallback& callback = pending_callbacks_[n]; + callback.callback->Run(callback.decrypted_ticket); +} + +} // namespace test +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/test_ticket_crypter.h b/chromium/net/third_party/quiche/src/quic/test_tools/test_ticket_crypter.h new file mode 100644 index 00000000000..b59634856c0 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/test_tools/test_ticket_crypter.h @@ -0,0 +1,49 @@ +// Copyright (c) 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_TEST_TOOLS_TEST_TICKET_CRYPTER_H_ +#define QUICHE_QUIC_TEST_TOOLS_TEST_TICKET_CRYPTER_H_ + +#include "net/third_party/quiche/src/quic/core/crypto/proof_source.h" + +namespace quic { +namespace test { + +// Provides a simple implementation of ProofSource::TicketCrypter for testing. +// THIS IMPLEMENTATION IS NOT SECURE. It is only intended for testing purposes. +class TestTicketCrypter : public ProofSource::TicketCrypter { + public: + ~TestTicketCrypter() override = default; + + // TicketCrypter interface + size_t MaxOverhead() override; + std::vector<uint8_t> Encrypt(quiche::QuicheStringPiece in) override; + void Decrypt(quiche::QuicheStringPiece in, + std::unique_ptr<ProofSource::DecryptCallback> callback) override; + + void SetRunCallbacksAsync(bool run_async); + size_t NumPendingCallbacks(); + void RunPendingCallback(size_t n); + + // Allows configuring this TestTicketCrypter to fail decryption. + void set_fail_decrypt(bool fail_decrypt) { fail_decrypt_ = fail_decrypt; } + + private: + // Performs the Decrypt operation synchronously. + std::vector<uint8_t> Decrypt(quiche::QuicheStringPiece in); + + struct PendingCallback { + std::unique_ptr<ProofSource::DecryptCallback> callback; + std::vector<uint8_t> decrypted_ticket; + }; + + bool fail_decrypt_ = false; + bool run_async_ = false; + std::vector<PendingCallback> pending_callbacks_; +}; + +} // namespace test +} // namespace quic + +#endif // QUICHE_QUIC_TEST_TOOLS_TEST_TICKET_CRYPTER_H_ diff --git a/chromium/net/third_party/quiche/src/quic/tools/fake_proof_verifier.h b/chromium/net/third_party/quiche/src/quic/tools/fake_proof_verifier.h index a605e071992..7f4a38ea5ec 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/fake_proof_verifier.h +++ b/chromium/net/third_party/quiche/src/quic/tools/fake_proof_verifier.h @@ -31,6 +31,7 @@ class FakeProofVerifier : public ProofVerifier { } QuicAsyncStatus VerifyCertChain( const std::string& /*hostname*/, + const uint16_t /*port*/, const std::vector<std::string>& /*certs*/, const std::string& /*ocsp_response*/, const std::string& /*cert_sct*/, 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 4b511849cb6..11edb195a9d 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 @@ -37,7 +37,9 @@ QuicClientBase::QuicClientBase( connection_error_(QUIC_NO_ERROR), connected_or_attempting_connect_(false), network_helper_(std::move(network_helper)), - connection_debug_visitor_(nullptr) {} + connection_debug_visitor_(nullptr), + server_connection_id_length_(kQuicDefaultConnectionIdLength), + client_connection_id_length_(0) {} QuicClientBase::~QuicClientBase() = default; @@ -306,11 +308,11 @@ QuicConnectionId QuicClientBase::GetNextServerDesignatedConnectionId() { } QuicConnectionId QuicClientBase::GenerateNewConnectionId() { - return QuicUtils::CreateRandomConnectionId(); + return QuicUtils::CreateRandomConnectionId(server_connection_id_length_); } QuicConnectionId QuicClientBase::GetClientConnectionId() { - return EmptyQuicConnectionId(); + return QuicUtils::CreateRandomConnectionId(client_connection_id_length_); } bool QuicClientBase::CanReconnectWithDifferentVersion( diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.h b/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.h index 6c1e09a78d0..0a40b82d64a 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.h +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.h @@ -230,6 +230,14 @@ class QuicClientBase { connection_debug_visitor_ = connection_debug_visitor; } + void set_server_connection_id_length(uint8_t server_connection_id_length) { + server_connection_id_length_ = server_connection_id_length; + } + + void set_client_connection_id_length(uint8_t client_connection_id_length) { + client_connection_id_length_ = client_connection_id_length; + } + protected: // TODO(rch): Move GetNumSentClientHellosFromSession and // GetNumReceivedServerConfigUpdatesFromSession into a new/better @@ -352,6 +360,14 @@ class QuicClientBase { // The debug visitor set on the connection right after it is constructed. // Not owned, must be valid for the lifetime of the QuicClientBase instance. QuicConnectionDebugVisitor* connection_debug_visitor_; + + // GenerateNewConnectionId creates a random connection ID of this length. + // Defaults to 8. + uint8_t server_connection_id_length_; + + // GetClientConnectionId creates a random connection ID of this length. + // Defaults to 0. + uint8_t client_connection_id_length_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client_interop_test_bin.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_client_interop_test_bin.cc index 9745955799f..803e313ea24 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_client_interop_test_bin.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client_interop_test_bin.cc @@ -105,20 +105,21 @@ class QuicClientInteropRunner : QuicConnectionDebugVisitor { QUIC_LOG(ERROR) << "Received unexpected GoogleQUIC connection close"; break; case IETF_QUIC_TRANSPORT_CONNECTION_CLOSE: - if (frame.transport_error_code == NO_IETF_QUIC_ERROR) { + if (frame.wire_error_code == NO_IETF_QUIC_ERROR) { InsertFeature(Feature::kConnectionClose); } else { QUIC_LOG(ERROR) << "Received transport connection close " << QuicIetfTransportErrorCodeString( - frame.transport_error_code); + static_cast<QuicIetfTransportErrorCodes>( + frame.wire_error_code)); } break; case IETF_QUIC_APPLICATION_CONNECTION_CLOSE: - if (frame.application_error_code == 0) { + if (frame.wire_error_code == 0) { InsertFeature(Feature::kConnectionClose); } else { QUIC_LOG(ERROR) << "Received application connection close " - << frame.application_error_code; + << frame.wire_error_code; } break; } @@ -166,7 +167,7 @@ void QuicClientInteropRunner::AttemptRequest(QuicSocketAddress addr, QuicEpollClock epoll_clock(&epoll_server); QuicConfig config; QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(20); - config.SetIdleNetworkTimeout(timeout, timeout); + config.SetIdleNetworkTimeout(timeout); auto client = std::make_unique<QuicClient>( addr, server_id, versions, config, &epoll_server, std::move(proof_verifier), std::move(session_cache)); @@ -261,7 +262,9 @@ void QuicClientInteropRunner::AttemptRequest(QuicSocketAddress addr, AttemptResumption(client.get()); } -std::set<Feature> ServerSupport(std::string host, int port) { +std::set<Feature> ServerSupport(std::string dns_host, + std::string url_host, + int port) { // Enable IETF version support. QuicVersionInitializeSupportForIetfDraft(); ParsedQuicVersion version = UnsupportedQuicVersion(); @@ -278,13 +281,13 @@ std::set<Feature> ServerSupport(std::string host, int port) { // Build the client, and try to connect. QuicSocketAddress addr = - tools::LookupAddress(host, quiche::QuicheStrCat(port)); + tools::LookupAddress(dns_host, quiche::QuicheStrCat(port)); if (!addr.IsInitialized()) { - QUIC_LOG(ERROR) << "Failed to resolve " << host; + QUIC_LOG(ERROR) << "Failed to resolve " << dns_host; return std::set<Feature>(); } - QuicServerId server_id(host, port, false); - std::string authority = quiche::QuicheStrCat(host, ":", port); + QuicServerId server_id(url_host, port, false); + std::string authority = quiche::QuicheStrCat(url_host, ":", port); QuicClientInteropRunner runner; @@ -307,13 +310,15 @@ int main(int argc, char* argv[]) { quic::QuicPrintCommandLineFlagHelp(usage); exit(1); } - std::string host = GetQuicFlag(FLAGS_host); + std::string dns_host = GetQuicFlag(FLAGS_host); + std::string url_host = ""; int port = GetQuicFlag(FLAGS_port); if (!args.empty()) { quic::QuicUrl url(args[0], "https"); - if (host.empty()) { - host = url.host(); + url_host = url.host(); + if (dns_host.empty()) { + dns_host = url_host; } if (port == 0) { port = url.port(); @@ -322,13 +327,16 @@ int main(int argc, char* argv[]) { if (port == 0) { port = 443; } - if (host.empty()) { + if (dns_host.empty()) { quic::QuicPrintCommandLineFlagHelp(usage); exit(1); } + if (url_host.empty()) { + url_host = dns_host; + } - auto supported_features = quic::ServerSupport(host, port); - std::cout << "Results for " << host << ":" << port << std::endl; + auto supported_features = quic::ServerSupport(dns_host, url_host, port); + std::cout << "Results for " << url_host << ":" << port << std::endl; int current_row = 1; for (auto feature : supported_features) { if (current_row < 2 && feature >= quic::Feature::kRebinding) { 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 38d445c6006..56a2323b190 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 @@ -178,7 +178,7 @@ class QuicMemoryCacheBackend : public QuicSimpleServerBackend { QuicBackendResponse::ServerPushInfo resource); // Cached responses. - QuicUnorderedMap<std::string, std::unique_ptr<QuicBackendResponse>> responses_ + QuicHashMap<std::string, std::unique_ptr<QuicBackendResponse>> responses_ QUIC_GUARDED_BY(response_mutex_); // The default response for cache misses, if set. diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_server_test.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_server_test.cc index fb7955f2554..3c4372018fb 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_server_test.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_server_test.cc @@ -48,10 +48,10 @@ class MockQuicSimpleDispatcher : public QuicSimpleDispatcher { kQuicDefaultConnectionIdLength) {} ~MockQuicSimpleDispatcher() override = default; - MOCK_METHOD0(OnCanWrite, void()); - MOCK_CONST_METHOD0(HasPendingWrites, bool()); - MOCK_CONST_METHOD0(HasChlosBuffered, bool()); - MOCK_METHOD1(ProcessBufferedChlos, void(size_t)); + MOCK_METHOD(void, OnCanWrite, (), (override)); + MOCK_METHOD(bool, HasPendingWrites, (), (const, override)); + MOCK_METHOD(bool, HasChlosBuffered, (), (const, override)); + MOCK_METHOD(void, ProcessBufferedChlos, (size_t), (override)); }; class TestQuicServer : public QuicServer { 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 5c83b4800fd..f84a248cda8 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 @@ -75,15 +75,14 @@ void QuicSimpleServerSession::PromisePushResources( spdy::SpdyHeaderBlock headers = SynthesizePushRequestHeaders( request_url, resource, original_request_headers); // TODO(b/136295430): Use sequential push IDs for IETF QUIC. - // TODO(bnc): If |highest_promised_stream_id_| is too large, it will always - // be skipped. Fix it by not incrementing if CanCreatePushStreamWithId() - // returns false. - highest_promised_stream_id_ += + auto new_highest_promised_stream_id = + highest_promised_stream_id_ + QuicUtils::StreamIdDelta(transport_version()); if (VersionUsesHttp3(transport_version()) && - !CanCreatePushStreamWithId(highest_promised_stream_id_)) { + !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( 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 f9c28a701d0..f5dad7d2d3f 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 @@ -95,8 +95,10 @@ class MockQuicCryptoServerStream : public QuicCryptoServerStream { delete; ~MockQuicCryptoServerStream() override {} - MOCK_METHOD1(SendServerConfigUpdate, - void(const CachedNetworkParameters* cached_network_parameters)); + MOCK_METHOD(void, + SendServerConfigUpdate, + (const CachedNetworkParameters*), + (override)); bool encryption_established() const override { return true; } }; @@ -104,15 +106,16 @@ class MockQuicCryptoServerStream : public QuicCryptoServerStream { class MockTlsServerHandshaker : public TlsServerHandshaker { public: explicit MockTlsServerHandshaker(QuicSession* session, - SSL_CTX* ssl_ctx, - ProofSource* proof_source) - : TlsServerHandshaker(session, ssl_ctx, proof_source) {} + const QuicCryptoServerConfig& crypto_config) + : TlsServerHandshaker(session, crypto_config) {} MockTlsServerHandshaker(const MockTlsServerHandshaker&) = delete; MockTlsServerHandshaker& operator=(const MockTlsServerHandshaker&) = delete; ~MockTlsServerHandshaker() override {} - MOCK_METHOD1(SendServerConfigUpdate, - void(const CachedNetworkParameters* cached_network_parameters)); + MOCK_METHOD(void, + SendServerConfigUpdate, + (const CachedNetworkParameters*), + (override)); bool encryption_established() const override { return true; } }; @@ -127,8 +130,7 @@ QuicCryptoServerStreamBase* CreateMockCryptoServerStream( return new MockQuicCryptoServerStream( crypto_config, compressed_certs_cache, session, helper); case PROTOCOL_TLS1_3: - return new MockTlsServerHandshaker(session, crypto_config->ssl_ctx(), - crypto_config->proof_source()); + return new MockTlsServerHandshaker(session, *crypto_config); case PROTOCOL_UNSUPPORTED: break; } @@ -158,11 +160,13 @@ class MockQuicConnectionWithSendStreamData : public MockQuicConnection { .WillByDefault(Invoke(consume_all_data)); } - MOCK_METHOD4(SendStreamData, - QuicConsumedData(QuicStreamId id, - size_t write_length, - QuicStreamOffset offset, - StreamSendingState state)); + MOCK_METHOD(QuicConsumedData, + SendStreamData, + (QuicStreamId id, + size_t write_length, + QuicStreamOffset offset, + StreamSendingState state), + (override)); }; class MockQuicSimpleServerSession : public QuicSimpleServerSession { @@ -191,12 +195,14 @@ class MockQuicSimpleServerSession : public QuicSimpleServerSession { return WritePushPromiseMock(original_stream_id, promised_stream_id, headers); } - MOCK_METHOD3(WritePushPromiseMock, - void(QuicStreamId original_stream_id, - QuicStreamId promised_stream_id, - const spdy::SpdyHeaderBlock& headers)); - - MOCK_METHOD1(SendBlocked, void(QuicStreamId)); + MOCK_METHOD(void, + WritePushPromiseMock, + (QuicStreamId original_stream_id, + QuicStreamId promised_stream_id, + const spdy::SpdyHeaderBlock& headers), + ()); + + MOCK_METHOD(void, SendBlocked, (QuicStreamId), (override)); }; class QuicSimpleServerSessionTest @@ -323,7 +329,7 @@ TEST_P(QuicSimpleServerSessionTest, CloseStreamDueToReset) { QuicStreamFrame data1(GetNthClientInitiatedBidirectionalId(0), false, 0, quiche::QuicheStringPiece("HT")); session_->OnStreamFrame(data1); - EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams()); + EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); // Receive a reset (and send a RST in response). QuicRstStreamFrame rst1(kInvalidControlFrameId, @@ -343,13 +349,13 @@ TEST_P(QuicSimpleServerSessionTest, CloseStreamDueToReset) { // a one-way close. InjectStopSending(GetNthClientInitiatedBidirectionalId(0), QUIC_ERROR_PROCESSING_STREAM); - EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); + EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); // Send the same two bytes of payload in a new packet. session_->OnStreamFrame(data1); // The stream should not be re-opened. - EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); + EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); EXPECT_TRUE(connection_->connected()); } @@ -373,7 +379,7 @@ TEST_P(QuicSimpleServerSessionTest, NeverOpenStreamDueToReset) { InjectStopSending(GetNthClientInitiatedBidirectionalId(0), QUIC_ERROR_PROCESSING_STREAM); - EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); + EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); // Send two bytes of payload. QuicStreamFrame data1(GetNthClientInitiatedBidirectionalId(0), false, 0, @@ -381,7 +387,7 @@ TEST_P(QuicSimpleServerSessionTest, NeverOpenStreamDueToReset) { session_->OnStreamFrame(data1); // The stream should never be opened, now that the reset is received. - EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); + EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); EXPECT_TRUE(connection_->connected()); } @@ -393,7 +399,7 @@ TEST_P(QuicSimpleServerSessionTest, AcceptClosedStream) { quiche::QuicheStringPiece("\2\0\0\0\0\0\0\0HT")); session_->OnStreamFrame(frame1); session_->OnStreamFrame(frame2); - EXPECT_EQ(2u, session_->GetNumOpenIncomingStreams()); + EXPECT_EQ(2u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); // Send a reset (and expect the peer to send a RST in response). QuicRstStreamFrame rst(kInvalidControlFrameId, @@ -424,7 +430,7 @@ TEST_P(QuicSimpleServerSessionTest, AcceptClosedStream) { session_->OnStreamFrame(frame3); session_->OnStreamFrame(frame4); // The stream should never be opened, now that the reset is received. - EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams()); + EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); EXPECT_TRUE(connection_->connected()); } @@ -435,12 +441,14 @@ TEST_P(QuicSimpleServerSessionTest, CreateIncomingStreamDisconnected) { } // Tests that incoming stream creation fails when connection is not connected. - size_t initial_num_open_stream = session_->GetNumOpenIncomingStreams(); + size_t initial_num_open_stream = + QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()); QuicConnectionPeer::TearDownLocalConnectionState(connection_); EXPECT_QUIC_BUG(QuicSimpleServerSessionPeer::CreateIncomingStream( session_.get(), GetNthClientInitiatedBidirectionalId(0)), "ShouldCreateIncomingStream called when disconnected"); - EXPECT_EQ(initial_num_open_stream, session_->GetNumOpenIncomingStreams()); + EXPECT_EQ(initial_num_open_stream, + QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); } TEST_P(QuicSimpleServerSessionTest, CreateIncomingStream) { @@ -457,14 +465,16 @@ TEST_P(QuicSimpleServerSessionTest, CreateOutgoingDynamicStreamDisconnected) { } // Tests that outgoing stream creation fails when connection is not connected. - size_t initial_num_open_stream = session_->GetNumOpenOutgoingStreams(); + size_t initial_num_open_stream = + QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()); QuicConnectionPeer::TearDownLocalConnectionState(connection_); EXPECT_QUIC_BUG( QuicSimpleServerSessionPeer::CreateOutgoingUnidirectionalStream( session_.get()), "ShouldCreateOutgoingUnidirectionalStream called when disconnected"); - EXPECT_EQ(initial_num_open_stream, session_->GetNumOpenOutgoingStreams()); + EXPECT_EQ(initial_num_open_stream, + QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); } TEST_P(QuicSimpleServerSessionTest, CreateOutgoingDynamicStreamUnencrypted) { @@ -475,12 +485,14 @@ TEST_P(QuicSimpleServerSessionTest, CreateOutgoingDynamicStreamUnencrypted) { // Tests that outgoing stream creation fails when encryption has not yet been // established. - size_t initial_num_open_stream = session_->GetNumOpenOutgoingStreams(); + size_t initial_num_open_stream = + QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()); EXPECT_QUIC_BUG( QuicSimpleServerSessionPeer::CreateOutgoingUnidirectionalStream( session_.get()), "Encryption not established so no outgoing stream created."); - EXPECT_EQ(initial_num_open_stream, session_->GetNumOpenOutgoingStreams()); + EXPECT_EQ(initial_num_open_stream, + QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); } TEST_P(QuicSimpleServerSessionTest, CreateOutgoingDynamicStreamUptoLimit) { @@ -493,8 +505,9 @@ TEST_P(QuicSimpleServerSessionTest, CreateOutgoingDynamicStreamUptoLimit) { QuicStreamFrame data1(GetNthClientInitiatedBidirectionalId(0), false, 0, quiche::QuicheStringPiece("HT")); session_->OnStreamFrame(data1); - EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams()); - EXPECT_EQ(0u, session_->GetNumOpenOutgoingStreams()); + EXPECT_EQ(1u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); + EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()) - + /*incoming=*/1); if (!VersionUsesHttp3(transport_version())) { session_->UnregisterStreamPriority( @@ -525,20 +538,24 @@ TEST_P(QuicSimpleServerSessionTest, CreateOutgoingDynamicStreamUptoLimit) { } else { EXPECT_EQ(GetNthServerInitiatedUnidirectionalId(i), created_stream->id()); } - EXPECT_EQ(i + 1, session_->GetNumOpenOutgoingStreams()); + EXPECT_EQ(i + 1, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()) - + /*incoming=*/1); } // Continuing creating push stream would fail. EXPECT_EQ(nullptr, QuicSimpleServerSessionPeer::CreateOutgoingUnidirectionalStream( session_.get())); - EXPECT_EQ(kMaxStreamsForTest, session_->GetNumOpenOutgoingStreams()); + EXPECT_EQ(kMaxStreamsForTest, + QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()) - + /*incoming=*/1); // Create peer initiated stream should have no problem. QuicStreamFrame data2(GetNthClientInitiatedBidirectionalId(1), false, 0, quiche::QuicheStringPiece("HT")); session_->OnStreamFrame(data2); - EXPECT_EQ(2u, session_->GetNumOpenIncomingStreams()); + EXPECT_EQ(2u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()) - + /*outcoming=*/kMaxStreamsForTest); } TEST_P(QuicSimpleServerSessionTest, OnStreamFrameWithEvenStreamId) { @@ -553,7 +570,8 @@ TEST_P(QuicSimpleServerSessionTest, OnStreamFrameWithEvenStreamId) { // Tests that calling GetOrCreateStream() on an outgoing stream not promised yet // should result close connection. TEST_P(QuicSimpleServerSessionTest, GetEvenIncomingError) { - const size_t initial_num_open_stream = session_->GetNumOpenIncomingStreams(); + const size_t initial_num_open_stream = + QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()); const QuicErrorCode expected_error = VersionUsesHttp3(transport_version()) ? QUIC_HTTP_STREAM_WRONG_DIRECTION : QUIC_INVALID_STREAM_ID; @@ -562,7 +580,8 @@ TEST_P(QuicSimpleServerSessionTest, GetEvenIncomingError) { EXPECT_EQ(nullptr, QuicSessionPeer::GetOrCreateStream( session_.get(), GetNthServerInitiatedUnidirectionalId(3))); - EXPECT_EQ(initial_num_open_stream, session_->GetNumOpenIncomingStreams()); + EXPECT_EQ(initial_num_open_stream, + QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); } // In order to test the case where server push stream creation goes beyond @@ -761,7 +780,8 @@ TEST_P(QuicSimpleServerSessionServerPushTest, TestPromisePushResources) { } size_t num_resources = kMaxStreamsForTest + 5; PromisePushResources(num_resources); - EXPECT_EQ(kMaxStreamsForTest, session_->GetNumOpenOutgoingStreams()); + EXPECT_EQ(kMaxStreamsForTest, + QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); } // Tests that after promised stream queued up, when an opened stream is marked @@ -827,13 +847,16 @@ TEST_P(QuicSimpleServerSessionServerPushTest, } if (VersionUsesHttp3(transport_version())) { - session_->StreamDraining(GetNthServerInitiatedUnidirectionalId(3)); + session_->StreamDraining(GetNthServerInitiatedUnidirectionalId(3), + /*unidirectional=*/true); } else { - session_->StreamDraining(GetNthServerInitiatedUnidirectionalId(0)); + 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, session_->GetNumOpenOutgoingStreams()); + EXPECT_EQ(kMaxStreamsForTest, + QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); } // Tests that after all resources are promised, a RST frame from client can @@ -926,8 +949,10 @@ TEST_P(QuicSimpleServerSessionServerPushTest, session_->OnMaxStreamsFrame( QuicMaxStreamsFrame(0, num_resources + 3, /*unidirectional=*/true)); } - session_->StreamDraining(GetNthServerInitiatedUnidirectionalId(3)); - session_->StreamDraining(GetNthServerInitiatedUnidirectionalId(4)); + 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 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 06e886680a4..3dfaa1e3d22 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 @@ -55,7 +55,7 @@ class TestStream : public QuicSimpleServerStream { ~TestStream() override = default; - MOCK_METHOD1(WriteHeadersMock, void(bool fin)); + MOCK_METHOD(void, WriteHeadersMock, (bool fin), ()); size_t WriteHeaders(spdy::SpdyHeaderBlock /*header_block*/, bool fin, @@ -120,30 +120,42 @@ class MockQuicSimpleServerSession : public QuicSimpleServerSession { delete; ~MockQuicSimpleServerSession() override = default; - MOCK_METHOD2(OnConnectionClosed, - void(const QuicConnectionCloseFrame& frame, - ConnectionCloseSource source)); - MOCK_METHOD1(CreateIncomingStream, QuicSpdyStream*(QuicStreamId id)); - MOCK_METHOD6(WritevData, - QuicConsumedData(QuicStreamId id, - size_t write_length, - QuicStreamOffset offset, - StreamSendingState state, - TransmissionType type, - quiche::QuicheOptional<EncryptionLevel> level)); - MOCK_METHOD4(OnStreamHeaderList, - void(QuicStreamId stream_id, - bool fin, - size_t frame_len, - const QuicHeaderList& header_list)); - MOCK_METHOD2(OnStreamHeadersPriority, - void(QuicStreamId stream_id, - const spdy::SpdyStreamPrecedence& precedence)); - MOCK_METHOD3(SendRstStream, - void(QuicStreamId stream_id, - QuicRstStreamErrorCode error, - QuicStreamOffset bytes_written)); - MOCK_METHOD1(OnHeadersHeadOfLineBlocking, void(QuicTime::Delta delta)); + MOCK_METHOD(void, + OnConnectionClosed, + (const QuicConnectionCloseFrame& frame, + ConnectionCloseSource source), + (override)); + MOCK_METHOD(QuicSpdyStream*, + CreateIncomingStream, + (QuicStreamId id), + (override)); + MOCK_METHOD(QuicConsumedData, + WritevData, + (QuicStreamId id, + size_t write_length, + QuicStreamOffset offset, + StreamSendingState state, + TransmissionType type, + quiche::QuicheOptional<EncryptionLevel> level), + (override)); + MOCK_METHOD(void, + OnStreamHeaderList, + (QuicStreamId stream_id, + bool fin, + size_t frame_len, + const QuicHeaderList& header_list), + (override)); + MOCK_METHOD(void, + OnStreamHeadersPriority, + (QuicStreamId stream_id, + const spdy::SpdyStreamPrecedence& precedence), + (override)); + MOCK_METHOD(void, + SendRstStream, + (QuicStreamId stream_id, + QuicRstStreamErrorCode error, + QuicStreamOffset bytes_written), + (override)); // Matchers cannot be used on non-copyable types like SpdyHeaderBlock. void PromisePushResources( const std::string& request_url, @@ -155,17 +167,17 @@ class MockQuicSimpleServerSession : public QuicSimpleServerSession { PromisePushResourcesMock(request_url, resources, original_stream_id, original_precedence, original_request_headers); } - MOCK_METHOD5(PromisePushResourcesMock, - void(const std::string&, - const std::list<QuicBackendResponse::ServerPushInfo>&, - QuicStreamId, - const spdy::SpdyStreamPrecedence&, - const spdy::SpdyHeaderBlock&)); + MOCK_METHOD(void, + PromisePushResourcesMock, + (const std::string&, + const std::list<QuicBackendResponse::ServerPushInfo>&, + QuicStreamId, + const spdy::SpdyStreamPrecedence&, + const spdy::SpdyHeaderBlock&), + ()); using QuicSession::ActivateStream; - MOCK_METHOD1(OnStopSendingReceived, void(const QuicStopSendingFrame& frame)); - QuicConsumedData ConsumeData( QuicStreamId id, size_t write_length, @@ -322,7 +334,7 @@ TEST_P(QuicSimpleServerStreamTest, SendQuicRstStreamNoErrorInStopReading) { EXPECT_FALSE(stream_->fin_received()); EXPECT_FALSE(stream_->rst_received()); - stream_->set_fin_sent(true); + QuicStreamPeer::SetFinSent(stream_); stream_->CloseWriteSide(); EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(1); @@ -383,7 +395,7 @@ TEST_P(QuicSimpleServerStreamTest, SendResponseWithIllegalResponseStatus) { memory_cache_backend_.AddResponse("www.google.com", "/bar", std::move(response_headers_), body); - stream_->set_fin_received(true); + QuicStreamPeer::SetFinReceived(stream_); InSequence s; EXPECT_CALL(*stream_, WriteHeadersMock(false)); @@ -416,7 +428,7 @@ TEST_P(QuicSimpleServerStreamTest, SendResponseWithIllegalResponseStatus2) { memory_cache_backend_.AddResponse("www.google.com", "/bar", std::move(response_headers_), body); - stream_->set_fin_received(true); + QuicStreamPeer::SetFinReceived(stream_); InSequence s; EXPECT_CALL(*stream_, WriteHeadersMock(false)); @@ -476,7 +488,7 @@ TEST_P(QuicSimpleServerStreamTest, SendResponseWithValidHeaders) { memory_cache_backend_.AddResponse("www.google.com", "/bar", std::move(response_headers_), body); - stream_->set_fin_received(true); + QuicStreamPeer::SetFinReceived(stream_); InSequence s; EXPECT_CALL(*stream_, WriteHeadersMock(false)); @@ -514,7 +526,7 @@ TEST_P(QuicSimpleServerStreamTest, SendResponseWithPushResources) { (*request_headers)[":authority"] = host; (*request_headers)[":method"] = "GET"; - stream_->set_fin_received(true); + QuicStreamPeer::SetFinReceived(stream_); InSequence s; EXPECT_CALL(session_, PromisePushResourcesMock( host + request_path, _, @@ -592,7 +604,7 @@ TEST_P(QuicSimpleServerStreamTest, PushResponseOnServerInitiatedStream) { TEST_P(QuicSimpleServerStreamTest, TestSendErrorResponse) { EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0); - stream_->set_fin_received(true); + QuicStreamPeer::SetFinReceived(stream_); InSequence s; EXPECT_CALL(*stream_, WriteHeadersMock(false)); 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 a944d6079df..1bb01efdb72 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 @@ -50,8 +50,7 @@ QuicSpdyClientBase::QuicSpdyClientBase( std::move(session_cache)), store_response_(false), latest_response_code_(-1), - max_allowed_push_id_(0), - disable_qpack_dynamic_table_(false) {} + max_allowed_push_id_(0) {} QuicSpdyClientBase::~QuicSpdyClientBase() { // We own the push promise index. We need to explicitly kill @@ -64,10 +63,6 @@ QuicSpdyClientSession* QuicSpdyClientBase::client_session() { } void QuicSpdyClientBase::InitializeSession() { - if (disable_qpack_dynamic_table_) { - client_session()->set_qpack_maximum_dynamic_table_capacity(0); - client_session()->set_qpack_maximum_blocked_streams(0); - } client_session()->Initialize(); client_session()->CryptoConnect(); if (max_allowed_push_id_ > 0 && diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.h b/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.h index c4381f7538f..a6d4f8690ff 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.h +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.h @@ -140,11 +140,7 @@ class QuicSpdyClientBase : public QuicClientBase, // Set the max promise id for the client session. // TODO(b/151641466): Rename this method. - void SetMaxAllowedPushId(QuicStreamId max) { max_allowed_push_id_ = max; } - - // Disables the use of the QPACK dynamic table and of blocked streams. - // Must be called before InitializeSession(). - void disable_qpack_dynamic_table() { disable_qpack_dynamic_table_ = true; } + void SetMaxAllowedPushId(PushId max) { max_allowed_push_id_ = max; } bool EarlyDataAccepted() override; bool ReceivedInchoateReject() override; @@ -224,9 +220,7 @@ class QuicSpdyClientBase : public QuicClientBase, bool drop_response_body_ = false; // The max promise id to set on the client session when created. - QuicStreamId max_allowed_push_id_; - - bool disable_qpack_dynamic_table_; + PushId max_allowed_push_id_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.h b/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.h index 432980531be..46dd7954a25 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.h +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.h @@ -59,9 +59,8 @@ class QuicTcpLikeTraceConverter { bool fin; }; - QuicUnorderedMap<QuicStreamId, StreamInfo> streams_info_; - QuicUnorderedMap<QuicControlFrameId, QuicInterval<uint64_t>> - control_frames_info_; + QuicHashMap<QuicStreamId, StreamInfo> streams_info_; + QuicHashMap<QuicControlFrameId, QuicInterval<uint64_t>> control_frames_info_; QuicControlFrameId largest_observed_control_frame_id_; 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 5733e0bb0d7..0018f0524b7 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 @@ -165,6 +165,16 @@ DEFINE_QUIC_COMMAND_LINE_FLAG( false, "If true, do not change local port after each request."); +DEFINE_QUIC_COMMAND_LINE_FLAG(int32_t, + server_connection_id_length, + -1, + "Length of the server connection ID used."); + +DEFINE_QUIC_COMMAND_LINE_FLAG(int32_t, + client_connection_id_length, + -1, + "Length of the client connection ID used."); + namespace quic { QuicToyClient::QuicToyClient(ClientFactory* client_factory) @@ -235,6 +245,16 @@ int QuicToyClient::SendRequestsAndPrintResponses( client->set_initial_max_packet_length( initial_mtu != 0 ? initial_mtu : quic::kDefaultMaxPacketSize); client->set_drop_response_body(GetQuicFlag(FLAGS_drop_response_body)); + const int32_t server_connection_id_length = + GetQuicFlag(FLAGS_server_connection_id_length); + if (server_connection_id_length >= 0) { + client->set_server_connection_id_length(server_connection_id_length); + } + const int32_t client_connection_id_length = + GetQuicFlag(FLAGS_client_connection_id_length); + if (client_connection_id_length >= 0) { + client->set_client_connection_id_length(client_connection_id_length); + } if (!client->Initialize()) { std::cerr << "Failed to initialize client." << std::endl; return 1; diff --git a/chromium/net/third_party/quiche/src/quic/tools/simple_ticket_crypter.cc b/chromium/net/third_party/quiche/src/quic/tools/simple_ticket_crypter.cc new file mode 100644 index 00000000000..3da114e5526 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/tools/simple_ticket_crypter.cc @@ -0,0 +1,109 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/tools/simple_ticket_crypter.h" + +#include "third_party/boringssl/src/include/openssl/aead.h" +#include "third_party/boringssl/src/include/openssl/rand.h" + +namespace quic { + +namespace { + +constexpr QuicTime::Delta kTicketKeyLifetime = + QuicTime::Delta::FromSeconds(60 * 60 * 24 * 7); + +// The format of an encrypted ticket is 1 byte for the key epoch, followed by +// 16 bytes of IV, followed by the output from the AES-GCM Seal operation. The +// seal operation has an overhead of 16 bytes for its auth tag. +constexpr size_t kEpochSize = 1; +constexpr size_t kIVSize = 16; +constexpr size_t kAuthTagSize = 16; + +// Offsets into the ciphertext to make message parsing easier. +constexpr size_t kIVOffset = kEpochSize; +constexpr size_t kMessageOffset = kIVOffset + kIVSize; + +} // namespace + +SimpleTicketCrypter::SimpleTicketCrypter(QuicClock* clock) : clock_(clock) { + RAND_bytes(&key_epoch_, 1); + current_key_ = NewKey(); +} + +SimpleTicketCrypter::~SimpleTicketCrypter() = default; + +size_t SimpleTicketCrypter::MaxOverhead() { + return kEpochSize + kIVSize + kAuthTagSize; +} + +std::vector<uint8_t> SimpleTicketCrypter::Encrypt( + quiche::QuicheStringPiece in) { + MaybeRotateKeys(); + std::vector<uint8_t> out(in.size() + MaxOverhead()); + out[0] = key_epoch_; + RAND_bytes(out.data() + kIVOffset, kIVSize); + size_t out_len; + const EVP_AEAD_CTX* ctx = current_key_->aead_ctx.get(); + if (!EVP_AEAD_CTX_seal(ctx, out.data() + kMessageOffset, &out_len, + out.size() - kMessageOffset, out.data() + kIVOffset, + kIVSize, reinterpret_cast<const uint8_t*>(in.data()), + in.size(), nullptr, 0)) { + return std::vector<uint8_t>(); + } + out.resize(out_len + kMessageOffset); + return out; +} + +std::vector<uint8_t> SimpleTicketCrypter::Decrypt( + quiche::QuicheStringPiece in) { + MaybeRotateKeys(); + if (in.size() < kMessageOffset) { + return std::vector<uint8_t>(); + } + const uint8_t* input = reinterpret_cast<const uint8_t*>(in.data()); + std::vector<uint8_t> out(in.size() - kMessageOffset); + size_t out_len; + const EVP_AEAD_CTX* ctx = current_key_->aead_ctx.get(); + if (input[0] != key_epoch_) { + if (input[0] == static_cast<uint8_t>(key_epoch_ - 1) && previous_key_) { + ctx = previous_key_->aead_ctx.get(); + } else { + return std::vector<uint8_t>(); + } + } + if (!EVP_AEAD_CTX_open(ctx, out.data(), &out_len, out.size(), + input + kIVOffset, kIVSize, input + kMessageOffset, + in.size() - kMessageOffset, nullptr, 0)) { + return std::vector<uint8_t>(); + } + out.resize(out_len); + return out; +} + +void SimpleTicketCrypter::Decrypt( + quiche::QuicheStringPiece in, + std::unique_ptr<quic::ProofSource::DecryptCallback> callback) { + callback->Run(Decrypt(in)); +} + +void SimpleTicketCrypter::MaybeRotateKeys() { + QuicTime now = clock_->ApproximateNow(); + if (current_key_->expiration < now) { + previous_key_ = std::move(current_key_); + current_key_ = NewKey(); + key_epoch_++; + } +} + +std::unique_ptr<SimpleTicketCrypter::Key> SimpleTicketCrypter::NewKey() { + auto key = std::make_unique<SimpleTicketCrypter::Key>(); + RAND_bytes(key->key, kKeySize); + EVP_AEAD_CTX_init(key->aead_ctx.get(), EVP_aead_aes_128_gcm(), key->key, + kKeySize, EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr); + key->expiration = clock_->ApproximateNow() + kTicketKeyLifetime; + return key; +} + +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/tools/simple_ticket_crypter.h b/chromium/net/third_party/quiche/src/quic/tools/simple_ticket_crypter.h new file mode 100644 index 00000000000..330c5091094 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/tools/simple_ticket_crypter.h @@ -0,0 +1,55 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_TOOLS_SIMPLE_TICKET_CRYPTER_H_ +#define QUICHE_QUIC_TOOLS_SIMPLE_TICKET_CRYPTER_H_ + +#include "third_party/boringssl/src/include/openssl/aead.h" +#include "net/third_party/quiche/src/quic/core/crypto/proof_source.h" +#include "net/third_party/quiche/src/quic/core/quic_clock.h" +#include "net/third_party/quiche/src/quic/core/quic_time.h" + +namespace quic { + +// SimpleTicketCrypter implements the QUIC ProofSource::TicketCrypter interface. +// It generates a random key at startup and every 7 days it rotates the key, +// keeping track of the previous key used to facilitate decrypting older +// tickets. This implementation is not suitable for server setups where multiple +// servers need to share keys. +class QUIC_NO_EXPORT SimpleTicketCrypter + : public quic::ProofSource::TicketCrypter { + public: + explicit SimpleTicketCrypter(QuicClock* clock); + ~SimpleTicketCrypter() override; + + size_t MaxOverhead() override; + std::vector<uint8_t> Encrypt(quiche::QuicheStringPiece in) override; + void Decrypt( + quiche::QuicheStringPiece in, + std::unique_ptr<quic::ProofSource::DecryptCallback> callback) override; + + private: + std::vector<uint8_t> Decrypt(quiche::QuicheStringPiece in); + + void MaybeRotateKeys(); + + static constexpr size_t kKeySize = 16; + + struct Key { + uint8_t key[kKeySize]; + bssl::ScopedEVP_AEAD_CTX aead_ctx; + QuicTime expiration = QuicTime::Zero(); + }; + + std::unique_ptr<Key> NewKey(); + + std::unique_ptr<Key> current_key_; + std::unique_ptr<Key> previous_key_; + uint8_t key_epoch_ = 0; + QuicClock* clock_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_TOOLS_SIMPLE_TICKET_CRYPTER_H_ diff --git a/chromium/net/third_party/quiche/src/quic/tools/simple_ticket_crypter_test.cc b/chromium/net/third_party/quiche/src/quic/tools/simple_ticket_crypter_test.cc new file mode 100644 index 00000000000..e609dc03571 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/tools/simple_ticket_crypter_test.cc @@ -0,0 +1,112 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/tools/simple_ticket_crypter.h" + +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h" + +namespace quic { +namespace test { + +namespace { + +constexpr QuicTime::Delta kOneDay = QuicTime::Delta::FromSeconds(60 * 60 * 24); + +} // namespace + +class DecryptCallback : public quic::ProofSource::DecryptCallback { + public: + explicit DecryptCallback(std::vector<uint8_t>* out) : out_(out) {} + + void Run(std::vector<uint8_t> plaintext) override { *out_ = plaintext; } + + private: + std::vector<uint8_t>* out_; +}; + +quiche::QuicheStringPiece StringPiece(const std::vector<uint8_t>& in) { + return quiche::QuicheStringPiece(reinterpret_cast<const char*>(in.data()), + in.size()); +} + +class SimpleTicketCrypterTest : public QuicTest { + public: + SimpleTicketCrypterTest() : ticket_crypter_(&mock_clock_) {} + + protected: + MockClock mock_clock_; + SimpleTicketCrypter ticket_crypter_; +}; + +TEST_F(SimpleTicketCrypterTest, EncryptDecrypt) { + std::vector<uint8_t> plaintext = {1, 2, 3, 4, 5}; + std::vector<uint8_t> ciphertext = + ticket_crypter_.Encrypt(StringPiece(plaintext)); + EXPECT_NE(plaintext, ciphertext); + + std::vector<uint8_t> out_plaintext; + ticket_crypter_.Decrypt(StringPiece(ciphertext), + std::make_unique<DecryptCallback>(&out_plaintext)); + EXPECT_EQ(out_plaintext, plaintext); +} + +TEST_F(SimpleTicketCrypterTest, CiphertextsDiffer) { + std::vector<uint8_t> plaintext = {1, 2, 3, 4, 5}; + std::vector<uint8_t> ciphertext1 = + ticket_crypter_.Encrypt(StringPiece(plaintext)); + std::vector<uint8_t> ciphertext2 = + ticket_crypter_.Encrypt(StringPiece(plaintext)); + EXPECT_NE(ciphertext1, ciphertext2); +} + +TEST_F(SimpleTicketCrypterTest, DecryptionFailureWithModifiedCiphertext) { + std::vector<uint8_t> plaintext = {1, 2, 3, 4, 5}; + std::vector<uint8_t> ciphertext = + ticket_crypter_.Encrypt(StringPiece(plaintext)); + EXPECT_NE(plaintext, ciphertext); + + // Check that a bit flip in any byte will cause a decryption failure. + for (size_t i = 0; i < ciphertext.size(); i++) { + SCOPED_TRACE(i); + std::vector<uint8_t> munged_ciphertext = ciphertext; + munged_ciphertext[i] ^= 1; + std::vector<uint8_t> out_plaintext; + ticket_crypter_.Decrypt(StringPiece(munged_ciphertext), + std::make_unique<DecryptCallback>(&out_plaintext)); + EXPECT_TRUE(out_plaintext.empty()); + } +} + +TEST_F(SimpleTicketCrypterTest, DecryptionFailureWithEmptyCiphertext) { + std::vector<uint8_t> out_plaintext; + ticket_crypter_.Decrypt(quiche::QuicheStringPiece(), + std::make_unique<DecryptCallback>(&out_plaintext)); + EXPECT_TRUE(out_plaintext.empty()); +} + +TEST_F(SimpleTicketCrypterTest, KeyRotation) { + std::vector<uint8_t> plaintext = {1, 2, 3}; + std::vector<uint8_t> ciphertext = + ticket_crypter_.Encrypt(StringPiece(plaintext)); + EXPECT_FALSE(ciphertext.empty()); + + // Advance the clock 8 days, so the key used for |ciphertext| is now the + // previous key. Check that decryption still works. + mock_clock_.AdvanceTime(kOneDay * 8); + std::vector<uint8_t> out_plaintext; + ticket_crypter_.Decrypt(StringPiece(ciphertext), + std::make_unique<DecryptCallback>(&out_plaintext)); + EXPECT_EQ(out_plaintext, plaintext); + + // Advance the clock 8 more days. Now the original key should be expired and + // decryption should fail. + mock_clock_.AdvanceTime(kOneDay * 8); + ticket_crypter_.Decrypt(StringPiece(ciphertext), + std::make_unique<DecryptCallback>(&out_plaintext)); + EXPECT_TRUE(out_plaintext.empty()); +} + +} // namespace test +} // namespace quic 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 8a4e17a0f53..4c44635e938 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 @@ -50,7 +50,6 @@ bool HpackDecoderAdapter::HandleControlFrameHeadersData( header_block_started_ = true; if (!hpack_decoder_.StartDecodingBlock()) { header_block_started_ = false; - SPDY_CODE_COUNT_N(decompress_failure_2, 1, 5); error_ = hpack_decoder_.error(); return false; } @@ -65,14 +64,12 @@ bool HpackDecoderAdapter::HandleControlFrameHeadersData( SPDY_DVLOG(1) << "max_decode_buffer_size_bytes_ < headers_data_length: " << max_decode_buffer_size_bytes_ << " < " << headers_data_length; - SPDY_CODE_COUNT_N(decompress_failure_2, 2, 5); error_ = http2::HpackDecodingError::kFragmentTooLong; return false; } listener_adapter_.AddToTotalHpackBytes(headers_data_length); if (max_header_block_bytes_ != 0 && listener_adapter_.total_hpack_bytes() > max_header_block_bytes_) { - SPDY_CODE_COUNT_N(decompress_failure, 3, 5); error_ = http2::HpackDecodingError::kCompressedHeaderSizeExceedsLimit; return false; } @@ -80,7 +77,6 @@ bool HpackDecoderAdapter::HandleControlFrameHeadersData( bool ok = hpack_decoder_.DecodeFragment(&db); DCHECK(!ok || db.Empty()) << "Remaining=" << db.Remaining(); if (!ok) { - SPDY_CODE_COUNT_N(decompress_failure_2, 4, 5); error_ = hpack_decoder_.error(); } return ok; @@ -96,7 +92,6 @@ bool HpackDecoderAdapter::HandleControlFrameHeadersComplete( } if (!hpack_decoder_.EndDecodingBlock()) { SPDY_DVLOG(3) << "EndDecodingBlock returned false"; - SPDY_CODE_COUNT_N(decompress_failure_2, 5, 5); error_ = hpack_decoder_.error(); return false; } 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 3835047e8b2..e3bf8f64c15 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 @@ -13,6 +13,7 @@ #include "net/third_party/quiche/src/spdy/core/hpack/hpack_huffman_table.h" #include "net/third_party/quiche/src/spdy/core/hpack/hpack_output_stream.h" #include "net/third_party/quiche/src/spdy/platform/api/spdy_estimate_memory_usage.h" +#include "net/third_party/quiche/src/spdy/platform/api/spdy_flags.h" #include "net/third_party/quiche/src/spdy/platform/api/spdy_logging.h" namespace spdy { @@ -146,10 +147,10 @@ void HpackEncoder::EncodeRepresentations(RepresentationIterator* iter, } else if (should_index_(header.first, header.second)) { EmitIndexedLiteral(header); } else { - EmitNonIndexedLiteral(header); + EmitNonIndexedLiteral(header, enable_compression_); } } else { - EmitNonIndexedLiteral(header); + EmitNonIndexedLiteral(header, enable_compression_); } } @@ -170,12 +171,25 @@ void HpackEncoder::EmitIndexedLiteral(const Representation& representation) { header_table_.TryAddEntry(representation.first, representation.second); } -void HpackEncoder::EmitNonIndexedLiteral(const Representation& representation) { +void HpackEncoder::EmitNonIndexedLiteral(const Representation& representation, + bool enable_compression) { SPDY_DVLOG(2) << "Emitting nonindexed literal: (" << representation.first << ", " << representation.second << ")"; output_stream_.AppendPrefix(kLiteralNoIndexOpcode); - output_stream_.AppendUint32(0); - EmitString(representation.first); + if (GetSpdyReloadableFlag(spdy_hpack_use_indexed_name)) { + SPDY_CODE_COUNT(spdy_hpack_use_indexed_name); + const HpackEntry* name_entry = + header_table_.GetByName(representation.first); + if (enable_compression && name_entry != nullptr) { + output_stream_.AppendUint32(header_table_.IndexOf(name_entry)); + } else { + output_stream_.AppendUint32(0); + EmitString(representation.first); + } + } else { + output_stream_.AppendUint32(0); + EmitString(representation.first); + } EmitString(representation.second); } @@ -347,14 +361,14 @@ void HpackEncoder::Encoderator::Next(size_t max_encoded_bytes, std::string* output) { SPDY_BUG_IF(!has_next_) << "Encoderator::Next called with nothing left to encode."; - const bool use_compression = encoder_->enable_compression_; + const bool enable_compression = encoder_->enable_compression_; // Encode up to max_encoded_bytes of headers. while (header_it_->HasNext() && encoder_->output_stream_.size() <= max_encoded_bytes) { const Representation header = header_it_->Next(); encoder_->listener_(header.first, header.second); - if (use_compression) { + if (enable_compression) { const HpackEntry* entry = encoder_->header_table_.GetByNameAndValue( header.first, header.second); if (entry != nullptr) { @@ -362,10 +376,10 @@ void HpackEncoder::Encoderator::Next(size_t max_encoded_bytes, } else if (encoder_->should_index_(header.first, header.second)) { encoder_->EmitIndexedLiteral(header); } else { - encoder_->EmitNonIndexedLiteral(header); + encoder_->EmitNonIndexedLiteral(header, enable_compression); } } else { - encoder_->EmitNonIndexedLiteral(header); + encoder_->EmitNonIndexedLiteral(header, enable_compression); } } diff --git a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.h b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.h index c3d3a1974d6..534b9e6c086 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.h +++ b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.h @@ -122,7 +122,8 @@ class QUICHE_EXPORT_PRIVATE HpackEncoder { // Emits a literal representation (Section 7.2). void EmitIndexedLiteral(const Representation& representation); - void EmitNonIndexedLiteral(const Representation& representation); + void EmitNonIndexedLiteral(const Representation& representation, + bool enable_compression); void EmitLiteral(const Representation& representation); // Emits a Huffman or identity string (whichever is smaller). 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 2ac0a5f8db4..2b1efe973b8 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 @@ -11,6 +11,7 @@ #include "net/third_party/quiche/src/common/platform/api/quiche_test.h" #include "net/third_party/quiche/src/spdy/core/hpack/hpack_huffman_table.h" #include "net/third_party/quiche/src/spdy/core/spdy_simple_arena.h" +#include "net/third_party/quiche/src/spdy/platform/api/spdy_flags.h" namespace spdy { @@ -182,6 +183,12 @@ class HpackEncoderTestBase : public QuicheTest { ExpectString(&expected_, name); ExpectString(&expected_, value); } + void ExpectNonIndexedLiteralWithNameIndex(const HpackEntry* key_entry, + quiche::QuicheStringPiece value) { + expected_.AppendPrefix(kLiteralNoIndexOpcode); + expected_.AppendUint32(IndexOf(key_entry)); + ExpectString(&expected_, value); + } void ExpectString(HpackOutputStream* stream, quiche::QuicheStringPiece str) { const HpackHuffmanTable& huffman_table = peer_.huffman_table(); size_t encoded_size = peer_.compression_enabled() @@ -267,7 +274,12 @@ TEST_F(HpackEncoderTestBase, EncodeRepresentations) { {"accept", "text/html, text/plain,application/xml"}, {"cookie", "val4"}, {"withnul", quiche::QuicheStringPiece("one\0two", 7)}}; - ExpectNonIndexedLiteral(":path", "/home"); + if (GetSpdyReloadableFlag(spdy_hpack_use_indexed_name)) { + ExpectNonIndexedLiteralWithNameIndex(peer_.table()->GetByName(":path"), + "/home"); + } else { + ExpectNonIndexedLiteral(":path", "/home"); + } ExpectIndexedLiteral(peer_.table()->GetByName("cookie"), "val1"); ExpectIndexedLiteral(peer_.table()->GetByName("cookie"), "val2"); ExpectIndexedLiteral(peer_.table()->GetByName("cookie"), "val3"); @@ -554,7 +566,12 @@ TEST_P(HpackEncoderTest, PseudoHeadersFirst) { // Headers are indexed in the order in which they were added. // This entry pushes "cookie: a=bb" back to 63. - ExpectNonIndexedLiteral(":path", "/spam/eggs.html"); + if (GetSpdyReloadableFlag(spdy_hpack_use_indexed_name)) { + ExpectNonIndexedLiteralWithNameIndex(peer_.table()->GetByName(":path"), + "/spam/eggs.html"); + } else { + ExpectNonIndexedLiteral(":path", "/spam/eggs.html"); + } ExpectIndexedLiteral(peer_.table()->GetByName(":authority"), "www.example.com"); ExpectIndexedLiteral("-foo", "bar"); 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 df600473d7b..f23b583e0f9 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 @@ -92,12 +92,6 @@ void CorruptFrameHeader(Http2FrameHeader* /*header*/) {} Http2DecoderAdapter::SpdyFramerError HpackDecodingErrorToSpdyFramerError( HpackDecodingError error) { - if (!GetSpdyReloadableFlag(spdy_enable_granular_decompress_errors)) { - return Http2DecoderAdapter::SpdyFramerError::SPDY_DECOMPRESS_FAILURE; - } - - SPDY_CODE_COUNT(spdy_enable_granular_decompress_errors); - switch (error) { case HpackDecodingError::kOk: return Http2DecoderAdapter::SpdyFramerError::SPDY_NO_ERROR; 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 3505e8911af..7e76a26d85e 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 @@ -231,7 +231,7 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface, public: // This is larger than our max frame size because header blocks that // are too long can spill over into CONTINUATION frames. - static const size_t kDefaultHeaderBufferSize = 16 * 1024 * 1024; + static constexpr size_t kDefaultHeaderBufferSize = 16 * 1024 * 1024; explicit TestSpdyVisitor(SpdyFramer::CompressionOption option) : framer_(option), 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 d6b7abc53e2..90493e11b5a 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 @@ -1,5 +1,7 @@ #include "net/third_party/quiche/src/spdy/core/spdy_header_storage.h" +#include <cstring> + #include "net/third_party/quiche/src/spdy/platform/api/spdy_logging.h" namespace spdy { 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 54723da996e..0bf8bb9d69f 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 @@ -319,8 +319,6 @@ const size_t kGetAltSvcFrameMinimumSize = kFrameHeaderSize + 2; const size_t kMaxFrameSizeLimit = kSpdyMaxFrameSizeLimit + kFrameHeaderSize; // Size of a header block size field. const size_t kSizeOfSizeField = sizeof(uint32_t); -// Per-header overhead for block size accounting in bytes. -const size_t kPerHeaderOverhead = 32; // Initial window size for a stream in bytes. const int32_t kInitialStreamWindowSize = 64 * 1024 - 1; // Initial window size for a session in bytes. 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 f7d48b47017..d6745bf09fc 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 @@ -5,6 +5,7 @@ #include "net/third_party/quiche/src/spdy/core/spdy_simple_arena.h" #include <algorithm> +#include <cstring> #include "net/third_party/quiche/src/spdy/platform/api/spdy_logging.h" |