Project import generated by Copybara.
PiperOrigin-RevId: 235760953
Change-Id: I302811f663a1f4772520f3fa3148e54851e0227a
diff --git a/http2/decoder/payload_decoders/altsvc_payload_decoder_test.cc b/http2/decoder/payload_decoders/altsvc_payload_decoder_test.cc
index bf928d3..0221328 100644
--- a/http2/decoder/payload_decoders/altsvc_payload_decoder_test.cc
+++ b/http2/decoder/payload_decoders/altsvc_payload_decoder_test.cc
@@ -96,10 +96,9 @@
const uint32_t value_length_;
};
-INSTANTIATE_TEST_CASE_P(VariousOriginAndValueLengths,
- AltSvcPayloadLengthTests,
- ::testing::Combine(::testing::Values(0, 1, 3, 65535),
- ::testing::Values(0, 1, 3, 65537)));
+INSTANTIATE_TEST_SUITE_P(VariousOriginAndValueLengths, AltSvcPayloadLengthTests,
+ ::testing::Combine(::testing::Values(0, 1, 3, 65535),
+ ::testing::Values(0, 1, 3, 65537)));
TEST_P(AltSvcPayloadLengthTests, ValidOriginAndValueLength) {
Http2String origin = Random().RandString(origin_length_);
diff --git a/http2/decoder/payload_decoders/continuation_payload_decoder_test.cc b/http2/decoder/payload_decoders/continuation_payload_decoder_test.cc
index 63888d3..6e81828 100644
--- a/http2/decoder/payload_decoders/continuation_payload_decoder_test.cc
+++ b/http2/decoder/payload_decoders/continuation_payload_decoder_test.cc
@@ -67,9 +67,8 @@
const uint32_t length_;
};
-INSTANTIATE_TEST_CASE_P(VariousLengths,
- ContinuationPayloadDecoderTest,
- ::testing::Values(0, 1, 2, 3, 4, 5, 6));
+INSTANTIATE_TEST_SUITE_P(VariousLengths, ContinuationPayloadDecoderTest,
+ ::testing::Values(0, 1, 2, 3, 4, 5, 6));
TEST_P(ContinuationPayloadDecoderTest, ValidLength) {
Http2String hpack_payload = Random().RandString(length_);
diff --git a/http2/decoder/payload_decoders/data_payload_decoder_test.cc b/http2/decoder/payload_decoders/data_payload_decoder_test.cc
index e5253b9..0622f17 100644
--- a/http2/decoder/payload_decoders/data_payload_decoder_test.cc
+++ b/http2/decoder/payload_decoders/data_payload_decoder_test.cc
@@ -98,9 +98,8 @@
}
};
-INSTANTIATE_TEST_CASE_P(VariousPadLengths,
- DataPayloadDecoderTest,
- ::testing::Values(0, 1, 2, 3, 4, 254, 255, 256));
+INSTANTIATE_TEST_SUITE_P(VariousPadLengths, DataPayloadDecoderTest,
+ ::testing::Values(0, 1, 2, 3, 4, 254, 255, 256));
TEST_P(DataPayloadDecoderTest, VariousDataPayloadSizes) {
for (size_t data_size : {0, 1, 2, 3, 255, 256, 1024}) {
diff --git a/http2/decoder/payload_decoders/goaway_payload_decoder_test.cc b/http2/decoder/payload_decoders/goaway_payload_decoder_test.cc
index 1df5214..c90cdcc 100644
--- a/http2/decoder/payload_decoders/goaway_payload_decoder_test.cc
+++ b/http2/decoder/payload_decoders/goaway_payload_decoder_test.cc
@@ -83,9 +83,8 @@
const uint32_t length_;
};
-INSTANTIATE_TEST_CASE_P(VariousLengths,
- GoAwayOpaqueDataLengthTests,
- ::testing::Values(0, 1, 2, 3, 4, 5, 6));
+INSTANTIATE_TEST_SUITE_P(VariousLengths, GoAwayOpaqueDataLengthTests,
+ ::testing::Values(0, 1, 2, 3, 4, 5, 6));
TEST_P(GoAwayOpaqueDataLengthTests, ValidLength) {
Http2GoAwayFields goaway;
diff --git a/http2/decoder/payload_decoders/headers_payload_decoder_test.cc b/http2/decoder/payload_decoders/headers_payload_decoder_test.cc
index a6fcb65..cb58b8e 100644
--- a/http2/decoder/payload_decoders/headers_payload_decoder_test.cc
+++ b/http2/decoder/payload_decoders/headers_payload_decoder_test.cc
@@ -94,9 +94,8 @@
HeadersPayloadDecoderPeer,
Listener> {};
-INSTANTIATE_TEST_CASE_P(VariousPadLengths,
- HeadersPayloadDecoderTest,
- ::testing::Values(0, 1, 2, 3, 4, 254, 255, 256));
+INSTANTIATE_TEST_SUITE_P(VariousPadLengths, HeadersPayloadDecoderTest,
+ ::testing::Values(0, 1, 2, 3, 4, 254, 255, 256));
// Decode various sizes of (fake) HPACK payload, both with and without the
// PRIORITY flag set.
diff --git a/http2/decoder/payload_decoders/push_promise_payload_decoder_test.cc b/http2/decoder/payload_decoders/push_promise_payload_decoder_test.cc
index 9d55a80..94220f7 100644
--- a/http2/decoder/payload_decoders/push_promise_payload_decoder_test.cc
+++ b/http2/decoder/payload_decoders/push_promise_payload_decoder_test.cc
@@ -87,9 +87,8 @@
PushPromisePayloadDecoderPeer,
Listener> {};
-INSTANTIATE_TEST_CASE_P(VariousPadLengths,
- PushPromisePayloadDecoderTest,
- ::testing::Values(0, 1, 2, 3, 4, 254, 255, 256));
+INSTANTIATE_TEST_SUITE_P(VariousPadLengths, PushPromisePayloadDecoderTest,
+ ::testing::Values(0, 1, 2, 3, 4, 254, 255, 256));
// Payload contains the required Http2PushPromiseFields, followed by some
// (fake) HPACK payload.
diff --git a/http2/decoder/payload_decoders/unknown_payload_decoder_test.cc b/http2/decoder/payload_decoders/unknown_payload_decoder_test.cc
index 7ba95f7..f9d203a 100644
--- a/http2/decoder/payload_decoders/unknown_payload_decoder_test.cc
+++ b/http2/decoder/payload_decoders/unknown_payload_decoder_test.cc
@@ -77,9 +77,8 @@
const uint32_t length_;
};
-INSTANTIATE_TEST_CASE_P(VariousLengths,
- UnknownPayloadDecoderTest,
- ::testing::Values(0, 1, 2, 3, 255, 256));
+INSTANTIATE_TEST_SUITE_P(VariousLengths, UnknownPayloadDecoderTest,
+ ::testing::Values(0, 1, 2, 3, 255, 256));
TEST_P(UnknownPayloadDecoderTest, ValidLength) {
Http2String unknown_payload = Random().RandString(length_);
diff --git a/http2/hpack/decoder/hpack_decoder_test.cc b/http2/hpack/decoder/hpack_decoder_test.cc
index 563e977..83a0ede 100644
--- a/http2/hpack/decoder/hpack_decoder_test.cc
+++ b/http2/hpack/decoder/hpack_decoder_test.cc
@@ -224,7 +224,7 @@
bool saw_start_ = false;
bool saw_end_ = false;
};
-INSTANTIATE_TEST_CASE_P(AllWays, HpackDecoderTest, ::testing::Bool());
+INSTANTIATE_TEST_SUITE_P(AllWays, HpackDecoderTest, ::testing::Bool());
// Test based on RFC 7541, section C.3: Request Examples without Huffman Coding.
// This section shows several consecutive header lists, corresponding to HTTP
diff --git a/http2/hpack/decoder/hpack_entry_decoder_test.cc b/http2/hpack/decoder/hpack_entry_decoder_test.cc
index 7249bd5..b447e82 100644
--- a/http2/hpack/decoder/hpack_entry_decoder_test.cc
+++ b/http2/hpack/decoder/hpack_entry_decoder_test.cc
@@ -157,9 +157,8 @@
const HpackEntryType entry_type_;
};
-INSTANTIATE_TEST_CASE_P(
- AllLiteralTypes,
- HpackLiteralEntryDecoderTest,
+INSTANTIATE_TEST_SUITE_P(
+ AllLiteralTypes, HpackLiteralEntryDecoderTest,
testing::Values(HpackEntryType::kIndexedLiteralHeader,
HpackEntryType::kUnindexedLiteralHeader,
HpackEntryType::kNeverIndexedLiteralHeader));
diff --git a/http2/hpack/huffman/hpack_huffman_transcoder_test.cc b/http2/hpack/huffman/hpack_huffman_transcoder_test.cc
index cfd73b5..2791d6a 100644
--- a/http2/hpack/huffman/hpack_huffman_transcoder_test.cc
+++ b/http2/hpack/huffman/hpack_huffman_transcoder_test.cc
@@ -139,9 +139,9 @@
const char c_;
};
-INSTANTIATE_TEST_CASE_P(HpackHuffmanTranscoderAdjacentCharTest,
- HpackHuffmanTranscoderAdjacentCharTest,
- ::testing::Range(0, 256));
+INSTANTIATE_TEST_SUITE_P(HpackHuffmanTranscoderAdjacentCharTest,
+ HpackHuffmanTranscoderAdjacentCharTest,
+ ::testing::Range(0, 256));
// Test c_ adjacent to every other character, both before and after.
TEST_P(HpackHuffmanTranscoderAdjacentCharTest, RoundTripAdjacentChar) {
@@ -169,11 +169,11 @@
const size_t length_;
};
-INSTANTIATE_TEST_CASE_P(
- HpackHuffmanTranscoderRepeatedCharTest,
- HpackHuffmanTranscoderRepeatedCharTest,
- ::testing::Combine(::testing::Range(0, 256),
- ::testing::Values(1, 2, 3, 4, 8, 16, 32)));
+INSTANTIATE_TEST_SUITE_P(HpackHuffmanTranscoderRepeatedCharTest,
+ HpackHuffmanTranscoderRepeatedCharTest,
+ ::testing::Combine(::testing::Range(0, 256),
+ ::testing::Values(1, 2, 3, 4, 8, 16,
+ 32)));
TEST_P(HpackHuffmanTranscoderRepeatedCharTest, RoundTripRepeatedChar) {
ASSERT_TRUE(TranscodeAndValidateSeveralWays(MakeString()));
diff --git a/http2/hpack/varint/hpack_varint_decoder_test.cc b/http2/hpack/varint/hpack_varint_decoder_test.cc
index 32a4a30..2d589fd 100644
--- a/http2/hpack/varint/hpack_varint_decoder_test.cc
+++ b/http2/hpack/varint/hpack_varint_decoder_test.cc
@@ -107,9 +107,8 @@
uint8_t prefix_length_;
};
-INSTANTIATE_TEST_CASE_P(
- HpackVarintDecoderTest,
- HpackVarintDecoderTest,
+INSTANTIATE_TEST_SUITE_P(
+ HpackVarintDecoderTest, HpackVarintDecoderTest,
::testing::Combine(
// Bits of the first byte not part of the prefix should be ignored.
::testing::Values(0b00000000, 0b11111111, 0b10101010),
diff --git a/http2/http2_structures_test.cc b/http2/http2_structures_test.cc
index 30ebb36..78107f7 100644
--- a/http2/http2_structures_test.cc
+++ b/http2/http2_structures_test.cc
@@ -163,10 +163,9 @@
};
class IsEndStreamTest : public Http2FrameHeaderTypeAndFlagTest {};
-INSTANTIATE_TEST_CASE_P(IsEndStream,
- IsEndStreamTest,
- Combine(ValuesIn(ValidFrameTypes()),
- Values(~Http2FrameFlag::END_STREAM, 0xff)));
+INSTANTIATE_TEST_SUITE_P(IsEndStream, IsEndStreamTest,
+ Combine(ValuesIn(ValidFrameTypes()),
+ Values(~Http2FrameFlag::END_STREAM, 0xff)));
TEST_P(IsEndStreamTest, IsEndStream) {
const bool is_set =
(flags_ & Http2FrameFlag::END_STREAM) == Http2FrameFlag::END_STREAM;
@@ -201,10 +200,9 @@
}
class IsACKTest : public Http2FrameHeaderTypeAndFlagTest {};
-INSTANTIATE_TEST_CASE_P(IsAck,
- IsACKTest,
- Combine(ValuesIn(ValidFrameTypes()),
- Values(~Http2FrameFlag::ACK, 0xff)));
+INSTANTIATE_TEST_SUITE_P(IsAck, IsACKTest,
+ Combine(ValuesIn(ValidFrameTypes()),
+ Values(~Http2FrameFlag::ACK, 0xff)));
TEST_P(IsACKTest, IsAck) {
const bool is_set = (flags_ & Http2FrameFlag::ACK) == Http2FrameFlag::ACK;
Http2String flags_string;
@@ -238,10 +236,9 @@
}
class IsEndHeadersTest : public Http2FrameHeaderTypeAndFlagTest {};
-INSTANTIATE_TEST_CASE_P(IsEndHeaders,
- IsEndHeadersTest,
- Combine(ValuesIn(ValidFrameTypes()),
- Values(~Http2FrameFlag::END_HEADERS, 0xff)));
+INSTANTIATE_TEST_SUITE_P(IsEndHeaders, IsEndHeadersTest,
+ Combine(ValuesIn(ValidFrameTypes()),
+ Values(~Http2FrameFlag::END_HEADERS, 0xff)));
TEST_P(IsEndHeadersTest, IsEndHeaders) {
const bool is_set =
(flags_ & Http2FrameFlag::END_HEADERS) == Http2FrameFlag::END_HEADERS;
@@ -279,10 +276,9 @@
}
class IsPaddedTest : public Http2FrameHeaderTypeAndFlagTest {};
-INSTANTIATE_TEST_CASE_P(IsPadded,
- IsPaddedTest,
- Combine(ValuesIn(ValidFrameTypes()),
- Values(~Http2FrameFlag::PADDED, 0xff)));
+INSTANTIATE_TEST_SUITE_P(IsPadded, IsPaddedTest,
+ Combine(ValuesIn(ValidFrameTypes()),
+ Values(~Http2FrameFlag::PADDED, 0xff)));
TEST_P(IsPaddedTest, IsPadded) {
const bool is_set =
(flags_ & Http2FrameFlag::PADDED) == Http2FrameFlag::PADDED;
@@ -318,10 +314,9 @@
}
class HasPriorityTest : public Http2FrameHeaderTypeAndFlagTest {};
-INSTANTIATE_TEST_CASE_P(HasPriority,
- HasPriorityTest,
- Combine(ValuesIn(ValidFrameTypes()),
- Values(~Http2FrameFlag::PRIORITY, 0xff)));
+INSTANTIATE_TEST_SUITE_P(HasPriority, HasPriorityTest,
+ Combine(ValuesIn(ValidFrameTypes()),
+ Values(~Http2FrameFlag::PRIORITY, 0xff)));
TEST_P(HasPriorityTest, HasPriority) {
const bool is_set =
(flags_ & Http2FrameFlag::PRIORITY) == Http2FrameFlag::PRIORITY;
diff --git a/quic/core/chlo_extractor.cc b/quic/core/chlo_extractor.cc
index b44aa9c..caf0af1 100644
--- a/quic/core/chlo_extractor.cc
+++ b/quic/core/chlo_extractor.cc
@@ -39,6 +39,7 @@
bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override;
void OnDecryptedPacket(EncryptionLevel level) override {}
bool OnPacketHeader(const QuicPacketHeader& header) override;
+ void OnCoalescedPacket(const QuicEncryptedPacket& packet) override;
bool OnStreamFrame(const QuicStreamFrame& frame) override;
bool OnCryptoFrame(const QuicCryptoFrame& frame) override;
bool OnAckFrameStart(QuicPacketNumber largest_acked,
@@ -75,6 +76,9 @@
void OnError(CryptoFramer* framer) override;
void OnHandshakeMessage(const CryptoHandshakeMessage& message) override;
+ // Shared implementation between OnStreamFrame and OnCryptoFrame.
+ bool OnHandshakeData(QuicStringPiece data);
+
bool found_chlo() { return found_chlo_; }
bool chlo_contains_tags() { return chlo_contains_tags_; }
@@ -119,39 +123,56 @@
bool ChloFramerVisitor::OnPacketHeader(const QuicPacketHeader& header) {
return true;
}
+void ChloFramerVisitor::OnCoalescedPacket(const QuicEncryptedPacket& packet) {}
bool ChloFramerVisitor::OnStreamFrame(const QuicStreamFrame& frame) {
+ if (framer_->transport_version() >= QUIC_VERSION_47) {
+ // CHLO will be sent in CRYPTO frames in v47 and above.
+ return false;
+ }
QuicStringPiece data(frame.data_buffer, frame.data_length);
if (frame.stream_id ==
QuicUtils::GetCryptoStreamId(framer_->transport_version()) &&
frame.offset == 0 && QuicTextUtils::StartsWith(data, "CHLO")) {
- CryptoFramer crypto_framer;
- crypto_framer.set_visitor(this);
- if (!crypto_framer.ProcessInput(data)) {
- return false;
- }
- // Interrogate the crypto framer and see if there are any
- // intersecting tags between what we saw in the maybe-CHLO and the
- // indicator set.
- for (const QuicTag tag : create_session_tag_indicators_) {
- if (crypto_framer.HasTag(tag)) {
- chlo_contains_tags_ = true;
- }
- }
- if (chlo_contains_tags_ && delegate_) {
- // Unfortunately, because this is a partial CHLO,
- // OnHandshakeMessage was never called, so the ALPN was never
- // extracted. Fake it up a bit and send it to the delegate so that
- // the correct dispatch can happen.
- crypto_framer.ForceHandshake();
- }
+ return OnHandshakeData(data);
}
-
return true;
}
bool ChloFramerVisitor::OnCryptoFrame(const QuicCryptoFrame& frame) {
- // TODO(nharper): Implement.
- return false;
+ if (framer_->transport_version() < QUIC_VERSION_47) {
+ // CHLO will be in stream frames before v47.
+ return false;
+ }
+ QuicStringPiece data(frame.data_buffer, frame.data_length);
+ if (frame.offset == 0 && QuicTextUtils::StartsWith(data, "CHLO")) {
+ return OnHandshakeData(data);
+ }
+ return true;
+}
+
+bool ChloFramerVisitor::OnHandshakeData(QuicStringPiece data) {
+ CryptoFramer crypto_framer;
+ crypto_framer.set_visitor(this);
+ if (!crypto_framer.ProcessInput(data)) {
+ return false;
+ }
+ // Interrogate the crypto framer and see if there are any
+ // intersecting tags between what we saw in the maybe-CHLO and the
+ // indicator set.
+ for (const QuicTag tag : create_session_tag_indicators_) {
+ if (crypto_framer.HasTag(tag)) {
+ chlo_contains_tags_ = true;
+ }
+ }
+ if (chlo_contains_tags_ && delegate_) {
+ // Unfortunately, because this is a partial CHLO,
+ // OnHandshakeMessage was never called, so the ALPN was never
+ // extracted. Fake it up a bit and send it to the delegate so that
+ // the correct dispatch can happen.
+ crypto_framer.ForceHandshake();
+ }
+
+ return true;
}
bool ChloFramerVisitor::OnAckFrameStart(QuicPacketNumber /*largest_acked*/,
diff --git a/quic/core/chlo_extractor_test.cc b/quic/core/chlo_extractor_test.cc
index d16050b..e8b6483 100644
--- a/quic/core/chlo_extractor_test.cc
+++ b/quic/core/chlo_extractor_test.cc
@@ -53,14 +53,35 @@
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;
+ }
}
- void MakePacket(const QuicStreamFrame& stream_frame) {
- QuicFrame frame(stream_frame);
+ void MakePacket(ParsedQuicVersion version,
+ QuicStringPiece data,
+ bool munge_offset,
+ bool munge_stream_id) {
QuicFrames frames;
- frames.push_back(frame);
+ size_t offset = 0;
+ if (munge_offset) {
+ offset++;
+ }
QuicFramer framer(SupportedVersions(header_.version), QuicTime::Zero(),
Perspective::IS_CLIENT);
+ if (version.transport_version < QUIC_VERSION_47 || munge_stream_id) {
+ QuicStreamId stream_id =
+ QuicUtils::GetCryptoStreamId(version.transport_version);
+ if (munge_stream_id) {
+ stream_id++;
+ }
+ frames.push_back(
+ QuicFrame(QuicStreamFrame(stream_id, false, offset, data)));
+ } else {
+ frames.push_back(
+ QuicFrame(new QuicCryptoFrame(ENCRYPTION_NONE, offset, data)));
+ }
std::unique_ptr<QuicPacket> packet(
BuildUnsizedDataPacket(&framer, header_, frames));
EXPECT_TRUE(packet != nullptr);
@@ -70,6 +91,7 @@
ASSERT_NE(0u, encrypted_length);
packet_ = QuicMakeUnique<QuicEncryptedPacket>(buffer_, encrypted_length);
EXPECT_TRUE(packet_ != nullptr);
+ DeleteFrames(&frames);
}
protected:
@@ -86,11 +108,19 @@
QuicString client_hello_str(client_hello.GetSerialized().AsStringPiece());
// Construct a CHLO with each supported version
for (ParsedQuicVersion version : AllSupportedVersions()) {
+ SCOPED_TRACE(version);
ParsedQuicVersionVector versions(SupportedVersions(version));
header_.version = version;
- MakePacket(
- QuicStreamFrame(QuicUtils::GetCryptoStreamId(version.transport_version),
- false, 0, client_hello_str));
+ 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_, versions, {}, &delegate_))
<< ParsedQuicVersionToString(version);
EXPECT_EQ(version.transport_version, delegate_.transport_version());
@@ -105,10 +135,8 @@
client_hello.set_tag(kCHLO);
QuicString client_hello_str(client_hello.GetSerialized().AsStringPiece());
- MakePacket(QuicStreamFrame(QuicUtils::GetCryptoStreamId(
- AllSupportedVersions()[0].transport_version) +
- 1,
- false, 0, client_hello_str));
+ MakePacket(AllSupportedVersions()[0], client_hello_str,
+ /*munge_offset*/ false, /*munge_stream_id*/ true);
EXPECT_FALSE(
ChloExtractor::Extract(*packet_, AllSupportedVersions(), {}, &delegate_));
}
@@ -118,17 +146,15 @@
client_hello.set_tag(kCHLO);
QuicString client_hello_str(client_hello.GetSerialized().AsStringPiece());
- MakePacket(QuicStreamFrame(
- QuicUtils::GetCryptoStreamId(AllSupportedVersions()[0].transport_version),
- false, 1, client_hello_str));
+ MakePacket(AllSupportedVersions()[0], client_hello_str, /*munge_offset*/ true,
+ /*munge_stream_id*/ false);
EXPECT_FALSE(
ChloExtractor::Extract(*packet_, AllSupportedVersions(), {}, &delegate_));
}
TEST_F(ChloExtractorTest, DoesNotFindInvalidChlo) {
- MakePacket(QuicStreamFrame(
- QuicUtils::GetCryptoStreamId(AllSupportedVersions()[0].transport_version),
- false, 0, "foo"));
+ MakePacket(AllSupportedVersions()[0], "foo", /*munge_offset*/ false,
+ /*munge_stream_id*/ true);
EXPECT_FALSE(
ChloExtractor::Extract(*packet_, AllSupportedVersions(), {}, &delegate_));
}
diff --git a/quic/core/congestion_control/general_loss_algorithm.cc b/quic/core/congestion_control/general_loss_algorithm.cc
index 27a3ab8..8cd5e71 100644
--- a/quic/core/congestion_control/general_loss_algorithm.cc
+++ b/quic/core/congestion_control/general_loss_algorithm.cc
@@ -32,7 +32,7 @@
GeneralLossAlgorithm::GeneralLossAlgorithm(LossDetectionType loss_type)
: loss_detection_timeout_(QuicTime::Zero()),
least_in_flight_(1),
- faster_detect_loss_(GetQuicReloadableFlag(quic_faster_detect_loss)) {
+ packet_number_space_(NUM_PACKET_NUMBER_SPACES) {
SetLossDetectionType(loss_type);
}
@@ -64,16 +64,14 @@
const AckedPacketVector& packets_acked,
LostPacketVector* packets_lost) {
loss_detection_timeout_ = QuicTime::Zero();
- if (faster_detect_loss_ && !packets_acked.empty() &&
+ if (!packets_acked.empty() &&
packets_acked.front().packet_number == least_in_flight_) {
if (least_in_flight_ + packets_acked.size() - 1 == largest_newly_acked) {
// Optimization for the case when no packet is missing.
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_faster_detect_loss, 1, 3);
least_in_flight_ = largest_newly_acked + 1;
largest_previously_acked_ = largest_newly_acked;
return;
}
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_faster_detect_loss, 2, 3);
// There is hole in acked_packets, increment least_in_flight_ if possible.
for (const auto& acked : packets_acked) {
if (acked.packet_number != least_in_flight_) {
@@ -89,34 +87,29 @@
max_rtt + (max_rtt >> reordering_shift_));
QuicPacketNumber packet_number = unacked_packets.GetLeastUnacked();
auto it = unacked_packets.begin();
- if (faster_detect_loss_) {
- if (least_in_flight_.IsInitialized() && least_in_flight_ >= packet_number) {
- if (least_in_flight_ > unacked_packets.largest_sent_packet() + 1) {
- QUIC_BUG << "least_in_flight: " << least_in_flight_
- << " is greater than largest_sent_packet + 1: "
- << unacked_packets.largest_sent_packet() + 1;
- } else {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_faster_detect_loss, 3, 3);
- it += (least_in_flight_ - packet_number);
- packet_number = least_in_flight_;
- }
- }
- // Clear least_in_flight_.
- least_in_flight_.Clear();
- } else {
- if (largest_lost_.IsInitialized() && largest_lost_ >= packet_number) {
- if (largest_lost_ > unacked_packets.largest_sent_packet()) {
- QUIC_BUG << "largest_lost: " << largest_lost_
- << " is greater than largest_sent_packet: "
- << unacked_packets.largest_sent_packet();
- } else {
- it += (largest_lost_ - packet_number + 1);
- packet_number = largest_lost_ + 1;
- }
+ if (least_in_flight_.IsInitialized() && least_in_flight_ >= packet_number) {
+ if (least_in_flight_ > unacked_packets.largest_sent_packet() + 1) {
+ QUIC_BUG << "least_in_flight: " << least_in_flight_
+ << " is greater than largest_sent_packet + 1: "
+ << unacked_packets.largest_sent_packet() + 1;
+ } else {
+ it += (least_in_flight_ - packet_number);
+ packet_number = least_in_flight_;
}
}
+ // Clear least_in_flight_.
+ least_in_flight_.Clear();
+ DCHECK(!unacked_packets.use_uber_loss_algorithm() ||
+ packet_number_space_ ==
+ unacked_packets.GetPacketNumberSpace(largest_newly_acked));
for (; it != unacked_packets.end() && packet_number <= largest_newly_acked;
++it, ++packet_number) {
+ if (unacked_packets.use_uber_loss_algorithm() &&
+ unacked_packets.GetPacketNumberSpace(it->encryption_level) !=
+ packet_number_space_) {
+ // Skip packets of different packet number space.
+ continue;
+ }
if (!it->in_flight) {
continue;
}
@@ -144,8 +137,18 @@
// Only early retransmit(RFC5827) when the last packet gets acked and
// there are retransmittable packets in flight.
// This also implements a timer-protected variant of FACK.
- if (unacked_packets.largest_sent_retransmittable_packet() <=
- largest_newly_acked ||
+ QuicPacketNumber largest_sent_retransmittable_packet;
+ if (unacked_packets.use_uber_loss_algorithm()) {
+ // Use largest_sent_retransmittable_packet of corresponding packet number
+ // space for timer based loss detection.
+ largest_sent_retransmittable_packet =
+ unacked_packets.GetLargestSentRetransmittableOfPacketNumberSpace(
+ packet_number_space_);
+ } else {
+ largest_sent_retransmittable_packet =
+ unacked_packets.largest_sent_retransmittable_packet();
+ }
+ if (largest_sent_retransmittable_packet <= largest_newly_acked ||
loss_type_ == kTime || loss_type_ == kAdaptiveTime) {
QuicTime when_lost = it->sent_time + loss_delay;
if (time < when_lost) {
@@ -176,11 +179,6 @@
least_in_flight_ = largest_newly_acked + 1;
}
largest_previously_acked_ = largest_newly_acked;
- if (!packets_lost->empty()) {
- DCHECK(!largest_lost_.IsInitialized() ||
- largest_lost_ < packets_lost->back().packet_number);
- largest_lost_ = packets_lost->back().packet_number;
- }
}
QuicTime GeneralLossAlgorithm::GetLossTimeout() const {
@@ -225,4 +223,14 @@
} while (proposed_extra_time < extra_time_needed && reordering_shift_ > 0);
}
+void GeneralLossAlgorithm::SetPacketNumberSpace(
+ PacketNumberSpace packet_number_space) {
+ if (packet_number_space_ < NUM_PACKET_NUMBER_SPACES) {
+ QUIC_BUG << "Cannot switch packet_number_space";
+ return;
+ }
+
+ packet_number_space_ = packet_number_space;
+}
+
} // namespace quic
diff --git a/quic/core/congestion_control/general_loss_algorithm.h b/quic/core/congestion_control/general_loss_algorithm.h
index 0d8e565..a2bcadd 100644
--- a/quic/core/congestion_control/general_loss_algorithm.h
+++ b/quic/core/congestion_control/general_loss_algorithm.h
@@ -55,6 +55,8 @@
const RttStats& rtt_stats,
QuicPacketNumber spurious_retransmission) override;
+ void SetPacketNumberSpace(PacketNumberSpace packet_number_space);
+
int reordering_shift() const { return reordering_shift_; }
private:
@@ -71,15 +73,11 @@
int reordering_shift_;
// The largest newly acked from the previous call to DetectLosses.
QuicPacketNumber largest_previously_acked_;
- // The largest lost packet.
- // TODO(fayang): Remove this variable when deprecating
- // quic_faster_detect_loss.
- QuicPacketNumber largest_lost_;
// The least in flight packet. Loss detection should start from this. Please
// note, least_in_flight_ could be largest packet ever sent + 1.
QuicPacketNumber least_in_flight_;
- // Latched value of quic_faster_detect_loss flag.
- const bool faster_detect_loss_;
+ // This is only used when quic_use_uber_loss_algorithm is true.
+ PacketNumberSpace packet_number_space_;
};
} // namespace quic
diff --git a/quic/core/congestion_control/general_loss_algorithm_test.cc b/quic/core/congestion_control/general_loss_algorithm_test.cc
index 2cd19a7..91a25da 100644
--- a/quic/core/congestion_control/general_loss_algorithm_test.cc
+++ b/quic/core/congestion_control/general_loss_algorithm_test.cc
@@ -23,10 +23,13 @@
class GeneralLossAlgorithmTest : public QuicTest {
protected:
- GeneralLossAlgorithmTest() {
+ GeneralLossAlgorithmTest() : unacked_packets_(Perspective::IS_CLIENT) {
rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(100),
QuicTime::Delta::Zero(), clock_.Now());
EXPECT_LT(0, rtt_stats_.smoothed_rtt().ToMicroseconds());
+ if (unacked_packets_.use_uber_loss_algorithm()) {
+ loss_algorithm_.SetPacketNumberSpace(HANDSHAKE_DATA);
+ }
}
~GeneralLossAlgorithmTest() override {}
@@ -54,9 +57,12 @@
void VerifyLosses(uint64_t largest_newly_acked,
const AckedPacketVector& packets_acked,
const std::vector<uint64_t>& losses_expected) {
- if (!unacked_packets_.largest_acked().IsInitialized() ||
- QuicPacketNumber(largest_newly_acked) >
- unacked_packets_.largest_acked()) {
+ if (unacked_packets_.use_uber_loss_algorithm()) {
+ unacked_packets_.MaybeUpdateLargestAckedOfPacketNumberSpace(
+ ENCRYPTION_NONE, QuicPacketNumber(largest_newly_acked));
+ } else if (!unacked_packets_.largest_acked().IsInitialized() ||
+ QuicPacketNumber(largest_newly_acked) >
+ unacked_packets_.largest_acked()) {
unacked_packets_.IncreaseLargestAcked(
QuicPacketNumber(largest_newly_acked));
}
@@ -208,7 +214,12 @@
clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
// Early retransmit when the final packet gets acked and the first is nacked.
- unacked_packets_.IncreaseLargestAcked(QuicPacketNumber(2));
+ if (unacked_packets_.use_uber_loss_algorithm()) {
+ unacked_packets_.MaybeUpdateLargestAckedOfPacketNumberSpace(
+ ENCRYPTION_NONE, QuicPacketNumber(2));
+ } else {
+ unacked_packets_.IncreaseLargestAcked(QuicPacketNumber(2));
+ }
unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
packets_acked.push_back(
AckedPacket(QuicPacketNumber(2), kMaxPacketSize, QuicTime::Zero()));
@@ -226,7 +237,12 @@
clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
// Early retransmit when the final packet gets acked and the first is nacked.
- unacked_packets_.IncreaseLargestAcked(QuicPacketNumber(2));
+ if (unacked_packets_.use_uber_loss_algorithm()) {
+ unacked_packets_.MaybeUpdateLargestAckedOfPacketNumberSpace(
+ ENCRYPTION_NONE, QuicPacketNumber(2));
+ } else {
+ unacked_packets_.IncreaseLargestAcked(QuicPacketNumber(2));
+ }
unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
packets_acked.push_back(
AckedPacket(QuicPacketNumber(2), kMaxPacketSize, QuicTime::Zero()));
@@ -253,7 +269,12 @@
AckedPacketVector packets_acked;
// Wait another RTT and ack 2.
clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
- unacked_packets_.IncreaseLargestAcked(QuicPacketNumber(2));
+ if (unacked_packets_.use_uber_loss_algorithm()) {
+ unacked_packets_.MaybeUpdateLargestAckedOfPacketNumberSpace(
+ ENCRYPTION_NONE, QuicPacketNumber(2));
+ } else {
+ unacked_packets_.IncreaseLargestAcked(QuicPacketNumber(2));
+ }
unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
packets_acked.push_back(
AckedPacket(QuicPacketNumber(2), kMaxPacketSize, QuicTime::Zero()));
diff --git a/quic/core/congestion_control/send_algorithm_test.cc b/quic/core/congestion_control/send_algorithm_test.cc
index 6001690..d7bfd85 100644
--- a/quic/core/congestion_control/send_algorithm_test.cc
+++ b/quic/core/congestion_control/send_algorithm_test.cc
@@ -268,10 +268,9 @@
SendAlgorithmInterface* sender_;
};
-INSTANTIATE_TEST_CASE_P(SendAlgorithmTests,
- SendAlgorithmTest,
- ::testing::ValuesIn(GetTestParams()),
- TestParamToString);
+INSTANTIATE_TEST_SUITE_P(SendAlgorithmTests, SendAlgorithmTest,
+ ::testing::ValuesIn(GetTestParams()),
+ TestParamToString);
// Test a simple long data transfer in the default setup.
TEST_P(SendAlgorithmTest, SimpleWiredNetworkTransfer) {
diff --git a/quic/core/congestion_control/uber_loss_algorithm.cc b/quic/core/congestion_control/uber_loss_algorithm.cc
new file mode 100644
index 0000000..8db151b
--- /dev/null
+++ b/quic/core/congestion_control/uber_loss_algorithm.cc
@@ -0,0 +1,86 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.h"
+
+#include <algorithm>
+
+namespace quic {
+
+UberLossAlgorithm::UberLossAlgorithm() : UberLossAlgorithm(kNack) {}
+
+UberLossAlgorithm::UberLossAlgorithm(LossDetectionType loss_type)
+ : loss_type_(loss_type) {
+ SetLossDetectionType(loss_type);
+ for (int8_t i = INITIAL_DATA; i < NUM_PACKET_NUMBER_SPACES; ++i) {
+ general_loss_algorithms_[i].SetPacketNumberSpace(
+ static_cast<PacketNumberSpace>(i));
+ }
+}
+
+LossDetectionType UberLossAlgorithm::GetLossDetectionType() const {
+ return loss_type_;
+}
+
+void UberLossAlgorithm::SetLossDetectionType(LossDetectionType loss_type) {
+ loss_type_ = loss_type;
+ for (auto& loss_algorithm : general_loss_algorithms_) {
+ loss_algorithm.SetLossDetectionType(loss_type);
+ }
+}
+
+void UberLossAlgorithm::DetectLosses(
+ const QuicUnackedPacketMap& unacked_packets,
+ QuicTime time,
+ const RttStats& rtt_stats,
+ QuicPacketNumber /*largest_newly_acked*/,
+ const AckedPacketVector& packets_acked,
+ LostPacketVector* packets_lost) {
+ DCHECK(unacked_packets.use_uber_loss_algorithm());
+ for (int8_t i = INITIAL_DATA; i < NUM_PACKET_NUMBER_SPACES; ++i) {
+ const QuicPacketNumber largest_acked =
+ unacked_packets.GetLargestAckedOfPacketNumberSpace(
+ static_cast<PacketNumberSpace>(i));
+ if (!largest_acked.IsInitialized() ||
+ unacked_packets.GetLeastUnacked() > largest_acked) {
+ // Skip detecting losses if no packet has been received for this packet
+ // number space or the least_unacked is greater than largest_acked.
+ continue;
+ }
+
+ general_loss_algorithms_[i].DetectLosses(unacked_packets, time, rtt_stats,
+ largest_acked, packets_acked,
+ packets_lost);
+ }
+}
+
+QuicTime UberLossAlgorithm::GetLossTimeout() const {
+ QuicTime loss_timeout = QuicTime::Zero();
+ // Returns the earliest non-zero loss timeout.
+ for (int8_t i = INITIAL_DATA; i < NUM_PACKET_NUMBER_SPACES; ++i) {
+ const QuicTime timeout = general_loss_algorithms_[i].GetLossTimeout();
+ if (!loss_timeout.IsInitialized()) {
+ loss_timeout = timeout;
+ continue;
+ }
+ if (timeout.IsInitialized()) {
+ loss_timeout = std::min(loss_timeout, timeout);
+ }
+ }
+ return loss_timeout;
+}
+
+void UberLossAlgorithm::SpuriousRetransmitDetected(
+ const QuicUnackedPacketMap& unacked_packets,
+ QuicTime time,
+ const RttStats& rtt_stats,
+ QuicPacketNumber spurious_retransmission) {
+ DCHECK(unacked_packets.use_uber_loss_algorithm());
+ general_loss_algorithms_[unacked_packets.GetPacketNumberSpace(
+ spurious_retransmission)]
+ .SpuriousRetransmitDetected(unacked_packets, time, rtt_stats,
+ spurious_retransmission);
+}
+
+} // namespace quic
diff --git a/quic/core/congestion_control/uber_loss_algorithm.h b/quic/core/congestion_control/uber_loss_algorithm.h
new file mode 100644
index 0000000..dddbcb3
--- /dev/null
+++ b/quic/core/congestion_control/uber_loss_algorithm.h
@@ -0,0 +1,53 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_CORE_CONGESTION_CONTROL_UBER_LOSS_ALGORITHM_H_
+#define QUICHE_QUIC_CORE_CONGESTION_CONTROL_UBER_LOSS_ALGORITHM_H_
+
+#include "net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.h"
+
+namespace quic {
+
+// This class comprises multiple loss algorithms, each per packet number space.
+class QUIC_EXPORT_PRIVATE UberLossAlgorithm : public LossDetectionInterface {
+ public:
+ UberLossAlgorithm();
+ explicit UberLossAlgorithm(LossDetectionType loss_type);
+ UberLossAlgorithm(const UberLossAlgorithm&) = delete;
+ UberLossAlgorithm& operator=(const UberLossAlgorithm&) = delete;
+ ~UberLossAlgorithm() override {}
+
+ LossDetectionType GetLossDetectionType() const override;
+
+ // Switches the loss detection type to |loss_type| and resets loss algorithm
+ // for all packet number spaces.
+ void SetLossDetectionType(LossDetectionType loss_type);
+
+ // 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;
+
+ // Returns the earliest time the early retransmit timer should be active.
+ QuicTime GetLossTimeout() const override;
+
+ // Increases the loss detection threshold for time loss detection.
+ void SpuriousRetransmitDetected(
+ const QuicUnackedPacketMap& unacked_packets,
+ QuicTime time,
+ const RttStats& rtt_stats,
+ QuicPacketNumber spurious_retransmission) override;
+
+ private:
+ LossDetectionType loss_type_;
+ // One loss algorithm per packet number space.
+ GeneralLossAlgorithm general_loss_algorithms_[NUM_PACKET_NUMBER_SPACES];
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_CORE_CONGESTION_CONTROL_UBER_LOSS_ALGORITHM_H_
diff --git a/quic/core/congestion_control/uber_loss_algorithm_test.cc b/quic/core/congestion_control/uber_loss_algorithm_test.cc
new file mode 100644
index 0000000..9aa2041
--- /dev/null
+++ b/quic/core/congestion_control/uber_loss_algorithm_test.cc
@@ -0,0 +1,159 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.h"
+
+#include "net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h"
+#include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_unacked_packet_map_peer.h"
+
+namespace quic {
+namespace test {
+namespace {
+
+// Default packet length.
+const uint32_t kDefaultLength = 1000;
+
+class UberLossAlgorithmTest : public QuicTest {
+ protected:
+ UberLossAlgorithmTest() {
+ SetQuicReloadableFlag(quic_use_uber_loss_algorithm, true);
+ unacked_packets_ =
+ QuicMakeUnique<QuicUnackedPacketMap>(Perspective::IS_CLIENT);
+ rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(100),
+ QuicTime::Delta::Zero(), clock_.Now());
+ EXPECT_LT(0, rtt_stats_.smoothed_rtt().ToMicroseconds());
+ }
+
+ void SendPacket(uint64_t packet_number, EncryptionLevel encryption_level) {
+ QuicStreamFrame frame;
+ frame.stream_id =
+ encryption_level == ENCRYPTION_NONE
+ ? QuicUtils::GetCryptoStreamId(
+ CurrentSupportedVersions()[0].transport_version)
+ : QuicUtils::GetHeadersStreamId(
+ CurrentSupportedVersions()[0].transport_version);
+ SerializedPacket packet(QuicPacketNumber(packet_number),
+ PACKET_1BYTE_PACKET_NUMBER, nullptr, kDefaultLength,
+ false, false);
+ packet.encryption_level = encryption_level;
+ packet.retransmittable_frames.push_back(QuicFrame(frame));
+ unacked_packets_->AddSentPacket(&packet, QuicPacketNumber(),
+ NOT_RETRANSMISSION, clock_.Now(), true);
+ }
+
+ void AckPackets(const std::vector<uint64_t>& packets_acked) {
+ packets_acked_.clear();
+ for (uint64_t acked : packets_acked) {
+ unacked_packets_->RemoveFromInFlight(QuicPacketNumber(acked));
+ packets_acked_.push_back(AckedPacket(QuicPacketNumber(acked),
+ kMaxPacketSize, QuicTime::Zero()));
+ }
+ }
+
+ void VerifyLosses(uint64_t largest_newly_acked,
+ const AckedPacketVector& packets_acked,
+ const std::vector<uint64_t>& losses_expected) {
+ LostPacketVector lost_packets;
+ loss_algorithm_.DetectLosses(*unacked_packets_, clock_.Now(), rtt_stats_,
+ QuicPacketNumber(largest_newly_acked),
+ packets_acked, &lost_packets);
+ 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,
+ QuicPacketNumber(losses_expected[i]));
+ }
+ }
+
+ MockClock clock_;
+ std::unique_ptr<QuicUnackedPacketMap> unacked_packets_;
+ RttStats rtt_stats_;
+ UberLossAlgorithm loss_algorithm_;
+ AckedPacketVector packets_acked_;
+};
+
+TEST_F(UberLossAlgorithmTest, ScenarioA) {
+ // This test mimics a scenario: client sends 1-CHLO, 2-0RTT, 3-0RTT,
+ // timeout and retransmits 4-CHLO. Server acks packet 1 (ack gets lost).
+ // Server receives and buffers packets 2 and 3. Server receives packet 4 and
+ // processes handshake asynchronously, so server acks 4 and cannot process
+ // packets 2 and 3.
+ SendPacket(1, ENCRYPTION_NONE);
+ SendPacket(2, ENCRYPTION_ZERO_RTT);
+ SendPacket(3, ENCRYPTION_ZERO_RTT);
+ unacked_packets_->RemoveFromInFlight(QuicPacketNumber(1));
+ SendPacket(4, ENCRYPTION_NONE);
+
+ AckPackets({1, 4});
+ unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace(
+ ENCRYPTION_NONE, QuicPacketNumber(4));
+ // Verify no packet is detected lost.
+ VerifyLosses(4, packets_acked_, std::vector<uint64_t>{});
+ EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
+}
+
+TEST_F(UberLossAlgorithmTest, ScenarioB) {
+ // This test mimics a scenario: client sends 3-0RTT, 4-0RTT, receives SHLO,
+ // sends 5-1RTT, 6-1RTT.
+ SendPacket(3, ENCRYPTION_ZERO_RTT);
+ SendPacket(4, ENCRYPTION_ZERO_RTT);
+ SendPacket(5, ENCRYPTION_FORWARD_SECURE);
+ SendPacket(6, ENCRYPTION_FORWARD_SECURE);
+
+ AckPackets({4});
+ unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace(
+ ENCRYPTION_ZERO_RTT, QuicPacketNumber(4));
+ // No packet loss by acking 4.
+ VerifyLosses(4, packets_acked_, std::vector<uint64_t>{});
+ EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
+
+ // Acking 6 causes 3 to be detected loss.
+ AckPackets({6});
+ unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace(
+ ENCRYPTION_FORWARD_SECURE, QuicPacketNumber(6));
+ VerifyLosses(6, packets_acked_, std::vector<uint64_t>{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});
+}
+
+TEST_F(UberLossAlgorithmTest, ScenarioC) {
+ // This test mimics a scenario: server sends 1-SHLO, 2-1RTT, 3-1RTT, 4-1RTT
+ // and retransmit 4-SHLO. Client receives and buffers packet 4. Client
+ // receives packet 5 and processes 4.
+ QuicUnackedPacketMapPeer::SetPerspective(unacked_packets_.get(),
+ Perspective::IS_SERVER);
+ SendPacket(1, ENCRYPTION_ZERO_RTT);
+ SendPacket(2, ENCRYPTION_FORWARD_SECURE);
+ SendPacket(3, ENCRYPTION_FORWARD_SECURE);
+ SendPacket(4, ENCRYPTION_FORWARD_SECURE);
+ unacked_packets_->RemoveFromInFlight(QuicPacketNumber(1));
+ SendPacket(5, ENCRYPTION_ZERO_RTT);
+
+ AckPackets({4, 5});
+ unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace(
+ ENCRYPTION_FORWARD_SECURE, QuicPacketNumber(4));
+ unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace(
+ ENCRYPTION_ZERO_RTT, QuicPacketNumber(5));
+ // No packet loss by acking 5.
+ VerifyLosses(5, packets_acked_, std::vector<uint64_t>{});
+ 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});
+}
+
+} // namespace
+} // namespace test
+} // namespace quic
diff --git a/quic/core/crypto/aead_base_decrypter.cc b/quic/core/crypto/aead_base_decrypter.cc
index 51cfa26..53bd0f0 100644
--- a/quic/core/crypto/aead_base_decrypter.cc
+++ b/quic/core/crypto/aead_base_decrypter.cc
@@ -141,8 +141,7 @@
return true;
}
-bool AeadBaseDecrypter::DecryptPacket(QuicTransportVersion /*version*/,
- uint64_t packet_number,
+bool AeadBaseDecrypter::DecryptPacket(uint64_t packet_number,
QuicStringPiece associated_data,
QuicStringPiece ciphertext,
char* output,
diff --git a/quic/core/crypto/aead_base_decrypter.h b/quic/core/crypto/aead_base_decrypter.h
index b4906b8..d374722 100644
--- a/quic/core/crypto/aead_base_decrypter.h
+++ b/quic/core/crypto/aead_base_decrypter.h
@@ -35,8 +35,7 @@
bool SetIV(QuicStringPiece iv) override;
bool SetPreliminaryKey(QuicStringPiece key) override;
bool SetDiversificationNonce(const DiversificationNonce& nonce) override;
- bool DecryptPacket(QuicTransportVersion version,
- uint64_t packet_number,
+ bool DecryptPacket(uint64_t packet_number,
QuicStringPiece associated_data,
QuicStringPiece ciphertext,
char* output,
diff --git a/quic/core/crypto/aead_base_encrypter.cc b/quic/core/crypto/aead_base_encrypter.cc
index 199851e..405292e 100644
--- a/quic/core/crypto/aead_base_encrypter.cc
+++ b/quic/core/crypto/aead_base_encrypter.cc
@@ -123,8 +123,7 @@
return true;
}
-bool AeadBaseEncrypter::EncryptPacket(QuicTransportVersion /*version*/,
- uint64_t packet_number,
+bool AeadBaseEncrypter::EncryptPacket(uint64_t packet_number,
QuicStringPiece associated_data,
QuicStringPiece plaintext,
char* output,
diff --git a/quic/core/crypto/aead_base_encrypter.h b/quic/core/crypto/aead_base_encrypter.h
index 255bd87..316d24e 100644
--- a/quic/core/crypto/aead_base_encrypter.h
+++ b/quic/core/crypto/aead_base_encrypter.h
@@ -33,8 +33,7 @@
bool SetKey(QuicStringPiece key) override;
bool SetNoncePrefix(QuicStringPiece nonce_prefix) override;
bool SetIV(QuicStringPiece iv) override;
- bool EncryptPacket(QuicTransportVersion version,
- uint64_t packet_number,
+ bool EncryptPacket(uint64_t packet_number,
QuicStringPiece associated_data,
QuicStringPiece plaintext,
char* output,
diff --git a/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc b/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc
index eb2fa5e..6513e45 100644
--- a/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc
+++ b/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc
@@ -212,8 +212,8 @@
std::unique_ptr<char[]> output(new char[ciphertext.length()]);
size_t output_length = 0;
const bool success = decrypter->DecryptPacket(
- QuicTransportVersionMax(), packet_number, associated_data, ciphertext,
- output.get(), &output_length, ciphertext.length());
+ packet_number, associated_data, ciphertext, output.get(), &output_length,
+ ciphertext.length());
if (!success) {
return nullptr;
}
diff --git a/quic/core/crypto/aes_128_gcm_decrypter_test.cc b/quic/core/crypto/aes_128_gcm_decrypter_test.cc
index ef66204..300e8a2 100644
--- a/quic/core/crypto/aes_128_gcm_decrypter_test.cc
+++ b/quic/core/crypto/aes_128_gcm_decrypter_test.cc
@@ -206,9 +206,9 @@
decrypter->SetIV(nonce);
std::unique_ptr<char[]> output(new char[ciphertext.length()]);
size_t output_length = 0;
- const bool success = decrypter->DecryptPacket(
- QuicTransportVersionMax(), 0, associated_data, ciphertext, output.get(),
- &output_length, ciphertext.length());
+ const bool success =
+ decrypter->DecryptPacket(0, associated_data, ciphertext, output.get(),
+ &output_length, ciphertext.length());
if (!success) {
return nullptr;
}
diff --git a/quic/core/crypto/aes_128_gcm_encrypter_test.cc b/quic/core/crypto/aes_128_gcm_encrypter_test.cc
index 79276ca..959cb9d 100644
--- a/quic/core/crypto/aes_128_gcm_encrypter_test.cc
+++ b/quic/core/crypto/aes_128_gcm_encrypter_test.cc
@@ -233,8 +233,8 @@
Aes128GcmEncrypter encrypter;
ASSERT_TRUE(encrypter.SetKey(key));
ASSERT_TRUE(encrypter.SetIV(iv));
- ASSERT_TRUE(encrypter.EncryptPacket(QUIC_VERSION_43, packet_num, aad, pt,
- out.data(), &out_size, out.size()));
+ ASSERT_TRUE(encrypter.EncryptPacket(packet_num, aad, pt, out.data(),
+ &out_size, out.size()));
EXPECT_EQ(out_size, out.size());
test::CompareCharArraysWithHexError("ciphertext", out.data(), out.size(),
ct.data(), ct.size());
diff --git a/quic/core/crypto/aes_256_gcm_decrypter_test.cc b/quic/core/crypto/aes_256_gcm_decrypter_test.cc
index b25b66b..cb5f702 100644
--- a/quic/core/crypto/aes_256_gcm_decrypter_test.cc
+++ b/quic/core/crypto/aes_256_gcm_decrypter_test.cc
@@ -210,9 +210,9 @@
decrypter->SetIV(nonce);
std::unique_ptr<char[]> output(new char[ciphertext.length()]);
size_t output_length = 0;
- const bool success = decrypter->DecryptPacket(
- QuicTransportVersionMax(), 0, associated_data, ciphertext, output.get(),
- &output_length, ciphertext.length());
+ const bool success =
+ decrypter->DecryptPacket(0, associated_data, ciphertext, output.get(),
+ &output_length, ciphertext.length());
if (!success) {
return nullptr;
}
diff --git a/quic/core/crypto/chacha20_poly1305_decrypter_test.cc b/quic/core/crypto/chacha20_poly1305_decrypter_test.cc
index a0c3cbe..5f5ae01 100644
--- a/quic/core/crypto/chacha20_poly1305_decrypter_test.cc
+++ b/quic/core/crypto/chacha20_poly1305_decrypter_test.cc
@@ -125,8 +125,8 @@
std::unique_ptr<char[]> output(new char[ciphertext.length()]);
size_t output_length = 0;
const bool success = decrypter->DecryptPacket(
- QuicTransportVersionMax(), packet_number, associated_data, ciphertext,
- output.get(), &output_length, ciphertext.length());
+ packet_number, associated_data, ciphertext, output.get(), &output_length,
+ ciphertext.length());
if (!success) {
return nullptr;
}
diff --git a/quic/core/crypto/chacha20_poly1305_encrypter_test.cc b/quic/core/crypto/chacha20_poly1305_encrypter_test.cc
index 8d9a900..d8c27bf 100644
--- a/quic/core/crypto/chacha20_poly1305_encrypter_test.cc
+++ b/quic/core/crypto/chacha20_poly1305_encrypter_test.cc
@@ -101,14 +101,14 @@
QuicString plaintext = "plaintext";
char encrypted[1024];
size_t len;
- ASSERT_TRUE(encrypter.EncryptPacket(QuicTransportVersionMax(), packet_number,
- associated_data, plaintext, encrypted,
- &len, QUIC_ARRAYSIZE(encrypted)));
+ ASSERT_TRUE(encrypter.EncryptPacket(packet_number, associated_data, plaintext,
+ encrypted, &len,
+ QUIC_ARRAYSIZE(encrypted)));
QuicStringPiece ciphertext(encrypted, len);
char decrypted[1024];
- ASSERT_TRUE(decrypter.DecryptPacket(QuicTransportVersionMax(), packet_number,
- associated_data, ciphertext, decrypted,
- &len, QUIC_ARRAYSIZE(decrypted)));
+ ASSERT_TRUE(decrypter.DecryptPacket(packet_number, associated_data,
+ ciphertext, decrypted, &len,
+ QUIC_ARRAYSIZE(decrypted)));
}
TEST_F(ChaCha20Poly1305EncrypterTest, Encrypt) {
diff --git a/quic/core/crypto/chacha20_poly1305_tls_decrypter_test.cc b/quic/core/crypto/chacha20_poly1305_tls_decrypter_test.cc
index 824c2dd..dd74539 100644
--- a/quic/core/crypto/chacha20_poly1305_tls_decrypter_test.cc
+++ b/quic/core/crypto/chacha20_poly1305_tls_decrypter_test.cc
@@ -119,9 +119,9 @@
decrypter->SetIV(nonce);
std::unique_ptr<char[]> output(new char[ciphertext.length()]);
size_t output_length = 0;
- const bool success = decrypter->DecryptPacket(
- QuicTransportVersionMax(), 0, associated_data, ciphertext, output.get(),
- &output_length, ciphertext.length());
+ const bool success =
+ decrypter->DecryptPacket(0, associated_data, ciphertext, output.get(),
+ &output_length, ciphertext.length());
if (!success) {
return nullptr;
}
diff --git a/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc b/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc
index bc7c6c4..905472b 100644
--- a/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc
+++ b/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc
@@ -100,14 +100,14 @@
QuicString plaintext = "plaintext";
char encrypted[1024];
size_t len;
- ASSERT_TRUE(encrypter.EncryptPacket(QuicTransportVersionMax(), packet_number,
- associated_data, plaintext, encrypted,
- &len, QUIC_ARRAYSIZE(encrypted)));
+ ASSERT_TRUE(encrypter.EncryptPacket(packet_number, associated_data, plaintext,
+ encrypted, &len,
+ QUIC_ARRAYSIZE(encrypted)));
QuicStringPiece ciphertext(encrypted, len);
char decrypted[1024];
- ASSERT_TRUE(decrypter.DecryptPacket(QuicTransportVersionMax(), packet_number,
- associated_data, ciphertext, decrypted,
- &len, QUIC_ARRAYSIZE(decrypted)));
+ ASSERT_TRUE(decrypter.DecryptPacket(packet_number, associated_data,
+ ciphertext, decrypted, &len,
+ QUIC_ARRAYSIZE(decrypted)));
}
TEST_F(ChaCha20Poly1305TlsEncrypterTest, Encrypt) {
diff --git a/quic/core/crypto/crypto_message_printer_bin.cc b/quic/core/crypto/crypto_message_printer_bin.cc
index f70c1c2..f14abb0 100644
--- a/quic/core/crypto/crypto_message_printer_bin.cc
+++ b/quic/core/crypto/crypto_message_printer_bin.cc
@@ -1,3 +1,7 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
// Dumps the contents of a QUIC crypto handshake message in a human readable
// format.
//
diff --git a/quic/core/crypto/crypto_protocol.h b/quic/core/crypto/crypto_protocol.h
index 5795119..b6a1e90 100644
--- a/quic/core/crypto/crypto_protocol.h
+++ b/quic/core/crypto/crypto_protocol.h
@@ -261,9 +261,6 @@
// Universal tags
const QuicTag kPAD = TAG('P', 'A', 'D', '\0'); // Padding
-// Server push tags
-const QuicTag kSPSH = TAG('S', 'P', 'S', 'H'); // Support server push.
-
// Stats collection tags
const QuicTag kEPID = TAG('E', 'P', 'I', 'D'); // Endpoint identifier.
diff --git a/quic/core/crypto/crypto_server_test.cc b/quic/core/crypto/crypto_server_test.cc
index c2c4041..4ed169e 100644
--- a/quic/core/crypto/crypto_server_test.cc
+++ b/quic/core/crypto/crypto_server_test.cc
@@ -236,7 +236,7 @@
void ShouldSucceed(const CryptoHandshakeMessage& message) {
bool called = false;
- QuicSocketAddress server_address;
+ QuicSocketAddress server_address(QuicIpAddress::Any4(), 5);
config_.ValidateClientHello(
message, client_address_.host(), server_address,
supported_versions_.front().transport_version, &clock_, signed_config_,
@@ -254,7 +254,7 @@
void ShouldFailMentioning(const char* error_substr,
const CryptoHandshakeMessage& message,
bool* called) {
- QuicSocketAddress server_address;
+ QuicSocketAddress server_address(QuicIpAddress::Any4(), 5);
config_.ValidateClientHello(
message, client_address_.host(), server_address,
supported_versions_.front().transport_version, &clock_, signed_config_,
@@ -312,7 +312,7 @@
QuicReferenceCountedPointer<ValidateCallback::Result> result,
bool should_succeed,
const char* error_substr) {
- QuicSocketAddress server_address;
+ QuicSocketAddress server_address(QuicIpAddress::Any4(), 5);
QuicConnectionId server_designated_connection_id =
TestConnectionId(rand_for_id_generation_.RandUint64());
bool called;
@@ -415,9 +415,8 @@
std::unique_ptr<CryptoHandshakeMessage> server_config_;
};
-INSTANTIATE_TEST_CASE_P(CryptoServerTests,
- CryptoServerTest,
- ::testing::ValuesIn(GetTestParams()));
+INSTANTIATE_TEST_SUITE_P(CryptoServerTests, CryptoServerTest,
+ ::testing::ValuesIn(GetTestParams()));
TEST_P(CryptoServerTest, BadSNI) {
// clang-format off
diff --git a/quic/core/crypto/crypto_utils.cc b/quic/core/crypto/crypto_utils.cc
index 46d172f..4f6a61d 100644
--- a/quic/core/crypto/crypto_utils.cc
+++ b/quic/core/crypto/crypto_utils.cc
@@ -107,24 +107,10 @@
std::vector<uint8_t> handshake_secret;
handshake_secret.resize(EVP_MAX_MD_SIZE);
size_t handshake_secret_len;
- bool hkdf_extract_success;
- if (!QuicConnectionIdSupportsVariableLength(perspective)) {
- uint64_t connection_id64 = QuicConnectionIdToUInt64(connection_id);
- uint8_t connection_id_bytes[sizeof(connection_id64)];
- for (size_t i = 0; i < sizeof(connection_id64); ++i) {
- connection_id_bytes[i] =
- (connection_id64 >> ((sizeof(connection_id64) - i - 1) * 8)) & 0xff;
- }
- hkdf_extract_success =
- HKDF_extract(handshake_secret.data(), &handshake_secret_len, hash,
- connection_id_bytes, QUIC_ARRAYSIZE(connection_id_bytes),
- kInitialSalt, QUIC_ARRAYSIZE(kInitialSalt));
- } else {
- hkdf_extract_success = HKDF_extract(
- handshake_secret.data(), &handshake_secret_len, hash,
- reinterpret_cast<const uint8_t*>(connection_id.data()),
- connection_id.length(), kInitialSalt, QUIC_ARRAYSIZE(kInitialSalt));
- }
+ const bool hkdf_extract_success = HKDF_extract(
+ handshake_secret.data(), &handshake_secret_len, hash,
+ reinterpret_cast<const uint8_t*>(connection_id.data()),
+ connection_id.length(), kInitialSalt, QUIC_ARRAYSIZE(kInitialSalt));
QUIC_BUG_IF(!hkdf_extract_success)
<< "HKDF_extract failed when creating initial crypters";
handshake_secret.resize(handshake_secret_len);
diff --git a/quic/core/crypto/null_decrypter.cc b/quic/core/crypto/null_decrypter.cc
index 0c108b6..288d3c4 100644
--- a/quic/core/crypto/null_decrypter.cc
+++ b/quic/core/crypto/null_decrypter.cc
@@ -38,8 +38,7 @@
return true;
}
-bool NullDecrypter::DecryptPacket(QuicTransportVersion version,
- uint64_t /*packet_number*/,
+bool NullDecrypter::DecryptPacket(uint64_t /*packet_number*/,
QuicStringPiece associated_data,
QuicStringPiece ciphertext,
char* output,
@@ -58,7 +57,7 @@
QUIC_BUG << "Output buffer must be larger than the plaintext.";
return false;
}
- if (hash != ComputeHash(version, associated_data, plaintext)) {
+ if (hash != ComputeHash(associated_data, plaintext)) {
return false;
}
// Copy the plaintext to output.
@@ -97,21 +96,15 @@
return true;
}
-QuicUint128 NullDecrypter::ComputeHash(QuicTransportVersion version,
- const QuicStringPiece data1,
+QuicUint128 NullDecrypter::ComputeHash(const QuicStringPiece data1,
const QuicStringPiece data2) const {
QuicUint128 correct_hash;
- if (version > QUIC_VERSION_35) {
- if (perspective_ == Perspective::IS_CLIENT) {
- // Peer is a server.
- correct_hash = QuicUtils::FNV1a_128_Hash_Three(data1, data2, "Server");
-
- } else {
- // Peer is a client.
- correct_hash = QuicUtils::FNV1a_128_Hash_Three(data1, data2, "Client");
- }
+ if (perspective_ == Perspective::IS_CLIENT) {
+ // Peer is a server.
+ correct_hash = QuicUtils::FNV1a_128_Hash_Three(data1, data2, "Server");
} else {
- correct_hash = QuicUtils::FNV1a_128_Hash_Two(data1, data2);
+ // Peer is a client.
+ correct_hash = QuicUtils::FNV1a_128_Hash_Three(data1, data2, "Client");
}
QuicUint128 mask = MakeQuicUint128(UINT64_C(0x0), UINT64_C(0xffffffff));
mask <<= 96;
diff --git a/quic/core/crypto/null_decrypter.h b/quic/core/crypto/null_decrypter.h
index 3996eb7..8381987 100644
--- a/quic/core/crypto/null_decrypter.h
+++ b/quic/core/crypto/null_decrypter.h
@@ -35,8 +35,7 @@
bool SetIV(QuicStringPiece iv) override;
bool SetPreliminaryKey(QuicStringPiece key) override;
bool SetDiversificationNonce(const DiversificationNonce& nonce) override;
- bool DecryptPacket(QuicTransportVersion version,
- uint64_t packet_number,
+ bool DecryptPacket(uint64_t packet_number,
QuicStringPiece associated_data,
QuicStringPiece ciphertext,
char* output,
@@ -51,9 +50,7 @@
private:
bool ReadHash(QuicDataReader* reader, QuicUint128* hash);
- QuicUint128 ComputeHash(QuicTransportVersion version,
- QuicStringPiece data1,
- QuicStringPiece data2) const;
+ QuicUint128 ComputeHash(QuicStringPiece data1, QuicStringPiece data2) const;
Perspective perspective_;
};
diff --git a/quic/core/crypto/null_decrypter_test.cc b/quic/core/crypto/null_decrypter_test.cc
index dd62a5c..09b1aaf 100644
--- a/quic/core/crypto/null_decrypter_test.cc
+++ b/quic/core/crypto/null_decrypter_test.cc
@@ -15,18 +15,35 @@
TEST_F(NullDecrypterTest, DecryptClient) {
unsigned char expected[] = {
// fnv hash
- 0x97, 0xdc, 0x27, 0x2f, 0x18, 0xa8, 0x56, 0x73, 0xdf, 0x8d, 0x1d, 0xd0,
+ 0x97,
+ 0xdc,
+ 0x27,
+ 0x2f,
+ 0x18,
+ 0xa8,
+ 0x56,
+ 0x73,
+ 0xdf,
+ 0x8d,
+ 0x1d,
+ 0xd0,
// payload
- 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!',
+ 'g',
+ 'o',
+ 'o',
+ 'd',
+ 'b',
+ 'y',
+ 'e',
+ '!',
};
const char* data = reinterpret_cast<const char*>(expected);
size_t len = QUIC_ARRAYSIZE(expected);
NullDecrypter decrypter(Perspective::IS_SERVER);
char buffer[256];
size_t length = 0;
- ASSERT_TRUE(decrypter.DecryptPacket(QUIC_VERSION_39, 0, "hello world!",
- QuicStringPiece(data, len), buffer,
- &length, 256));
+ ASSERT_TRUE(decrypter.DecryptPacket(
+ 0, "hello world!", QuicStringPiece(data, len), buffer, &length, 256));
EXPECT_LT(0u, length);
EXPECT_EQ("goodbye!", QuicStringPiece(buffer, length));
}
@@ -34,56 +51,35 @@
TEST_F(NullDecrypterTest, DecryptServer) {
unsigned char expected[] = {
// fnv hash
- 0x63, 0x5e, 0x08, 0x03, 0x32, 0x80, 0x8f, 0x73, 0xdf, 0x8d, 0x1d, 0x1a,
+ 0x63,
+ 0x5e,
+ 0x08,
+ 0x03,
+ 0x32,
+ 0x80,
+ 0x8f,
+ 0x73,
+ 0xdf,
+ 0x8d,
+ 0x1d,
+ 0x1a,
// payload
- 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!',
+ 'g',
+ 'o',
+ 'o',
+ 'd',
+ 'b',
+ 'y',
+ 'e',
+ '!',
};
const char* data = reinterpret_cast<const char*>(expected);
size_t len = QUIC_ARRAYSIZE(expected);
NullDecrypter decrypter(Perspective::IS_CLIENT);
char buffer[256];
size_t length = 0;
- ASSERT_TRUE(decrypter.DecryptPacket(QUIC_VERSION_39, 0, "hello world!",
- QuicStringPiece(data, len), buffer,
- &length, 256));
- EXPECT_LT(0u, length);
- EXPECT_EQ("goodbye!", QuicStringPiece(buffer, length));
-}
-
-TEST_F(NullDecrypterTest, DecryptClientPre37) {
- unsigned char expected[] = {
- // fnv hash
- 0xa0, 0x6f, 0x44, 0x8a, 0x44, 0xf8, 0x18, 0x3b, 0x47, 0x91, 0xb2, 0x13,
- // payload
- 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!',
- };
- const char* data = reinterpret_cast<const char*>(expected);
- size_t len = QUIC_ARRAYSIZE(expected);
- NullDecrypter decrypter(Perspective::IS_CLIENT);
- char buffer[256];
- size_t length = 0;
- ASSERT_TRUE(decrypter.DecryptPacket(QUIC_VERSION_35, 0, "hello world!",
- QuicStringPiece(data, len), buffer,
- &length, 256));
- EXPECT_LT(0u, length);
- EXPECT_EQ("goodbye!", QuicStringPiece(buffer, length));
-}
-
-TEST_F(NullDecrypterTest, DecryptServerPre37) {
- unsigned char expected[] = {
- // fnv hash
- 0xa0, 0x6f, 0x44, 0x8a, 0x44, 0xf8, 0x18, 0x3b, 0x47, 0x91, 0xb2, 0x13,
- // payload
- 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!',
- };
- const char* data = reinterpret_cast<const char*>(expected);
- size_t len = QUIC_ARRAYSIZE(expected);
- NullDecrypter decrypter(Perspective::IS_SERVER);
- char buffer[256];
- size_t length = 0;
- ASSERT_TRUE(decrypter.DecryptPacket(QUIC_VERSION_35, 0, "hello world!",
- QuicStringPiece(data, len), buffer,
- &length, 256));
+ ASSERT_TRUE(decrypter.DecryptPacket(
+ 0, "hello world!", QuicStringPiece(data, len), buffer, &length, 256));
EXPECT_LT(0u, length);
EXPECT_EQ("goodbye!", QuicStringPiece(buffer, length));
}
@@ -91,18 +87,35 @@
TEST_F(NullDecrypterTest, BadHash) {
unsigned char expected[] = {
// fnv hash
- 0x46, 0x11, 0xea, 0x5f, 0xcf, 0x1d, 0x66, 0x5b, 0xba, 0xf0, 0xbc, 0xfd,
+ 0x46,
+ 0x11,
+ 0xea,
+ 0x5f,
+ 0xcf,
+ 0x1d,
+ 0x66,
+ 0x5b,
+ 0xba,
+ 0xf0,
+ 0xbc,
+ 0xfd,
// payload
- 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!',
+ 'g',
+ 'o',
+ 'o',
+ 'd',
+ 'b',
+ 'y',
+ 'e',
+ '!',
};
const char* data = reinterpret_cast<const char*>(expected);
size_t len = QUIC_ARRAYSIZE(expected);
NullDecrypter decrypter(Perspective::IS_CLIENT);
char buffer[256];
size_t length = 0;
- ASSERT_FALSE(decrypter.DecryptPacket(QUIC_VERSION_35, 0, "hello world!",
- QuicStringPiece(data, len), buffer,
- &length, 256));
+ ASSERT_FALSE(decrypter.DecryptPacket(
+ 0, "hello world!", QuicStringPiece(data, len), buffer, &length, 256));
}
TEST_F(NullDecrypterTest, ShortInput) {
@@ -115,9 +128,8 @@
NullDecrypter decrypter(Perspective::IS_CLIENT);
char buffer[256];
size_t length = 0;
- ASSERT_FALSE(decrypter.DecryptPacket(QUIC_VERSION_35, 0, "hello world!",
- QuicStringPiece(data, len), buffer,
- &length, 256));
+ ASSERT_FALSE(decrypter.DecryptPacket(
+ 0, "hello world!", QuicStringPiece(data, len), buffer, &length, 256));
}
} // namespace test
diff --git a/quic/core/crypto/null_encrypter.cc b/quic/core/crypto/null_encrypter.cc
index e4a165f..9819a31 100644
--- a/quic/core/crypto/null_encrypter.cc
+++ b/quic/core/crypto/null_encrypter.cc
@@ -26,8 +26,7 @@
return iv.empty();
}
-bool NullEncrypter::EncryptPacket(QuicTransportVersion version,
- uint64_t /*packet_number*/,
+bool NullEncrypter::EncryptPacket(uint64_t /*packet_number*/,
QuicStringPiece associated_data,
QuicStringPiece plaintext,
char* output,
@@ -38,16 +37,12 @@
return false;
}
QuicUint128 hash;
- if (version > QUIC_VERSION_35) {
- if (perspective_ == Perspective::IS_SERVER) {
- hash =
- QuicUtils::FNV1a_128_Hash_Three(associated_data, plaintext, "Server");
- } else {
- hash =
- QuicUtils::FNV1a_128_Hash_Three(associated_data, plaintext, "Client");
- }
+ if (perspective_ == Perspective::IS_SERVER) {
+ hash =
+ QuicUtils::FNV1a_128_Hash_Three(associated_data, plaintext, "Server");
} else {
- hash = QuicUtils::FNV1a_128_Hash_Two(associated_data, plaintext);
+ hash =
+ QuicUtils::FNV1a_128_Hash_Three(associated_data, plaintext, "Client");
}
// TODO(ianswett): memmove required for in place encryption. Placing the
// hash at the end would allow use of memcpy, doing nothing for in place.
diff --git a/quic/core/crypto/null_encrypter.h b/quic/core/crypto/null_encrypter.h
index 01ecd45..fe4487d 100644
--- a/quic/core/crypto/null_encrypter.h
+++ b/quic/core/crypto/null_encrypter.h
@@ -29,8 +29,7 @@
bool SetKey(QuicStringPiece key) override;
bool SetNoncePrefix(QuicStringPiece nonce_prefix) override;
bool SetIV(QuicStringPiece iv) override;
- bool EncryptPacket(QuicTransportVersion version,
- uint64_t packet_number,
+ bool EncryptPacket(uint64_t packet_number,
QuicStringPiece associated_data,
QuicStringPiece plaintext,
char* output,
diff --git a/quic/core/crypto/null_encrypter_test.cc b/quic/core/crypto/null_encrypter_test.cc
index 6dd4c98..fd95cc6 100644
--- a/quic/core/crypto/null_encrypter_test.cc
+++ b/quic/core/crypto/null_encrypter_test.cc
@@ -15,16 +15,33 @@
TEST_F(NullEncrypterTest, EncryptClient) {
unsigned char expected[] = {
// fnv hash
- 0x97, 0xdc, 0x27, 0x2f, 0x18, 0xa8, 0x56, 0x73, 0xdf, 0x8d, 0x1d, 0xd0,
+ 0x97,
+ 0xdc,
+ 0x27,
+ 0x2f,
+ 0x18,
+ 0xa8,
+ 0x56,
+ 0x73,
+ 0xdf,
+ 0x8d,
+ 0x1d,
+ 0xd0,
// payload
- 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!',
+ 'g',
+ 'o',
+ 'o',
+ 'd',
+ 'b',
+ 'y',
+ 'e',
+ '!',
};
char encrypted[256];
size_t encrypted_len = 0;
NullEncrypter encrypter(Perspective::IS_CLIENT);
- ASSERT_TRUE(encrypter.EncryptPacket(QUIC_VERSION_39, 0, "hello world!",
- "goodbye!", encrypted, &encrypted_len,
- 256));
+ ASSERT_TRUE(encrypter.EncryptPacket(0, "hello world!", "goodbye!", encrypted,
+ &encrypted_len, 256));
test::CompareCharArraysWithHexError(
"encrypted data", encrypted, encrypted_len,
reinterpret_cast<const char*>(expected), QUIC_ARRAYSIZE(expected));
@@ -33,52 +50,33 @@
TEST_F(NullEncrypterTest, EncryptServer) {
unsigned char expected[] = {
// fnv hash
- 0x63, 0x5e, 0x08, 0x03, 0x32, 0x80, 0x8f, 0x73, 0xdf, 0x8d, 0x1d, 0x1a,
+ 0x63,
+ 0x5e,
+ 0x08,
+ 0x03,
+ 0x32,
+ 0x80,
+ 0x8f,
+ 0x73,
+ 0xdf,
+ 0x8d,
+ 0x1d,
+ 0x1a,
// payload
- 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!',
+ 'g',
+ 'o',
+ 'o',
+ 'd',
+ 'b',
+ 'y',
+ 'e',
+ '!',
};
char encrypted[256];
size_t encrypted_len = 0;
NullEncrypter encrypter(Perspective::IS_SERVER);
- ASSERT_TRUE(encrypter.EncryptPacket(QUIC_VERSION_39, 0, "hello world!",
- "goodbye!", encrypted, &encrypted_len,
- 256));
- test::CompareCharArraysWithHexError(
- "encrypted data", encrypted, encrypted_len,
- reinterpret_cast<const char*>(expected), QUIC_ARRAYSIZE(expected));
-}
-
-TEST_F(NullEncrypterTest, EncryptClientPre37) {
- unsigned char expected[] = {
- // fnv hash
- 0xa0, 0x6f, 0x44, 0x8a, 0x44, 0xf8, 0x18, 0x3b, 0x47, 0x91, 0xb2, 0x13,
- // payload
- 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!',
- };
- char encrypted[256];
- size_t encrypted_len = 0;
- NullEncrypter encrypter(Perspective::IS_CLIENT);
- ASSERT_TRUE(encrypter.EncryptPacket(QUIC_VERSION_35, 0, "hello world!",
- "goodbye!", encrypted, &encrypted_len,
- 256));
- test::CompareCharArraysWithHexError(
- "encrypted data", encrypted, encrypted_len,
- reinterpret_cast<const char*>(expected), QUIC_ARRAYSIZE(expected));
-}
-
-TEST_F(NullEncrypterTest, EncryptServerPre37) {
- unsigned char expected[] = {
- // fnv hash
- 0xa0, 0x6f, 0x44, 0x8a, 0x44, 0xf8, 0x18, 0x3b, 0x47, 0x91, 0xb2, 0x13,
- // payload
- 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!',
- };
- char encrypted[256];
- size_t encrypted_len = 0;
- NullEncrypter encrypter(Perspective::IS_SERVER);
- ASSERT_TRUE(encrypter.EncryptPacket(QUIC_VERSION_35, 0, "hello world!",
- "goodbye!", encrypted, &encrypted_len,
- 256));
+ ASSERT_TRUE(encrypter.EncryptPacket(0, "hello world!", "goodbye!", encrypted,
+ &encrypted_len, 256));
test::CompareCharArraysWithHexError(
"encrypted data", encrypted, encrypted_len,
reinterpret_cast<const char*>(expected), QUIC_ARRAYSIZE(expected));
diff --git a/quic/core/crypto/quic_crypto_client_config.cc b/quic/core/crypto/quic_crypto_client_config.cc
index 56447bb..0bf1b41 100644
--- a/quic/core/crypto/quic_crypto_client_config.cc
+++ b/quic/core/crypto/quic_crypto_client_config.cc
@@ -657,14 +657,7 @@
const QuicData& client_hello_serialized = out->GetSerialized();
hkdf_input.append(QuicCryptoConfig::kCETVLabel,
strlen(QuicCryptoConfig::kCETVLabel) + 1);
- if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_CLIENT)) {
- const uint64_t connection_id64_net =
- QuicEndian::HostToNet64(QuicConnectionIdToUInt64(connection_id));
- hkdf_input.append(reinterpret_cast<const char*>(&connection_id64_net),
- sizeof(connection_id64_net));
- } else {
hkdf_input.append(connection_id.data(), connection_id.length());
- }
hkdf_input.append(client_hello_serialized.data(),
client_hello_serialized.length());
hkdf_input.append(cached->server_config());
@@ -696,8 +689,7 @@
std::unique_ptr<char[]> output(new char[encrypted_len]);
size_t output_size = 0;
if (!crypters.encrypter->EncryptPacket(
- preferred_version.transport_version, 0 /* packet number */,
- QuicStringPiece() /* associated data */,
+ 0 /* packet number */, QuicStringPiece() /* associated data */,
cetv_plaintext.AsStringPiece(), output.get(), &output_size,
encrypted_len)) {
*error_details = "Packet encryption failed";
@@ -715,16 +707,8 @@
// out_params->hkdf_input_suffix
// out_params->initial_crypters
out_params->hkdf_input_suffix.clear();
- if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_CLIENT)) {
- const uint64_t connection_id64_net =
- QuicEndian::HostToNet64(QuicConnectionIdToUInt64(connection_id));
- out_params->hkdf_input_suffix.append(
- reinterpret_cast<const char*>(&connection_id64_net),
- sizeof(connection_id64_net));
- } else {
out_params->hkdf_input_suffix.append(connection_id.data(),
connection_id.length());
- }
const QuicData& client_hello_serialized = out->GetSerialized();
out_params->hkdf_input_suffix.append(client_hello_serialized.data(),
client_hello_serialized.length());
@@ -857,15 +841,7 @@
if (rej.tag() == kSREJ) {
QuicConnectionId connection_id;
- if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_CLIENT)) {
- uint64_t connection_id64;
- if (rej.GetUint64(kRCID, &connection_id64) != QUIC_NO_ERROR) {
- *error_details = "Missing kRCID";
- return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
- }
- connection_id64 = QuicEndian::NetToHost64(connection_id64);
- connection_id = QuicConnectionIdFromUInt64(connection_id64);
- } else {
+
QuicStringPiece connection_id_bytes;
if (!rej.GetStringPiece(kRCID, &connection_id_bytes)) {
*error_details = "Missing kRCID";
@@ -880,7 +856,6 @@
*error_details = "Bad kRCID length";
return QUIC_CRYPTO_INTERNAL_ERROR;
}
- }
cached->add_server_designated_connection_id(connection_id);
if (!nonce.empty()) {
cached->add_server_nonce(QuicString(nonce));
diff --git a/quic/core/crypto/quic_crypto_server_config.cc b/quic/core/crypto/quic_crypto_server_config.cc
index 851f8e3..af67166 100644
--- a/quic/core/crypto/quic_crypto_server_config.cc
+++ b/quic/core/crypto/quic_crypto_server_config.cc
@@ -77,7 +77,7 @@
std::unique_ptr<KeyExchange> Create(QuicString /*server_config_id*/,
QuicTag type,
- QuicStringPiece private_key) {
+ QuicStringPiece private_key) override {
if (private_key.empty()) {
QUIC_LOG(WARNING) << "Server config contains key exchange method without "
"corresponding private key: "
@@ -876,10 +876,6 @@
<< "ProcessClientHelloAfterGetProof: attempted to use connection ID "
<< connection_id << " which is invalid with version "
<< QuicVersionToString(version.transport_version);
- if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_SERVER)) {
- connection_id = QuicConnectionIdFromUInt64(
- QuicEndian::HostToNet64(QuicConnectionIdToUInt64(connection_id)));
- }
ProcessClientHelloHelper helper(&done_cb);
if (found_error) {
@@ -1020,21 +1016,10 @@
QuicString hkdf_suffix;
const QuicData& client_hello_serialized = client_hello.GetSerialized();
- if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_SERVER)) {
- // connection_id is already passed in in network byte order.
- const uint64_t connection_id64_net =
- QuicConnectionIdToUInt64(connection_id);
- hkdf_suffix.reserve(sizeof(connection_id64_net) +
- client_hello_serialized.length() +
- requested_config->serialized.size());
- hkdf_suffix.append(reinterpret_cast<const char*>(&connection_id64_net),
- sizeof(connection_id64_net));
- } else {
hkdf_suffix.reserve(connection_id.length() +
client_hello_serialized.length() +
requested_config->serialized.size());
hkdf_suffix.append(connection_id.data(), connection_id.length());
- }
hkdf_suffix.append(client_hello_serialized.data(),
client_hello_serialized.length());
hkdf_suffix.append(requested_config->serialized);
@@ -1057,15 +1042,7 @@
QuicString hkdf_input;
hkdf_input.append(QuicCryptoConfig::kCETVLabel,
strlen(QuicCryptoConfig::kCETVLabel) + 1);
- if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_SERVER)) {
- // connection_id is already passed in in network byte order.
- const uint64_t connection_id64_net =
- QuicConnectionIdToUInt64(connection_id);
- hkdf_input.append(reinterpret_cast<const char*>(&connection_id64_net),
- sizeof(connection_id64_net));
- } else {
- hkdf_input.append(connection_id.data(), connection_id.length());
- }
+ hkdf_input.append(connection_id.data(), connection_id.length());
hkdf_input.append(client_hello_copy_serialized.data(),
client_hello_copy_serialized.length());
hkdf_input.append(requested_config->serialized);
@@ -1084,9 +1061,8 @@
char plaintext[kMaxPacketSize];
size_t plaintext_length = 0;
const bool success = crypters.decrypter->DecryptPacket(
- QUIC_VERSION_35, 0 /* packet number */,
- QuicStringPiece() /* associated data */, cetv_ciphertext, plaintext,
- &plaintext_length, kMaxPacketSize);
+ 0 /* packet number */, QuicStringPiece() /* associated data */,
+ cetv_ciphertext, plaintext, &plaintext_length, kMaxPacketSize);
if (!success) {
helper.Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
"CETV decryption failure");
@@ -1613,10 +1589,6 @@
<< "with server-designated connection ID "
<< server_designated_connection_id;
out->set_tag(kSREJ);
- if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_SERVER)) {
- out->SetValue(kRCID, QuicEndian::HostToNet64(QuicConnectionIdToUInt64(
- server_designated_connection_id)));
- } else {
if (!QuicUtils::IsConnectionIdValidForVersion(
server_designated_connection_id, version)) {
QUIC_BUG << "Tried to send server designated connection ID "
@@ -1628,7 +1600,6 @@
out->SetStringPiece(
kRCID, QuicStringPiece(server_designated_connection_id.data(),
server_designated_connection_id.length()));
- }
} else {
out->set_tag(kREJ);
}
@@ -2078,6 +2049,7 @@
bool QuicCryptoServerConfig::IsNextConfigReady(QuicWallTime now) const {
if (GetQuicReloadableFlag(quic_fix_config_rotation)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_fix_config_rotation);
return !next_config_promotion_time_.IsZero() &&
!next_config_promotion_time_.IsAfter(now);
}
diff --git a/quic/core/crypto/quic_decrypter.h b/quic/core/crypto/quic_decrypter.h
index 892504c..c7c2ccc 100644
--- a/quic/core/crypto/quic_decrypter.h
+++ b/quic/core/crypto/quic_decrypter.h
@@ -53,8 +53,7 @@
// to form the nonce.
// TODO(wtc): add a way for DecryptPacket to report decryption failure due
// to non-authentic inputs, as opposed to other reasons for failure.
- virtual bool DecryptPacket(QuicTransportVersion version,
- uint64_t packet_number,
+ virtual bool DecryptPacket(uint64_t packet_number,
QuicStringPiece associated_data,
QuicStringPiece ciphertext,
char* output,
diff --git a/quic/core/crypto/quic_encrypter.h b/quic/core/crypto/quic_encrypter.h
index 591021e..cb53e33 100644
--- a/quic/core/crypto/quic_encrypter.h
+++ b/quic/core/crypto/quic_encrypter.h
@@ -34,8 +34,7 @@
// SetNoncePrefix() to form the nonce. |output| must not overlap with
// |associated_data|. If |output| overlaps with |plaintext| then
// |plaintext| must be <= |output|.
- virtual bool EncryptPacket(QuicTransportVersion version,
- uint64_t packet_number,
+ virtual bool EncryptPacket(uint64_t packet_number,
QuicStringPiece associated_data,
QuicStringPiece plaintext,
char* output,
diff --git a/quic/core/frames/quic_ack_frame.cc b/quic/core/frames/quic_ack_frame.cc
index 5f47b3f..389f1c0 100644
--- a/quic/core/frames/quic_ack_frame.cc
+++ b/quic/core/frames/quic_ack_frame.cc
@@ -5,9 +5,9 @@
#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frame.h"
#include "net/third_party/quiche/src/quic/core/quic_constants.h"
+#include "net/third_party/quiche/src/quic/core/quic_interval.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_interval.h"
namespace quic {
diff --git a/quic/core/frames/quic_ack_frame.h b/quic/core/frames/quic_ack_frame.h
index 4dcfc3d..771d93e 100644
--- a/quic/core/frames/quic_ack_frame.h
+++ b/quic/core/frames/quic_ack_frame.h
@@ -7,11 +7,11 @@
#include <ostream>
+#include "net/third_party/quiche/src/quic/core/quic_interval.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_interval.h"
namespace quic {
diff --git a/quic/core/frames/quic_frames_test.cc b/quic/core/frames/quic_frames_test.cc
index af9c40b..8099ccc 100644
--- a/quic/core/frames/quic_frames_test.cc
+++ b/quic/core/frames/quic_frames_test.cc
@@ -14,8 +14,8 @@
#include "net/third_party/quiche/src/quic/core/frames/quic_stop_waiting_frame.h"
#include "net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h"
#include "net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.h"
+#include "net/third_party/quiche/src/quic/core/quic_interval.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_interval.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
diff --git a/quic/core/frames/quic_message_frame.cc b/quic/core/frames/quic_message_frame.cc
index 79a23fe..c0de272 100644
--- a/quic/core/frames/quic_message_frame.cc
+++ b/quic/core/frames/quic_message_frame.cc
@@ -9,17 +9,20 @@
namespace quic {
-QuicMessageFrame::QuicMessageFrame() : message_id(0) {}
+QuicMessageFrame::QuicMessageFrame()
+ : message_id(0), data(nullptr), message_length(0) {}
-QuicMessageFrame::QuicMessageFrame(QuicMessageId message_id,
- QuicStringPiece message_data)
- : message_id(message_id), message_data(message_data) {}
+QuicMessageFrame::QuicMessageFrame(QuicMessageId message_id)
+ : message_id(message_id), data(nullptr), message_length(0) {}
+
+QuicMessageFrame::QuicMessageFrame(const char* data, QuicPacketLength length)
+ : message_id(0), data(data), message_length(length) {}
QuicMessageFrame::~QuicMessageFrame() {}
std::ostream& operator<<(std::ostream& os, const QuicMessageFrame& s) {
os << " message_id: " << s.message_id
- << ", message_length: " << s.message_data.length() << " }\n";
+ << ", message_length: " << s.message_length << " }\n";
return os;
}
diff --git a/quic/core/frames/quic_message_frame.h b/quic/core/frames/quic_message_frame.h
index 6458a11..4accff2 100644
--- a/quic/core/frames/quic_message_frame.h
+++ b/quic/core/frames/quic_message_frame.h
@@ -6,14 +6,26 @@
#define QUICHE_QUIC_CORE_FRAMES_QUIC_MESSAGE_FRAME_H_
#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
namespace quic {
+typedef QuicInlinedVector<QuicMemSlice, 1> QuicMessageData;
+
struct QUIC_EXPORT_PRIVATE QuicMessageFrame {
QuicMessageFrame();
- QuicMessageFrame(QuicMessageId message_id, QuicStringPiece message_data);
+ explicit QuicMessageFrame(QuicMessageId message_id);
+ QuicMessageFrame(const char* data, QuicPacketLength length);
+
+ QuicMessageFrame(const QuicMessageFrame& other) = delete;
+ QuicMessageFrame& operator=(const QuicMessageFrame& other) = delete;
+
+ QuicMessageFrame(QuicMessageFrame&& other) = default;
+ QuicMessageFrame& operator=(QuicMessageFrame&& other) = default;
+
~QuicMessageFrame();
friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
@@ -23,8 +35,13 @@
// message_id is only used on the sender side and does not get serialized on
// wire.
QuicMessageId message_id;
- // The actual data.
- QuicString message_data;
+ // Not owned, only used on read path.
+ const char* data;
+ // Total length of message_data, must be fit into one packet.
+ QuicPacketLength message_length;
+
+ // The actual message data which is reference counted, used on write path.
+ QuicMessageData message_data;
};
} // namespace quic
diff --git a/quic/core/frames/quic_retire_connection_id_frame.cc b/quic/core/frames/quic_retire_connection_id_frame.cc
index a507269..6828ce4 100644
--- a/quic/core/frames/quic_retire_connection_id_frame.cc
+++ b/quic/core/frames/quic_retire_connection_id_frame.cc
@@ -1,3 +1,7 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
#include "net/third_party/quiche/src/quic/core/frames/quic_retire_connection_id_frame.h"
#include "net/third_party/quiche/src/quic/core/quic_constants.h"
diff --git a/quic/core/frames/quic_retire_connection_id_frame.h b/quic/core/frames/quic_retire_connection_id_frame.h
index 7bce51c..79521f6 100644
--- a/quic/core/frames/quic_retire_connection_id_frame.h
+++ b/quic/core/frames/quic_retire_connection_id_frame.h
@@ -1,3 +1,7 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_RETIRE_CONNECTION_ID_FRAME_H_
#define QUICHE_QUIC_CORE_FRAMES_QUIC_RETIRE_CONNECTION_ID_FRAME_H_
diff --git a/quic/core/http/end_to_end_test.cc b/quic/core/http/end_to_end_test.cc
index 132da8e..adf82c9 100644
--- a/quic/core/http/end_to_end_test.cc
+++ b/quic/core/http/end_to_end_test.cc
@@ -10,8 +10,6 @@
#include <utility>
#include <vector>
-#include "gfe/gfe2/base/epoll_server.h"
-#include "net/util/netutil.h"
#include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h"
#include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h"
#include "net/third_party/quiche/src/quic/core/quic_epoll_connection_helper.h"
@@ -26,6 +24,7 @@
#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_logging.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_port_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_sleep.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
@@ -139,18 +138,21 @@
ParsedQuicVersionVector all_supported_versions =
FilterSupportedVersions(AllSupportedVersions());
- // Buckets are separated by the handshake protocol (QUIC crypto or TLS) in
- // use, since if the handshake protocol changes, the ClientHello/CHLO must be
+ // Buckets are separated by versions: versions prior to QUIC_VERSION_47 use
+ // STREAM frames for the handshake, and only have QUIC crypto as the handshake
+ // protocol. Version 47 and greater use CRYPTO frames for the handshake, and
+ // 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[2];
+ ParsedQuicVersionVector version_buckets[3];
for (const ParsedQuicVersion& version : all_supported_versions) {
- // Versions: 35+
- // QUIC_VERSION_35 allows endpoints to independently set stream limit.
- if (version.handshake_protocol == PROTOCOL_TLS1_3) {
+ if (version.transport_version < QUIC_VERSION_47) {
+ version_buckets[0].push_back(version);
+ } else if (version.handshake_protocol == PROTOCOL_QUIC_CRYPTO) {
version_buckets[1].push_back(version);
} else {
- version_buckets[0].push_back(version);
+ version_buckets[2].push_back(version);
}
}
@@ -273,7 +275,7 @@
: initialized_(false),
connect_to_server_on_initialize_(true),
server_address_(
- QuicSocketAddress(TestLoopback(), net_util::PickUnusedPortOrDie())),
+ QuicSocketAddress(TestLoopback(), QuicPickUnusedPortOrDie())),
server_hostname_("test.example.com"),
client_writer_(nullptr),
server_writer_(nullptr),
@@ -313,9 +315,7 @@
AddToCache("/bar", 200, kBarResponseBody);
}
- ~EndToEndTest() override {
- net_util::RecycleUnusedPort(server_address_.port());
- }
+ ~EndToEndTest() override { QuicRecyclePort(server_address_.port()); }
virtual void CreateClientWithWriter() {
client_.reset(CreateQuicClient(client_writer_));
@@ -404,9 +404,6 @@
copt.push_back(kTPCC);
}
- if (support_server_push_) {
- copt.push_back(kSPSH);
- }
if (GetParam().client_supports_stateless_rejects) {
copt.push_back(kSREJ);
}
@@ -602,13 +599,15 @@
}
QuicStreamId GetNthClientInitiatedBidirectionalId(int n) {
- return QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId(
- *client_->client()->client_session(), n);
+ return GetNthClientInitiatedBidirectionalStreamId(
+ client_->client()->client_session()->connection()->transport_version(),
+ n);
}
QuicStreamId GetNthServerInitiatedBidirectionalId(int n) {
- return QuicSpdySessionPeer::GetNthServerInitiatedBidirectionalStreamId(
- *client_->client()->client_session(), n);
+ return GetNthServerInitiatedBidirectionalStreamId(
+ client_->client()->client_session()->connection()->transport_version(),
+ n);
}
ScopedEnvironmentForThreads environment_;
@@ -639,21 +638,21 @@
};
// Run all end to end tests with all supported versions.
-INSTANTIATE_TEST_CASE_P(EndToEndTests,
- EndToEndTest,
- ::testing::ValuesIn(GetTestParams(false, false)));
+INSTANTIATE_TEST_SUITE_P(EndToEndTests,
+ EndToEndTest,
+ ::testing::ValuesIn(GetTestParams(false, false)));
class EndToEndTestWithTls : public EndToEndTest {};
-INSTANTIATE_TEST_CASE_P(EndToEndTestsWithTls,
- EndToEndTestWithTls,
- ::testing::ValuesIn(GetTestParams(true, false)));
+INSTANTIATE_TEST_SUITE_P(EndToEndTestsWithTls,
+ EndToEndTestWithTls,
+ ::testing::ValuesIn(GetTestParams(true, false)));
class EndToEndTestWithStatelessReject : public EndToEndTest {};
-INSTANTIATE_TEST_CASE_P(WithStatelessReject,
- EndToEndTestWithStatelessReject,
- ::testing::ValuesIn(GetTestParams(false, true)));
+INSTANTIATE_TEST_SUITE_P(WithStatelessReject,
+ EndToEndTestWithStatelessReject,
+ ::testing::ValuesIn(GetTestParams(false, true)));
TEST_P(EndToEndTestWithTls, HandshakeSuccessful) {
ASSERT_TRUE(Initialize());
@@ -709,25 +708,6 @@
client_->client()->GetNumSentClientHellos());
}
-// TODO(dschinazi) remove this test once the flags are deprecated
-TEST_P(EndToEndTest, SimpleRequestResponseVariableLengthConnectionIDClient) {
- SetQuicRestartFlag(quic_variable_length_connection_ids_client, true);
- SetQuicRestartFlag(quic_variable_length_connection_ids_server, false);
- ASSERT_TRUE(Initialize());
-
- EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
- EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
- int expected_num_client_hellos = 2;
- if (ServerSendsVersionNegotiation()) {
- ++expected_num_client_hellos;
- if (BothSidesSupportStatelessRejects()) {
- ++expected_num_client_hellos;
- }
- }
- EXPECT_EQ(expected_num_client_hellos,
- client_->client()->GetNumSentClientHellos());
-}
-
TEST_P(EndToEndTest, SimpleRequestResponseZeroConnectionID) {
QuicConnectionId connection_id = QuicUtils::CreateZeroConnectionId(
GetParam().negotiated_version.transport_version);
@@ -750,25 +730,6 @@
GetParam().negotiated_version.transport_version));
}
-// TODO(dschinazi) remove this test once the flags are deprecated
-TEST_P(EndToEndTest, SimpleRequestResponseVariableLengthConnectionIDServer) {
- SetQuicRestartFlag(quic_variable_length_connection_ids_client, false);
- SetQuicRestartFlag(quic_variable_length_connection_ids_server, true);
- ASSERT_TRUE(Initialize());
-
- EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
- EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
- int expected_num_client_hellos = 2;
- if (ServerSendsVersionNegotiation()) {
- ++expected_num_client_hellos;
- if (BothSidesSupportStatelessRejects()) {
- ++expected_num_client_hellos;
- }
- }
- EXPECT_EQ(expected_num_client_hellos,
- client_->client()->GetNumSentClientHellos());
-}
-
TEST_P(EndToEndTest, SimpleRequestResponseWithLargeReject) {
chlo_multiplier_ = 1;
ASSERT_TRUE(Initialize());
@@ -1360,7 +1321,7 @@
// Make sure that the stream has data pending so that it will be marked as
// write blocked when it receives a stream level WINDOW_UPDATE.
- stream->WriteOrBufferBody("hello", false, nullptr);
+ stream->WriteOrBufferBody("hello", false);
// The stream now attempts to write, fails because it is still connection
// level flow control blocked, and is added to the write blocked list.
@@ -1949,7 +1910,7 @@
// Open a data stream to make sure the stream level flow control is updated.
QuicSpdyClientStream* stream = client_->GetOrCreateStream();
- stream->WriteOrBufferBody("hello", false, nullptr);
+ stream->WriteOrBufferBody("hello", false);
// Client should have the right values for server's receive window.
EXPECT_EQ(kServerStreamIFCW,
@@ -2005,7 +1966,7 @@
// Open a data stream to make sure the stream level flow control is updated.
QuicSpdyClientStream* stream = client_->GetOrCreateStream();
- stream->WriteOrBufferBody("hello", false, nullptr);
+ stream->WriteOrBufferBody("hello", false);
// Client should have the right values for server's receive window.
EXPECT_EQ(kExpectedStreamIFCW,
@@ -2045,9 +2006,14 @@
QuicCryptoStream* crypto_stream = QuicSessionPeer::GetMutableCryptoStream(
client_->client()->client_session());
- EXPECT_LT(
- QuicFlowControllerPeer::SendWindowSize(crypto_stream->flow_controller()),
- kStreamIFCW);
+ // In v47 and later, the crypto handshake (sent in CRYPTO frames) is not
+ // subject to flow control.
+ if (client_->client()->client_session()->connection()->transport_version() <
+ QUIC_VERSION_47) {
+ EXPECT_LT(QuicFlowControllerPeer::SendWindowSize(
+ crypto_stream->flow_controller()),
+ kStreamIFCW);
+ }
EXPECT_EQ(kSessionIFCW,
QuicFlowControllerPeer::SendWindowSize(
client_->client()->client_session()->flow_controller()));
@@ -2223,20 +2189,9 @@
QuicString request_string =
"a request body bigger than one packet" + QuicString(kMaxPacketSize, '.');
- // Calculate header length for version 99, so that the ack listener know how
- // many actual bytes will be acked.
- QuicByteCount header_length = 0;
- if (client_->client()->client_session()->connection()->transport_version() ==
- QUIC_VERSION_99) {
- HttpEncoder encoder;
- std::unique_ptr<char[]> buf;
- header_length =
- encoder.SerializeDataFrameHeader(request_string.length(), &buf);
- }
-
// The TestAckListener will cause a failure if not notified.
QuicReferenceCountedPointer<TestAckListener> ack_listener(
- new TestAckListener(request_string.length() + header_length));
+ new TestAckListener(request_string.length()));
// Send the request, and register the delegate for ACKs.
client_->SendData(request_string, true, ack_listener);
@@ -2875,9 +2830,9 @@
};
// Run all server push end to end tests with all supported versions.
-INSTANTIATE_TEST_CASE_P(EndToEndTestsServerPush,
- EndToEndTestServerPush,
- ::testing::ValuesIn(GetTestParams(false, false)));
+INSTANTIATE_TEST_SUITE_P(EndToEndTestsServerPush,
+ EndToEndTestServerPush,
+ ::testing::ValuesIn(GetTestParams(false, false)));
TEST_P(EndToEndTestServerPush, ServerPush) {
ASSERT_TRUE(Initialize());
@@ -3266,7 +3221,6 @@
QuicConnection* client_connection =
client_->client()->client_session()->connection();
client_connection->set_debug_visitor(&observer);
- QuicTransportVersion version = client_connection->transport_version();
// 100KB body.
QuicString body(100 * 1024, 'a');
SpdyHeaderBlock headers;
@@ -3278,12 +3232,8 @@
EXPECT_EQ(kFooResponseBody,
client_->SendCustomSynchronousRequest(headers, body));
client_->Disconnect();
- if (version != QUIC_VERSION_35) {
- EXPECT_LT(0u, observer.num_window_update_frames());
- EXPECT_EQ(0u, observer.num_ping_frames());
- } else {
- EXPECT_EQ(0u, observer.num_window_update_frames());
- }
+ EXPECT_LT(0u, observer.num_window_update_frames());
+ EXPECT_EQ(0u, observer.num_ping_frames());
}
TEST_P(EndToEndTest, SendStatelessResetTokenInShlo) {
@@ -3506,13 +3456,12 @@
// 1 MB body.
QuicString body(1024 * 1024, 'a');
- stream->WriteOrBufferBody(body, true, nullptr);
+ stream->WriteOrBufferBody(body, true);
client_->WaitForResponse();
EXPECT_EQ(QUIC_STREAM_TTL_EXPIRED, client_->stream_error());
}
TEST_P(EndToEndTest, SendMessages) {
- SetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission, true);
ASSERT_TRUE(Initialize());
EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
QuicSession* client_session = client_->client()->client_session();
@@ -3529,22 +3478,30 @@
QuicStringPiece message_buffer(message_string);
QuicRandom* random =
QuicConnectionPeer::GetHelper(client_connection)->GetRandomGenerator();
+ QuicMemSliceStorage storage(nullptr, 0, nullptr, 0);
{
QuicConnection::ScopedPacketFlusher flusher(
client_session->connection(), QuicConnection::SEND_ACK_IF_PENDING);
// Verify the largest message gets successfully sent.
EXPECT_EQ(MessageResult(MESSAGE_STATUS_SUCCESS, 1),
- client_session->SendMessage(
+ client_session->SendMessage(MakeSpan(
+ client_session->connection()
+ ->helper()
+ ->GetStreamSendBufferAllocator(),
QuicStringPiece(message_buffer.data(),
- client_session->GetLargestMessagePayload())));
+ client_session->GetLargestMessagePayload()),
+ &storage)));
// Send more messages with size (0, largest_payload] until connection is
// write blocked.
const int kTestMaxNumberOfMessages = 100;
for (size_t i = 2; i <= kTestMaxNumberOfMessages; ++i) {
size_t message_length =
random->RandUint64() % client_session->GetLargestMessagePayload() + 1;
- MessageResult result = client_session->SendMessage(
- QuicStringPiece(message_buffer.data(), message_length));
+ MessageResult result = client_session->SendMessage(MakeSpan(
+ client_session->connection()
+ ->helper()
+ ->GetStreamSendBufferAllocator(),
+ QuicStringPiece(message_buffer.data(), message_length), &storage));
if (result.status == MESSAGE_STATUS_BLOCKED) {
// Connection is write blocked.
break;
@@ -3554,12 +3511,17 @@
}
client_->WaitForDelayedAcks();
- EXPECT_EQ(MESSAGE_STATUS_TOO_LARGE,
- client_session
- ->SendMessage(QuicStringPiece(
- message_buffer.data(),
- client_session->GetLargestMessagePayload() + 1))
- .status);
+ EXPECT_EQ(
+ MESSAGE_STATUS_TOO_LARGE,
+ client_session
+ ->SendMessage(MakeSpan(
+ client_session->connection()
+ ->helper()
+ ->GetStreamSendBufferAllocator(),
+ QuicStringPiece(message_buffer.data(),
+ client_session->GetLargestMessagePayload() + 1),
+ &storage))
+ .status);
EXPECT_EQ(QUIC_NO_ERROR, client_->connection_error());
}
@@ -3580,9 +3542,9 @@
PacketReorderingWriter* reorder_writer_;
};
-INSTANTIATE_TEST_CASE_P(EndToEndPacketReorderingTests,
- EndToEndPacketReorderingTest,
- testing::ValuesIn(GetTestParams(false, false)));
+INSTANTIATE_TEST_SUITE_P(EndToEndPacketReorderingTests,
+ EndToEndPacketReorderingTest,
+ testing::ValuesIn(GetTestParams(false, false)));
TEST_P(EndToEndPacketReorderingTest, ReorderedConnectivityProbing) {
ASSERT_TRUE(Initialize());
diff --git a/quic/core/http/http_decoder.cc b/quic/core/http/http_decoder.cc
index 345f2cb..e697821 100644
--- a/quic/core/http/http_decoder.cc
+++ b/quic/core/http/http_decoder.cc
@@ -22,7 +22,7 @@
}
// Length of the type field of HTTP/3 frames.
-static const size_t kFrameTypeLength = 1;
+static const QuicByteCount kFrameTypeLength = 1;
} // namespace
@@ -40,9 +40,9 @@
HttpDecoder::~HttpDecoder() {}
-size_t HttpDecoder::ProcessInput(const char* data, size_t len) {
+QuicByteCount HttpDecoder::ProcessInput(const char* data, QuicByteCount len) {
has_payload_ = false;
- QuicDataReader reader(data, len, NETWORK_BYTE_ORDER);
+ QuicDataReader reader(data, len);
while (error_ == QUIC_NO_ERROR && reader.BytesRemaining() != 0) {
switch (state_) {
case STATE_READING_FRAME_LENGTH:
@@ -75,7 +75,7 @@
return;
}
QuicDataReader length_reader(length_buffer_.data(),
- current_length_field_size_, NETWORK_BYTE_ORDER);
+ current_length_field_size_);
if (!length_reader.ReadVarInt62(¤t_frame_length_)) {
RaiseError(QUIC_INTERNAL_ERROR, "Unable to read frame length");
visitor_->OnError(this);
@@ -105,8 +105,8 @@
Http3FrameLengths(current_length_field_size_ + kFrameTypeLength,
current_frame_length_));
}
- size_t bytes_to_read =
- std::min<size_t>(remaining_frame_length_, reader->BytesRemaining());
+ QuicByteCount bytes_to_read = std::min<QuicByteCount>(
+ remaining_frame_length_, reader->BytesRemaining());
QuicStringPiece payload;
if (!reader->ReadStringPiece(&payload, bytes_to_read)) {
RaiseError(QUIC_INTERNAL_ERROR, "Unable to read data");
@@ -126,8 +126,8 @@
if (current_frame_length_ == remaining_frame_length_) {
visitor_->OnHeadersFrameStart();
}
- size_t bytes_to_read =
- std::min<size_t>(remaining_frame_length_, reader->BytesRemaining());
+ QuicByteCount bytes_to_read = std::min<QuicByteCount>(
+ remaining_frame_length_, reader->BytesRemaining());
QuicStringPiece payload;
if (!reader->ReadStringPiece(&payload, bytes_to_read)) {
RaiseError(QUIC_INTERNAL_ERROR, "Unable to read data");
@@ -138,7 +138,7 @@
if (remaining_frame_length_ == 0) {
state_ = STATE_READING_FRAME_LENGTH;
current_length_field_size_ = 0;
- visitor_->OnHeadersFrameEnd();
+ visitor_->OnHeadersFrameEnd(current_frame_length_);
}
return;
}
@@ -148,8 +148,7 @@
BufferFramePayload(reader);
if (remaining_frame_length_ == 0) {
PriorityFrame frame;
- QuicDataReader reader(buffer_.data(), current_frame_length_,
- NETWORK_BYTE_ORDER);
+ QuicDataReader reader(buffer_.data(), current_frame_length_);
if (!ParsePriorityFrame(&reader, &frame)) {
return;
}
@@ -164,8 +163,7 @@
BufferFramePayload(reader);
if (remaining_frame_length_ == 0) {
CancelPushFrame frame;
- QuicDataReader reader(buffer_.data(), current_frame_length_,
- NETWORK_BYTE_ORDER);
+ QuicDataReader reader(buffer_.data(), current_frame_length_);
if (!reader.ReadVarInt62(&frame.push_id)) {
RaiseError(QUIC_INTERNAL_ERROR, "Unable to read push_id");
return;
@@ -184,8 +182,7 @@
BufferFramePayload(reader);
if (remaining_frame_length_ == 0) {
SettingsFrame frame;
- QuicDataReader reader(buffer_.data(), current_frame_length_,
- NETWORK_BYTE_ORDER);
+ QuicDataReader reader(buffer_.data(), current_frame_length_);
if (!ParseSettingsFrame(&reader, &frame)) {
return;
}
@@ -197,7 +194,7 @@
}
case 0x5: { // PUSH_PROMISE
if (current_frame_length_ == remaining_frame_length_) {
- size_t bytes_remaining = reader->BytesRemaining();
+ QuicByteCount bytes_remaining = reader->BytesRemaining();
PushId push_id;
// TODO(rch): Handle partial delivery of this field.
if (!reader->ReadVarInt62(&push_id)) {
@@ -207,8 +204,8 @@
remaining_frame_length_ -= bytes_remaining - reader->BytesRemaining();
visitor_->OnPushPromiseFrameStart(push_id);
}
- size_t bytes_to_read =
- std::min<size_t>(remaining_frame_length_, reader->BytesRemaining());
+ QuicByteCount bytes_to_read = std::min<QuicByteCount>(
+ remaining_frame_length_, reader->BytesRemaining());
if (bytes_to_read == 0) {
return;
}
@@ -230,8 +227,7 @@
BufferFramePayload(reader);
if (remaining_frame_length_ == 0) {
GoAwayFrame frame;
- QuicDataReader reader(buffer_.data(), current_frame_length_,
- NETWORK_BYTE_ORDER);
+ QuicDataReader reader(buffer_.data(), current_frame_length_);
uint64_t stream_id;
if (!reader.ReadVarInt62(&stream_id)) {
RaiseError(QUIC_INTERNAL_ERROR, "Unable to read GOAWAY stream_id");
@@ -249,8 +245,7 @@
// TODO(rch): Handle partial delivery.
BufferFramePayload(reader);
if (remaining_frame_length_ == 0) {
- QuicDataReader reader(buffer_.data(), current_frame_length_,
- NETWORK_BYTE_ORDER);
+ QuicDataReader reader(buffer_.data(), current_frame_length_);
MaxPushIdFrame frame;
if (!reader.ReadVarInt62(&frame.push_id)) {
RaiseError(QUIC_INTERNAL_ERROR, "Unable to read push_id");
@@ -268,8 +263,7 @@
if (remaining_frame_length_ != 0) {
return;
}
- QuicDataReader reader(buffer_.data(), current_frame_length_,
- NETWORK_BYTE_ORDER);
+ QuicDataReader reader(buffer_.data(), current_frame_length_);
DuplicatePushFrame frame;
if (!reader.ReadVarInt62(&frame.push_id)) {
RaiseError(QUIC_INTERNAL_ERROR, "Unable to read push_id");
@@ -305,8 +299,8 @@
}
void HttpDecoder::DiscardFramePayload(QuicDataReader* reader) {
- size_t bytes_to_read =
- std::min<size_t>(remaining_frame_length_, reader->BytesRemaining());
+ QuicByteCount bytes_to_read = std::min<QuicByteCount>(
+ remaining_frame_length_, reader->BytesRemaining());
QuicStringPiece payload;
if (!reader->ReadStringPiece(&payload, bytes_to_read)) {
RaiseError(QUIC_INTERNAL_ERROR, "Unable to read frame payload");
@@ -324,8 +318,8 @@
buffer_.erase(buffer_.size());
buffer_.reserve(current_frame_length_);
}
- size_t bytes_to_read =
- std::min<size_t>(remaining_frame_length_, reader->BytesRemaining());
+ QuicByteCount bytes_to_read = std::min<QuicByteCount>(
+ remaining_frame_length_, reader->BytesRemaining());
if (!reader->ReadBytes(
&(buffer_[0]) + current_frame_length_ - remaining_frame_length_,
bytes_to_read)) {
@@ -349,8 +343,8 @@
length_buffer_.erase(length_buffer_.size());
length_buffer_.reserve(current_length_field_size_);
}
- size_t bytes_to_read = std::min<size_t>(remaining_length_field_length_,
- reader->BytesRemaining());
+ QuicByteCount bytes_to_read = std::min<QuicByteCount>(
+ remaining_length_field_length_, reader->BytesRemaining());
if (!reader->ReadBytes(&(length_buffer_[0]) + current_length_field_size_ -
remaining_length_field_length_,
bytes_to_read)) {
diff --git a/quic/core/http/http_decoder.h b/quic/core/http/http_decoder.h
index a5f41b5..910d189 100644
--- a/quic/core/http/http_decoder.h
+++ b/quic/core/http/http_decoder.h
@@ -9,6 +9,7 @@
#include "net/third_party/quiche/src/quic/core/http/http_frames.h"
#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
@@ -20,7 +21,7 @@
// |header_length| stores number of bytes header occupies.
// |payload_length| stores number of bytes payload occupies.
struct QUIC_EXPORT_PRIVATE Http3FrameLengths {
- Http3FrameLengths(uint64_t header, uint64_t payload)
+ Http3FrameLengths(QuicByteCount header, QuicByteCount payload)
: header_length(header), payload_length(payload) {}
bool operator==(const Http3FrameLengths& other) const {
@@ -76,7 +77,8 @@
// multiple times for a single frame.
virtual void OnHeadersFramePayload(QuicStringPiece payload) = 0;
// Called when a HEADERS frame has been completely processed.
- virtual void OnHeadersFrameEnd() = 0;
+ // |frame_len| is the length of the HEADERS frame payload.
+ virtual void OnHeadersFrameEnd(QuicByteCount frame_len) = 0;
// Called when a PUSH_PROMISE frame has been recevied for |push_id|.
virtual void OnPushPromiseFrameStart(PushId push_id) = 0;
@@ -104,7 +106,7 @@
// Processes the input and invokes the visitor for any frames.
// Returns the number of bytes consumed, or 0 if there was an error, in which
// case error() should be consulted.
- size_t ProcessInput(const char* data, size_t len);
+ QuicByteCount ProcessInput(const char* data, QuicByteCount len);
bool has_payload() { return has_payload_; }
@@ -158,13 +160,13 @@
// Type of the frame currently being parsed.
uint8_t current_frame_type_;
// Size of the frame's length field.
- uint64_t current_length_field_size_;
+ QuicByteCount current_length_field_size_;
// Remaining length that's needed for the frame's length field.
- uint64_t remaining_length_field_length_;
+ QuicByteCount remaining_length_field_length_;
// Length of the payload of the frame currently being parsed.
- uint64_t current_frame_length_;
+ QuicByteCount current_frame_length_;
// Remaining payload bytes to be parsed.
- uint64_t remaining_frame_length_;
+ QuicByteCount remaining_frame_length_;
// Last error.
QuicErrorCode error_;
// The issue which caused |error_|
diff --git a/quic/core/http/http_decoder_test.cc b/quic/core/http/http_decoder_test.cc
index c2b303c..c6d7d9f 100644
--- a/quic/core/http/http_decoder_test.cc
+++ b/quic/core/http/http_decoder_test.cc
@@ -31,7 +31,7 @@
MOCK_METHOD0(OnHeadersFrameStart, void());
MOCK_METHOD1(OnHeadersFramePayload, void(QuicStringPiece payload));
- MOCK_METHOD0(OnHeadersFrameEnd, void());
+ MOCK_METHOD1(OnHeadersFrameEnd, void(QuicByteCount frame_len));
MOCK_METHOD1(OnPushPromiseFrameStart, void(PushId push_id));
MOCK_METHOD1(OnPushPromiseFramePayload, void(QuicStringPiece payload));
@@ -84,7 +84,7 @@
TEST_F(HttpDecoderTest, ReservedFramesLargePayload) {
for (int n = 0; n < 8; ++n) {
const uint8_t type = 0xB + 0x1F * n;
- const size_t payload_size = 256;
+ const QuicByteCount payload_size = 256;
char input[payload_size + 3] = {// length
0x40 + 0x01, 0x00,
// type
@@ -383,7 +383,7 @@
InSequence s;
EXPECT_CALL(visitor_, OnHeadersFrameStart());
EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("Headers")));
- EXPECT_CALL(visitor_, OnHeadersFrameEnd());
+ EXPECT_CALL(visitor_, OnHeadersFrameEnd(7));
EXPECT_EQ(QUIC_ARRAYSIZE(input),
decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input)));
EXPECT_EQ(QUIC_NO_ERROR, decoder_.error());
@@ -398,7 +398,7 @@
EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("e")));
EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("r")));
EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("s")));
- EXPECT_CALL(visitor_, OnHeadersFrameEnd());
+ EXPECT_CALL(visitor_, OnHeadersFrameEnd(7));
for (char c : input) {
EXPECT_EQ(1u, decoder_.ProcessInput(&c, 1));
}
diff --git a/quic/core/http/http_encoder.cc b/quic/core/http/http_encoder.cc
index 7c07838..d2d1699 100644
--- a/quic/core/http/http_encoder.cc
+++ b/quic/core/http/http_encoder.cc
@@ -66,7 +66,7 @@
QuicDataWriter::GetVarInt62Len(payload_length) + kFrameTypeLength;
output->reset(new char[header_length]);
- QuicDataWriter writer(header_length, output->get(), NETWORK_BYTE_ORDER);
+ QuicDataWriter writer(header_length, output->get());
if (WriteFrameHeader(payload_length, HttpFrameType::DATA, &writer)) {
return header_length;
@@ -82,7 +82,7 @@
QuicDataWriter::GetVarInt62Len(payload_length) + kFrameTypeLength;
output->reset(new char[header_length]);
- QuicDataWriter writer(header_length, output->get(), NETWORK_BYTE_ORDER);
+ QuicDataWriter writer(header_length, output->get());
if (WriteFrameHeader(payload_length, HttpFrameType::HEADERS, &writer)) {
return header_length;
@@ -101,7 +101,7 @@
QuicByteCount total_length = GetTotalLength(payload_length);
output->reset(new char[total_length]);
- QuicDataWriter writer(total_length, output->get(), NETWORK_BYTE_ORDER);
+ QuicDataWriter writer(total_length, output->get());
if (!WriteFrameHeader(payload_length, HttpFrameType::PRIORITY, &writer)) {
return 0;
@@ -132,7 +132,7 @@
QuicByteCount total_length = GetTotalLength(payload_length);
output->reset(new char[total_length]);
- QuicDataWriter writer(total_length, output->get(), NETWORK_BYTE_ORDER);
+ QuicDataWriter writer(total_length, output->get());
if (WriteFrameHeader(payload_length, HttpFrameType::CANCEL_PUSH, &writer) &&
writer.WriteVarInt62(cancel_push.push_id)) {
@@ -154,7 +154,7 @@
QuicByteCount total_length = GetTotalLength(payload_length);
output->reset(new char[total_length]);
- QuicDataWriter writer(total_length, output->get(), NETWORK_BYTE_ORDER);
+ QuicDataWriter writer(total_length, output->get());
if (!WriteFrameHeader(payload_length, HttpFrameType::SETTINGS, &writer)) {
return 0;
@@ -181,7 +181,7 @@
QuicDataWriter::GetVarInt62Len(push_promise.push_id);
output->reset(new char[total_length]);
- QuicDataWriter writer(total_length, output->get(), NETWORK_BYTE_ORDER);
+ QuicDataWriter writer(total_length, output->get());
if (WriteFrameHeader(payload_length, HttpFrameType::PUSH_PROMISE, &writer) &&
writer.WriteVarInt62(push_promise.push_id)) {
@@ -198,7 +198,7 @@
QuicByteCount total_length = GetTotalLength(payload_length);
output->reset(new char[total_length]);
- QuicDataWriter writer(total_length, output->get(), NETWORK_BYTE_ORDER);
+ QuicDataWriter writer(total_length, output->get());
if (WriteFrameHeader(payload_length, HttpFrameType::GOAWAY, &writer) &&
writer.WriteVarInt62(goaway.stream_id)) {
@@ -215,7 +215,7 @@
QuicByteCount total_length = GetTotalLength(payload_length);
output->reset(new char[total_length]);
- QuicDataWriter writer(total_length, output->get(), NETWORK_BYTE_ORDER);
+ QuicDataWriter writer(total_length, output->get());
if (WriteFrameHeader(payload_length, HttpFrameType::MAX_PUSH_ID, &writer) &&
writer.WriteVarInt62(max_push_id.push_id)) {
@@ -232,7 +232,7 @@
QuicByteCount total_length = GetTotalLength(payload_length);
output->reset(new char[total_length]);
- QuicDataWriter writer(total_length, output->get(), NETWORK_BYTE_ORDER);
+ QuicDataWriter writer(total_length, output->get());
if (WriteFrameHeader(payload_length, HttpFrameType::DUPLICATE_PUSH,
&writer) &&
diff --git a/quic/core/http/quic_client_promised_info_test.cc b/quic/core/http/quic_client_promised_info_test.cc
index 2cf3f76..2a7b1b0 100644
--- a/quic/core/http/quic_client_promised_info_test.cc
+++ b/quic/core/http/quic_client_promised_info_test.cc
@@ -84,8 +84,8 @@
headers_["content-length"] = "11";
stream_ = QuicMakeUnique<QuicSpdyClientStream>(
- QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId(
- session_, 0),
+ GetNthClientInitiatedBidirectionalStreamId(
+ connection_->transport_version(), 0),
&session_, BIDIRECTIONAL);
stream_visitor_ = QuicMakeUnique<StreamVisitor>();
stream_->set_visitor(stream_visitor_.get());
@@ -99,9 +99,8 @@
promise_url_ = SpdyUtils::GetPromisedUrlFromHeaders(push_promise_);
client_request_ = push_promise_.Clone();
- promise_id_ =
- QuicSpdySessionPeer::GetNthServerInitiatedUnidirectionalStreamId(
- session_, 0);
+ promise_id_ = GetNthServerInitiatedUnidirectionalStreamId(
+ connection_->transport_version(), 0);
}
class StreamVisitor : public QuicSpdyClientStream::Visitor {
diff --git a/quic/core/http/quic_client_push_promise_index_test.cc b/quic/core/http/quic_client_push_promise_index_test.cc
index 0ddde61..b68b41f 100644
--- a/quic/core/http/quic_client_push_promise_index_test.cc
+++ b/quic/core/http/quic_client_push_promise_index_test.cc
@@ -54,12 +54,11 @@
&alarm_factory_,
Perspective::IS_CLIENT)),
session_(connection_->supported_versions(), connection_, &index_),
- promised_(
- &session_,
- QuicSpdySessionPeer::GetNthServerInitiatedUnidirectionalStreamId(
- session_,
- 0),
- url_) {
+ promised_(&session_,
+ GetNthServerInitiatedUnidirectionalStreamId(
+ connection_->transport_version(),
+ 0),
+ url_) {
request_[":path"] = "/bar";
request_[":authority"] = "www.google.com";
request_[":version"] = "HTTP/1.1";
diff --git a/quic/core/http/quic_headers_stream.cc b/quic/core/http/quic_headers_stream.cc
index 09d8797..9c99ab7 100644
--- a/quic/core/http/quic_headers_stream.cc
+++ b/quic/core/http/quic_headers_stream.cc
@@ -60,7 +60,8 @@
bool QuicHeadersStream::OnStreamFrameAcked(QuicStreamOffset offset,
QuicByteCount data_length,
bool fin_acked,
- QuicTime::Delta ack_delay_time) {
+ QuicTime::Delta ack_delay_time,
+ QuicByteCount* newly_acked_length) {
QuicIntervalSet<QuicStreamOffset> newly_acked(offset, offset + data_length);
newly_acked.Difference(bytes_acked());
for (const auto& acked : newly_acked) {
@@ -104,7 +105,7 @@
unacked_headers_.pop_front();
}
return QuicStream::OnStreamFrameAcked(offset, data_length, fin_acked,
- ack_delay_time);
+ ack_delay_time, newly_acked_length);
}
void QuicHeadersStream::OnStreamFrameRetransmitted(QuicStreamOffset offset,
diff --git a/quic/core/http/quic_headers_stream.h b/quic/core/http/quic_headers_stream.h
index 4abfb01..abc0aeb 100644
--- a/quic/core/http/quic_headers_stream.h
+++ b/quic/core/http/quic_headers_stream.h
@@ -43,7 +43,8 @@
bool OnStreamFrameAcked(QuicStreamOffset offset,
QuicByteCount data_length,
bool fin_acked,
- QuicTime::Delta ack_delay_time) override;
+ QuicTime::Delta ack_delay_time,
+ QuicByteCount* newly_acked_length) override;
void OnStreamFrameRetransmitted(QuicStreamOffset offset,
QuicByteCount data_length,
diff --git a/quic/core/http/quic_headers_stream_test.cc b/quic/core/http/quic_headers_stream_test.cc
index 1bbb9e4..b6409b1 100644
--- a/quic/core/http/quic_headers_stream_test.cc
+++ b/quic/core/http/quic_headers_stream_test.cc
@@ -195,21 +195,19 @@
EXPECT_EQ(transport_version(), session_.connection()->transport_version());
EXPECT_TRUE(headers_stream_ != nullptr);
connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
- client_id_1_ =
- QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId(
- session_, 0);
- client_id_2_ =
- QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId(
- session_, 1);
- client_id_3_ =
- QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId(
- session_, 2);
- next_stream_id_ = QuicSpdySessionPeer::StreamIdDelta(session_);
+ client_id_1_ = GetNthClientInitiatedBidirectionalStreamId(
+ connection_->transport_version(), 0);
+ client_id_2_ = GetNthClientInitiatedBidirectionalStreamId(
+ connection_->transport_version(), 1);
+ client_id_3_ = GetNthClientInitiatedBidirectionalStreamId(
+ connection_->transport_version(), 2);
+ next_stream_id_ =
+ QuicUtils::StreamIdDelta(connection_->transport_version());
}
QuicStreamId GetNthClientInitiatedId(int n) {
- return QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId(
- session_, n);
+ return GetNthClientInitiatedBidirectionalStreamId(
+ connection_->transport_version(), n);
}
QuicConsumedData SaveIov(size_t write_length) {
@@ -278,9 +276,8 @@
connection_->transport_version()),
_, _, NO_FIN))
.WillOnce(WithArgs<2>(Invoke(this, &QuicHeadersStreamTest::SaveIov)));
- QuicSpdySessionPeer::WriteHeadersImpl(
- &session_, stream_id, headers_.Clone(), fin,
- Spdy3PriorityToHttp2Weight(priority), 0, false, nullptr);
+ QuicSpdySessionPeer::WriteHeadersOnHeadersStream(
+ &session_, stream_id, headers_.Clone(), fin, priority, nullptr);
// Parse the outgoing data and check that it matches was was written.
if (is_request) {
@@ -363,9 +360,8 @@
};
// Run all tests with each version and perspective (client or server).
-INSTANTIATE_TEST_CASE_P(Tests,
- QuicHeadersStreamTest,
- ::testing::ValuesIn(GetTestParams()));
+INSTANTIATE_TEST_SUITE_P(Tests, QuicHeadersStreamTest,
+ ::testing::ValuesIn(GetTestParams()));
TEST_P(QuicHeadersStreamTest, StreamId) {
EXPECT_EQ(QuicUtils::GetHeadersStreamId(connection_->transport_version()),
@@ -833,27 +829,34 @@
headers_stream_->OnStreamFrameRetransmitted(28, 7, false);
// Packets are acked in order: 2, 3, 1.
+ QuicByteCount newly_acked_length = 0;
EXPECT_CALL(*ack_listener3, OnPacketAcked(7, _));
EXPECT_CALL(*ack_listener2, OnPacketAcked(7, _));
- EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(21, 7, false,
- QuicTime::Delta::Zero()));
- EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(28, 7, false,
- QuicTime::Delta::Zero()));
+ EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(
+ 21, 7, false, QuicTime::Delta::Zero(), &newly_acked_length));
+ EXPECT_EQ(7u, newly_acked_length);
+ EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(
+ 28, 7, false, QuicTime::Delta::Zero(), &newly_acked_length));
+ EXPECT_EQ(7u, newly_acked_length);
EXPECT_CALL(*ack_listener3, OnPacketAcked(7, _));
- EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(35, 7, false,
- QuicTime::Delta::Zero()));
+ EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(
+ 35, 7, false, QuicTime::Delta::Zero(), &newly_acked_length));
+ EXPECT_EQ(7u, newly_acked_length);
EXPECT_CALL(*ack_listener1, OnPacketAcked(7, _));
EXPECT_CALL(*ack_listener1, OnPacketAcked(7, _));
- EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(0, 7, false,
- QuicTime::Delta::Zero()));
- EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(7, 7, false,
- QuicTime::Delta::Zero()));
+ EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(
+ 0, 7, false, QuicTime::Delta::Zero(), &newly_acked_length));
+ EXPECT_EQ(7u, newly_acked_length);
+ EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(
+ 7, 7, false, QuicTime::Delta::Zero(), &newly_acked_length));
+ EXPECT_EQ(7u, newly_acked_length);
// Unsent data is acked.
EXPECT_CALL(*ack_listener2, OnPacketAcked(7, _));
- EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(14, 10, false,
- QuicTime::Delta::Zero()));
+ EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(
+ 14, 10, false, QuicTime::Delta::Zero(), &newly_acked_length));
+ EXPECT_EQ(7u, newly_acked_length);
}
TEST_P(QuicHeadersStreamTest, FrameContainsMultipleHeaders) {
@@ -884,21 +887,25 @@
headers_stream_->OnStreamFrameRetransmitted(0, 17, false);
// Frames are acked in order: 2, 3, 1.
+ QuicByteCount newly_acked_length = 0;
EXPECT_CALL(*ack_listener2, OnPacketAcked(4, _));
EXPECT_CALL(*ack_listener3, OnPacketAcked(7, _));
EXPECT_CALL(*ack_listener2, OnPacketAcked(2, _));
- EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(17, 13, false,
- QuicTime::Delta::Zero()));
+ EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(
+ 17, 13, false, QuicTime::Delta::Zero(), &newly_acked_length));
+ EXPECT_EQ(13u, newly_acked_length);
EXPECT_CALL(*ack_listener2, OnPacketAcked(5, _));
EXPECT_CALL(*ack_listener3, OnPacketAcked(7, _));
- EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(30, 12, false,
- QuicTime::Delta::Zero()));
+ EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(
+ 30, 12, false, QuicTime::Delta::Zero(), &newly_acked_length));
+ EXPECT_EQ(12u, newly_acked_length);
EXPECT_CALL(*ack_listener1, OnPacketAcked(14, _));
EXPECT_CALL(*ack_listener2, OnPacketAcked(3, _));
- EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(0, 17, false,
- QuicTime::Delta::Zero()));
+ EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(
+ 0, 17, false, QuicTime::Delta::Zero(), &newly_acked_length));
+ EXPECT_EQ(17u, newly_acked_length);
}
TEST_P(QuicHeadersStreamTest, HeadersGetAckedMultipleTimes) {
@@ -924,30 +931,36 @@
headers_stream_->WriteOrBufferData("Header9", false, ack_listener3);
// Ack [15, 20), [5, 25), [10, 17), [0, 12) and [22, 42).
+ QuicByteCount newly_acked_length = 0;
EXPECT_CALL(*ack_listener2, OnPacketAcked(5, _));
- EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(15, 5, false,
- QuicTime::Delta::Zero()));
+ EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(
+ 15, 5, false, QuicTime::Delta::Zero(), &newly_acked_length));
+ EXPECT_EQ(5u, newly_acked_length);
EXPECT_CALL(*ack_listener1, OnPacketAcked(9, _));
EXPECT_CALL(*ack_listener2, OnPacketAcked(1, _));
EXPECT_CALL(*ack_listener2, OnPacketAcked(1, _));
EXPECT_CALL(*ack_listener3, OnPacketAcked(4, _));
- EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(5, 20, false,
- QuicTime::Delta::Zero()));
+ EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(
+ 5, 20, false, QuicTime::Delta::Zero(), &newly_acked_length));
+ EXPECT_EQ(15u, newly_acked_length);
// Duplicate ack.
- EXPECT_FALSE(headers_stream_->OnStreamFrameAcked(10, 7, false,
- QuicTime::Delta::Zero()));
+ EXPECT_FALSE(headers_stream_->OnStreamFrameAcked(
+ 10, 7, false, QuicTime::Delta::Zero(), &newly_acked_length));
+ EXPECT_EQ(0u, newly_acked_length);
EXPECT_CALL(*ack_listener1, OnPacketAcked(5, _));
- EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(0, 12, false,
- QuicTime::Delta::Zero()));
+ EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(
+ 0, 12, false, QuicTime::Delta::Zero(), &newly_acked_length));
+ EXPECT_EQ(5u, newly_acked_length);
EXPECT_CALL(*ack_listener3, OnPacketAcked(3, _));
EXPECT_CALL(*ack_listener2, OnPacketAcked(7, _));
EXPECT_CALL(*ack_listener3, OnPacketAcked(7, _));
- EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(22, 20, false,
- QuicTime::Delta::Zero()));
+ EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(
+ 22, 20, false, QuicTime::Delta::Zero(), &newly_acked_length));
+ EXPECT_EQ(17u, newly_acked_length);
}
} // namespace
diff --git a/quic/core/http/quic_server_session_base.cc b/quic/core/http/quic_server_session_base.cc
index 40b43dc..b18b1fa 100644
--- a/quic/core/http/quic_server_session_base.cc
+++ b/quic/core/http/quic_server_session_base.cc
@@ -55,11 +55,6 @@
bandwidth_resumption_enabled_ =
last_bandwidth_resumption || max_bandwidth_resumption;
- if (connection()->transport_version() < QUIC_VERSION_35) {
- set_server_push_enabled(
- ContainsQuicTag(config()->ReceivedConnectionOptions(), kSPSH));
- }
-
// If the client has provided a bandwidth estimate from the same serving
// region as this server, then decide whether to use the data for bandwidth
// resumption.
diff --git a/quic/core/http/quic_server_session_base_test.cc b/quic/core/http/quic_server_session_base_test.cc
index 9f36e37..2b75f70 100644
--- a/quic/core/http/quic_server_session_base_test.cc
+++ b/quic/core/http/quic_server_session_base_test.cc
@@ -65,7 +65,7 @@
compressed_certs_cache),
quic_simple_server_backend_(quic_simple_server_backend) {}
- ~TestServerSession() override { delete connection(); };
+ ~TestServerSession() override { delete connection(); }
protected:
QuicSpdyStream* CreateIncomingStream(QuicStreamId id) override {
@@ -157,13 +157,13 @@
}
QuicStreamId GetNthClientInitiatedBidirectionalId(int n) {
- return QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId(
- *session_, n);
+ return GetNthClientInitiatedBidirectionalStreamId(
+ connection_->transport_version(), n);
}
QuicStreamId GetNthServerInitiatedUnidirectionalId(int n) {
- return QuicSpdySessionPeer::GetNthServerInitiatedUnidirectionalStreamId(
- *session_, n);
+ return quic::test::GetNthServerInitiatedUnidirectionalStreamId(
+ connection_->transport_version(), n);
}
QuicTransportVersion transport_version() const {
@@ -188,6 +188,7 @@
EXPECT_CALL(owner_, OnStopSendingReceived(_)).Times(1);
// Expect the RESET_STREAM that is generated in response to receiving a
// STOP_SENDING.
+ EXPECT_CALL(*connection_, SendControlFrame(_));
EXPECT_CALL(*connection_, OnStreamReset(stream_id, rst_stream_code));
session_->OnStopSendingFrame(stop_sending);
}
@@ -222,9 +223,8 @@
reference.previous_connection_state());
}
-INSTANTIATE_TEST_CASE_P(Tests,
- QuicServerSessionBaseTest,
- ::testing::ValuesIn(AllSupportedVersions()));
+INSTANTIATE_TEST_SUITE_P(Tests, QuicServerSessionBaseTest,
+ ::testing::ValuesIn(AllSupportedVersions()));
TEST_P(QuicServerSessionBaseTest, CloseStreamDueToReset) {
// Open a stream, then reset it.
// Send two bytes of payload to open it.
@@ -238,10 +238,14 @@
GetNthClientInitiatedBidirectionalId(0),
QUIC_ERROR_PROCESSING_STREAM, 0);
EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
- EXPECT_CALL(*connection_, SendControlFrame(_));
- EXPECT_CALL(*connection_,
- OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
- QUIC_RST_ACKNOWLEDGEMENT));
+ if (transport_version() != QUIC_VERSION_99) {
+ // For non-version 99, the RESET_STREAM will do the full close.
+ // Set up expects accordingly.
+ EXPECT_CALL(*connection_, SendControlFrame(_));
+ EXPECT_CALL(*connection_,
+ OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
+ QUIC_RST_ACKNOWLEDGEMENT));
+ }
visitor_->OnRstStream(rst1);
// For version-99 will create and receive a stop-sending, completing
@@ -265,10 +269,14 @@
GetNthClientInitiatedBidirectionalId(0),
QUIC_ERROR_PROCESSING_STREAM, 0);
EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
- EXPECT_CALL(*connection_, SendControlFrame(_));
- EXPECT_CALL(*connection_,
- OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
- QUIC_RST_ACKNOWLEDGEMENT));
+ if (transport_version() != QUIC_VERSION_99) {
+ // For non-version 99, the RESET_STREAM will do the full close.
+ // Set up expects accordingly.
+ EXPECT_CALL(*connection_, SendControlFrame(_));
+ EXPECT_CALL(*connection_,
+ OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
+ QUIC_RST_ACKNOWLEDGEMENT));
+ }
visitor_->OnRstStream(rst1);
// For version-99 will create and receive a stop-sending, completing
@@ -303,10 +311,14 @@
GetNthClientInitiatedBidirectionalId(0),
QUIC_ERROR_PROCESSING_STREAM, 0);
EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
- EXPECT_CALL(*connection_, SendControlFrame(_));
- EXPECT_CALL(*connection_,
- OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
- QUIC_RST_ACKNOWLEDGEMENT));
+ if (transport_version() != QUIC_VERSION_99) {
+ // For non-version 99, the RESET_STREAM will do the full close.
+ // Set up expects accordingly.
+ EXPECT_CALL(*connection_, SendControlFrame(_));
+ EXPECT_CALL(*connection_,
+ OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
+ QUIC_RST_ACKNOWLEDGEMENT));
+ }
visitor_->OnRstStream(rst);
// For version-99 will create and receive a stop-sending, completing
@@ -350,7 +362,7 @@
for (size_t i = 0; i < kMaxStreamsForTest; ++i) {
EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateDynamicStream(
session_.get(), stream_id));
- stream_id += QuicSpdySessionPeer::StreamIdDelta(*session_);
+ stream_id += QuicUtils::StreamIdDelta(connection_->transport_version());
}
if (transport_version() != QUIC_VERSION_99) {
@@ -359,11 +371,11 @@
for (size_t i = 0; i < kMaxStreamsMinimumIncrement; ++i) {
EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateDynamicStream(
session_.get(), stream_id));
- stream_id += QuicSpdySessionPeer::StreamIdDelta(*session_);
+ stream_id += QuicUtils::StreamIdDelta(connection_->transport_version());
}
}
// Now violate the server's internal stream limit.
- stream_id += QuicSpdySessionPeer::StreamIdDelta(*session_);
+ stream_id += QuicUtils::StreamIdDelta(connection_->transport_version());
if (transport_version() != QUIC_VERSION_99) {
// For non-version 99, QUIC responds to an attempt to exceed the stream
@@ -395,7 +407,8 @@
session_.get(), GetNthClientInitiatedBidirectionalId(0)));
// Establish available streams up to the server's limit.
- QuicStreamId next_id = QuicSpdySessionPeer::StreamIdDelta(*session_);
+ QuicStreamId next_id =
+ QuicUtils::StreamIdDelta(connection_->transport_version());
const int kLimitingStreamId =
GetNthClientInitiatedBidirectionalId(kAvailableStreamLimit + 1);
if (transport_version() != QUIC_VERSION_99) {
@@ -665,9 +678,8 @@
QuicCryptoServerConfigPeer crypto_config_peer_;
};
-INSTANTIATE_TEST_CASE_P(StreamMemberLifetimeTests,
- StreamMemberLifetimeTest,
- ::testing::ValuesIn(AllSupportedVersions()));
+INSTANTIATE_TEST_SUITE_P(StreamMemberLifetimeTests, StreamMemberLifetimeTest,
+ ::testing::ValuesIn(AllSupportedVersions()));
// Trigger an operation which causes an async invocation of
// ProofSource::GetProof. Delay the completion of the operation until after the
diff --git a/quic/core/http/quic_spdy_client_session_test.cc b/quic/core/http/quic_spdy_client_session_test.cc
index a9d6c62..84229fd 100644
--- a/quic/core/http/quic_spdy_client_session_test.cc
+++ b/quic/core/http/quic_spdy_client_session_test.cc
@@ -108,12 +108,10 @@
push_promise_[":method"] = "GET";
push_promise_[":scheme"] = "https";
promise_url_ = SpdyUtils::GetPromisedUrlFromHeaders(push_promise_);
- promised_stream_id_ =
- QuicSpdySessionPeer::GetNthServerInitiatedUnidirectionalStreamId(
- *session_, 0);
- associated_stream_id_ =
- QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId(
- *session_, 0);
+ promised_stream_id_ = GetNthServerInitiatedUnidirectionalStreamId(
+ connection_->transport_version(), 0);
+ associated_stream_id_ = GetNthClientInitiatedBidirectionalStreamId(
+ connection_->transport_version(), 0);
}
// The function ensures that A) the max stream id frames get properly deleted
@@ -172,9 +170,8 @@
QuicStreamId associated_stream_id_;
};
-INSTANTIATE_TEST_CASE_P(Tests,
- QuicSpdyClientSessionTest,
- ::testing::ValuesIn(AllSupportedVersions()));
+INSTANTIATE_TEST_SUITE_P(Tests, QuicSpdyClientSessionTest,
+ ::testing::ValuesIn(AllSupportedVersions()));
TEST_P(QuicSpdyClientSessionTest, CryptoConnect) {
CompleteCryptoHandshake();
@@ -281,9 +278,8 @@
// Note that this is to be the second stream created, but GetNth... starts
// numbering at 0 (the first stream is 0, second is 1...)
- QuicMaxStreamIdFrame frame(
- 0, QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId(
- *session_, 1));
+ QuicMaxStreamIdFrame frame(0, GetNthClientInitiatedBidirectionalStreamId(
+ connection_->transport_version(), 1));
session_->OnMaxStreamIdFrame(frame);
}
stream = session_->CreateOutgoingBidirectionalStream();
@@ -350,9 +346,8 @@
if (GetParam().transport_version == QUIC_VERSION_99) {
// Note that this is to be the second stream created, but GetNth... starts
// numbering at 0 (the first stream is 0, second is 1...)
- QuicMaxStreamIdFrame frame(
- 0, QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId(
- *session_, 1));
+ QuicMaxStreamIdFrame frame(0, GetNthClientInitiatedBidirectionalStreamId(
+ connection_->transport_version(), 1));
session_->OnMaxStreamIdFrame(frame);
}
stream = session_->CreateOutgoingBidirectionalStream();
@@ -454,7 +449,7 @@
QuicReceivedPacket valid_packet(buf, 2, QuicTime::Zero(), false);
// Close connection shouldn't be called.
EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
- if (connection_->transport_version() > QUIC_VERSION_46) {
+ if (connection_->transport_version() > QUIC_VERSION_44) {
// Illegal fixed bit value.
EXPECT_CALL(*connection_, OnError(_)).Times(1);
}
@@ -539,7 +534,8 @@
EXPECT_CALL(*stream, OnPromiseHeaderList(promised_stream_id_, _, _));
session_->OnPromiseHeaderList(associated_stream_id_, promised_stream_id_, 0,
QuicHeaderList());
- associated_stream_id_ += QuicSpdySessionPeer::StreamIdDelta(*session_);
+ associated_stream_id_ +=
+ QuicUtils::StreamIdDelta(connection_->transport_version());
EXPECT_CALL(*connection_,
CloseConnection(QUIC_INVALID_STREAM_ID,
"Received push stream id lesser or equal to the"
@@ -557,9 +553,8 @@
session_->CreateOutgoingBidirectionalStream());
// Promise an illegal (outgoing) stream id.
- promised_stream_id_ =
- QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId(*session_,
- 0);
+ promised_stream_id_ = GetNthClientInitiatedBidirectionalStreamId(
+ connection_->transport_version(), 0);
EXPECT_CALL(
*connection_,
CloseConnection(QUIC_INVALID_STREAM_ID,
@@ -615,7 +610,8 @@
EXPECT_NE(session_->GetPromisedById(promised_stream_id_), nullptr);
EXPECT_NE(session_->GetPromisedByUrl(promise_url_), nullptr);
- promised_stream_id_ += QuicSpdySessionPeer::StreamIdDelta(*session_);
+ promised_stream_id_ +=
+ QuicUtils::StreamIdDelta(connection_->transport_version());
EXPECT_CALL(*connection_, SendControlFrame(_));
EXPECT_CALL(*connection_,
OnStreamReset(promised_stream_id_, QUIC_DUPLICATE_PROMISE_URL));
@@ -632,7 +628,8 @@
push_promise_[":path"] = QuicStringPrintf("/bar%zu", i);
QuicStreamId id =
- promised_stream_id_ + i * QuicSpdySessionPeer::StreamIdDelta(*session_);
+ promised_stream_id_ +
+ i * QuicUtils::StreamIdDelta(connection_->transport_version());
EXPECT_TRUE(
session_->HandlePromised(associated_stream_id_, id, push_promise_));
@@ -648,7 +645,8 @@
push_promise_[":path"] = QuicStringPrintf("/bar%d", i);
QuicStreamId id =
- promised_stream_id_ + i * QuicSpdySessionPeer::StreamIdDelta(*session_);
+ promised_stream_id_ +
+ i * QuicUtils::StreamIdDelta(connection_->transport_version());
EXPECT_CALL(*connection_, SendControlFrame(_));
EXPECT_CALL(*connection_, OnStreamReset(id, QUIC_REFUSED_STREAM));
EXPECT_FALSE(
@@ -780,9 +778,8 @@
} else {
EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
}
- session_->GetOrCreateStream(
- QuicSpdySessionPeer::GetNthServerInitiatedBidirectionalStreamId(*session_,
- 0));
+ session_->GetOrCreateStream(GetNthServerInitiatedBidirectionalStreamId(
+ connection_->transport_version(), 0));
}
} // namespace
diff --git a/quic/core/http/quic_spdy_client_stream.cc b/quic/core/http/quic_spdy_client_stream.cc
index 21a09d6..d4e8a69 100644
--- a/quic/core/http/quic_spdy_client_stream.cc
+++ b/quic/core/http/quic_spdy_client_stream.cc
@@ -151,7 +151,7 @@
bytes_sent += header_bytes_written_;
if (!body.empty()) {
- WriteOrBufferBody(body, fin, nullptr);
+ WriteOrBufferBody(body, fin);
}
return bytes_sent;
diff --git a/quic/core/http/quic_spdy_client_stream_test.cc b/quic/core/http/quic_spdy_client_stream_test.cc
index ded2d7d..059558b 100644
--- a/quic/core/http/quic_spdy_client_stream_test.cc
+++ b/quic/core/http/quic_spdy_client_stream_test.cc
@@ -75,8 +75,8 @@
headers_["content-length"] = "11";
stream_ = QuicMakeUnique<QuicSpdyClientStream>(
- QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId(
- session_, 0),
+ GetNthClientInitiatedBidirectionalStreamId(
+ connection_->transport_version(), 0),
&session_, BIDIRECTIONAL);
stream_visitor_ = QuicMakeUnique<StreamVisitor>();
stream_->set_visitor(stream_visitor_.get());
@@ -101,9 +101,8 @@
HttpEncoder encoder_;
};
-INSTANTIATE_TEST_CASE_P(Tests,
- QuicSpdyClientStreamTest,
- ::testing::ValuesIn(AllSupportedVersions()));
+INSTANTIATE_TEST_SUITE_P(Tests, QuicSpdyClientStreamTest,
+ ::testing::ValuesIn(AllSupportedVersions()));
TEST_P(QuicSpdyClientStreamTest, TestReceivingIllegalResponseStatusCode) {
headers_[":status"] = "200 ok";
@@ -125,7 +124,7 @@
QuicByteCount header_length =
encoder_.SerializeDataFrameHeader(body_.length(), &buffer);
QuicString header = QuicString(buffer.get(), header_length);
- QuicString data = connection_->transport_version() == QUIC_VERSION_99
+ QuicString data = VersionHasDataFrameHeader(connection_->transport_version())
? header + body_
: body_;
stream_->OnStreamFrame(
@@ -156,7 +155,7 @@
QuicByteCount header_length =
encoder_.SerializeDataFrameHeader(body_.length(), &buffer);
QuicString header = QuicString(buffer.get(), header_length);
- QuicString data = connection_->transport_version() == QUIC_VERSION_99
+ QuicString data = VersionHasDataFrameHeader(connection_->transport_version())
? header + body_
: body_;
stream_->OnStreamFrame(
@@ -180,7 +179,7 @@
QuicByteCount header_length =
encoder_.SerializeDataFrameHeader(large_body.length(), &buffer);
QuicString header = QuicString(buffer.get(), header_length);
- QuicString data = connection_->transport_version() == QUIC_VERSION_99
+ QuicString data = VersionHasDataFrameHeader(connection_->transport_version())
? header + large_body
: large_body;
EXPECT_CALL(*connection_, SendControlFrame(_));
@@ -219,7 +218,7 @@
QuicByteCount header_length =
encoder_.SerializeDataFrameHeader(body_.length(), &buffer);
QuicString header = QuicString(buffer.get(), header_length);
- QuicString data = connection_->transport_version() == QUIC_VERSION_99
+ QuicString data = VersionHasDataFrameHeader(connection_->transport_version())
? header + body_
: body_;
stream_->OnStreamFrame(
diff --git a/quic/core/http/quic_spdy_server_stream_base_test.cc b/quic/core/http/quic_spdy_server_stream_base_test.cc
index 51abf0c..4e1aa1b 100644
--- a/quic/core/http/quic_spdy_server_stream_base_test.cc
+++ b/quic/core/http/quic_spdy_server_stream_base_test.cc
@@ -32,8 +32,8 @@
&alarm_factory_,
Perspective::IS_SERVER)) {
stream_ = new TestQuicSpdyServerStream(
- QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId(
- session_, 0),
+ GetNthClientInitiatedBidirectionalStreamId(
+ session_.connection()->transport_version(), 0),
&session_, BIDIRECTIONAL);
session_.ActivateStream(QuicWrapUnique(stream_));
helper_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
@@ -58,7 +58,21 @@
EXPECT_FALSE(stream_->reading_stopped());
EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0);
- EXPECT_CALL(session_, SendRstStream(_, QUIC_RST_ACKNOWLEDGEMENT, _)).Times(1);
+
+ if (session_.connection()->transport_version() != QUIC_VERSION_99) {
+ EXPECT_CALL(session_, SendRstStream(_, QUIC_RST_ACKNOWLEDGEMENT, _))
+ .Times(1);
+ } else {
+ // Intercept & check that the call to the QuicConnection's OnStreamReast
+ // has correct stream ID and error code -- for V99/IETF Quic, it should
+ // have the STREAM_CANCELLED error code, not RST_ACK... Capture
+ // OnStreamReset (rather than SendRstStream) because the V99 path bypasses
+ // SendRstStream, calling SendRstStreamInner directly. Mocking
+ // SendRstStreamInner is problematic since the test relies on it to perform
+ // the closing operations and getting the stream in the correct state.
+ EXPECT_CALL(*(static_cast<MockQuicConnection*>(session_.connection())),
+ OnStreamReset(stream_->id(), QUIC_STREAM_CANCELLED));
+ }
QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream_->id(),
QUIC_STREAM_CANCELLED, 1234);
stream_->OnStreamReset(rst_frame);
diff --git a/quic/core/http/quic_spdy_session.cc b/quic/core/http/quic_spdy_session.cc
index bc3cf5c..824ecfa 100644
--- a/quic/core/http/quic_spdy_session.cc
+++ b/quic/core/http/quic_spdy_session.cc
@@ -347,6 +347,11 @@
QuicUtils::GetHeadersStreamId(connection()->transport_version()));
}
+ if (VersionUsesQpack(connection()->transport_version())) {
+ qpack_encoder_ = QuicMakeUnique<QpackEncoder>(this, this);
+ qpack_decoder_ = QuicMakeUnique<QpackDecoder>(this, this);
+ }
+
headers_stream_ = QuicMakeUnique<QuicHeadersStream>((this));
DCHECK_EQ(QuicUtils::GetHeadersStreamId(connection()->transport_version()),
headers_stream_->id());
@@ -360,6 +365,34 @@
set_max_decode_buffer_size_bytes(2 * max_inbound_header_list_size_);
}
+void QuicSpdySession::OnDecoderStreamError(QuicStringPiece error_message) {
+ DCHECK(VersionUsesQpack(connection()->transport_version()));
+
+ // TODO(112770235): Signal connection error on decoder stream errors.
+ QUIC_NOTREACHED();
+}
+
+void QuicSpdySession::WriteEncoderStreamData(QuicStringPiece data) {
+ DCHECK(VersionUsesQpack(connection()->transport_version()));
+
+ // TODO(112770235): Send encoder stream data on encoder stream.
+ QUIC_NOTREACHED();
+}
+
+void QuicSpdySession::OnEncoderStreamError(QuicStringPiece error_message) {
+ DCHECK(VersionUsesQpack(connection()->transport_version()));
+
+ // TODO(112770235): Signal connection error on encoder stream errors.
+ QUIC_NOTREACHED();
+}
+
+void QuicSpdySession::WriteDecoderStreamData(QuicStringPiece data) {
+ DCHECK(VersionUsesQpack(connection()->transport_version()));
+
+ // TODO(112770235): Send decoder stream data on decoder stream.
+ QUIC_NOTREACHED();
+}
+
void QuicSpdySession::OnStreamHeadersPriority(QuicStreamId stream_id,
SpdyPriority priority) {
QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
@@ -424,38 +457,16 @@
iov.iov_len);
}
-size_t QuicSpdySession::WriteHeaders(
+size_t QuicSpdySession::WriteHeadersOnHeadersStream(
QuicStreamId id,
SpdyHeaderBlock headers,
bool fin,
SpdyPriority priority,
QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
- return WriteHeadersImpl(
- id, std::move(headers), fin, Spdy3PriorityToHttp2Weight(priority),
- /*parent_stream_id=*/0, /*exclusive=*/false, std::move(ack_listener));
-}
-
-size_t QuicSpdySession::WriteHeadersImpl(
- QuicStreamId id,
- SpdyHeaderBlock headers,
- bool fin,
- int weight,
- QuicStreamId parent_stream_id,
- bool exclusive,
- QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
- SpdyHeadersIR headers_frame(id, std::move(headers));
- headers_frame.set_fin(fin);
- if (perspective() == Perspective::IS_CLIENT) {
- headers_frame.set_has_priority(true);
- headers_frame.set_weight(weight);
- headers_frame.set_parent_stream_id(parent_stream_id);
- headers_frame.set_exclusive(exclusive);
- }
- SpdySerializedFrame frame(spdy_framer_.SerializeFrame(headers_frame));
- headers_stream_->WriteOrBufferData(
- QuicStringPiece(frame.data(), frame.size()), false,
- std::move(ack_listener));
- return frame.size();
+ return WriteHeadersOnHeadersStreamImpl(
+ id, std::move(headers), fin,
+ /* parent_stream_id = */ 0, Spdy3PriorityToHttp2Weight(priority),
+ /* exclusive = */ false, std::move(ack_listener));
}
size_t QuicSpdySession::WritePriority(QuicStreamId id,
@@ -502,6 +513,18 @@
return frame.size();
}
+QpackEncoder* QuicSpdySession::qpack_encoder() {
+ DCHECK(VersionUsesQpack(connection()->transport_version()));
+
+ return qpack_encoder_.get();
+}
+
+QpackDecoder* QuicSpdySession::qpack_decoder() {
+ DCHECK(VersionUsesQpack(connection()->transport_version()));
+
+ return qpack_decoder_.get();
+}
+
QuicSpdyStream* QuicSpdySession::GetSpdyDataStream(
const QuicStreamId stream_id) {
return static_cast<QuicSpdyStream*>(GetOrCreateDynamicStream(stream_id));
@@ -519,6 +542,29 @@
return !QuicUtils::IsBidirectionalStreamId(id);
}
+size_t QuicSpdySession::WriteHeadersOnHeadersStreamImpl(
+ QuicStreamId id,
+ spdy::SpdyHeaderBlock headers,
+ bool fin,
+ QuicStreamId parent_stream_id,
+ int weight,
+ bool exclusive,
+ QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
+ SpdyHeadersIR headers_frame(id, std::move(headers));
+ headers_frame.set_fin(fin);
+ if (perspective() == Perspective::IS_CLIENT) {
+ headers_frame.set_has_priority(true);
+ headers_frame.set_parent_stream_id(parent_stream_id);
+ headers_frame.set_weight(weight);
+ headers_frame.set_exclusive(exclusive);
+ }
+ SpdySerializedFrame frame(spdy_framer_.SerializeFrame(headers_frame));
+ headers_stream_->WriteOrBufferData(
+ QuicStringPiece(frame.data(), frame.size()), false,
+ std::move(ack_listener));
+ return frame.size();
+}
+
void QuicSpdySession::OnPromiseHeaderList(QuicStreamId stream_id,
QuicStreamId promised_stream_id,
size_t frame_len,
diff --git a/quic/core/http/quic_spdy_session.h b/quic/core/http/quic_spdy_session.h
index 2874e26..363edf3 100644
--- a/quic/core/http/quic_spdy_session.h
+++ b/quic/core/http/quic_spdy_session.h
@@ -12,7 +12,12 @@
#include "net/third_party/quiche/src/quic/core/http/quic_header_list.h"
#include "net/third_party/quiche/src/quic/core/http/quic_headers_stream.h"
#include "net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h"
#include "net/third_party/quiche/src/quic/core/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"
#include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
@@ -44,7 +49,12 @@
};
// A QUIC session with a headers stream.
-class QUIC_EXPORT_PRIVATE QuicSpdySession : public QuicSession {
+class QUIC_EXPORT_PRIVATE QuicSpdySession
+ : public QuicSession,
+ public QpackEncoder::DecoderStreamErrorDelegate,
+ public QpackEncoderStreamSender::Delegate,
+ public QpackDecoder::EncoderStreamErrorDelegate,
+ public QpackDecoderStreamSender::Delegate {
public:
// Does not take ownership of |connection| or |visitor|.
QuicSpdySession(QuicConnection* connection,
@@ -58,6 +68,18 @@
void Initialize() override;
+ // QpackEncoder::DecoderStreamErrorDelegate implementation.
+ void OnDecoderStreamError(QuicStringPiece error_message) override;
+
+ // QpackEncoderStreamSender::Delegate implemenation.
+ void WriteEncoderStreamData(QuicStringPiece data) override;
+
+ // QpackDecoder::EncoderStreamErrorDelegate implementation.
+ void OnEncoderStreamError(QuicStringPiece error_message) override;
+
+ // QpackDecoderStreamSender::Delegate implementation.
+ void WriteDecoderStreamData(QuicStringPiece data) override;
+
// Called by |headers_stream_| when headers with a priority have been
// received for a stream. This method will only be called for server streams.
virtual void OnStreamHeadersPriority(QuicStreamId stream_id,
@@ -79,7 +101,7 @@
size_t frame_len,
const QuicHeaderList& header_list);
- // Callbed by |headers_stream_| when a PRIORITY frame has been received for a
+ // Called by |headers_stream_| when a PRIORITY frame has been received for a
// stream. This method will only be called for server streams.
virtual void OnPriorityFrame(QuicStreamId stream_id,
spdy::SpdyPriority priority);
@@ -91,7 +113,7 @@
// If |fin| is true, then no more data will be sent for the stream |id|.
// If provided, |ack_notifier_delegate| will be registered to be notified when
// we have seen ACKs for all packets resulting from this call.
- virtual size_t WriteHeaders(
+ virtual size_t WriteHeadersOnHeadersStream(
QuicStreamId id,
spdy::SpdyHeaderBlock headers,
bool fin,
@@ -116,6 +138,8 @@
// Sends SETTINGS_MAX_HEADER_LIST_SIZE SETTINGS frame.
size_t SendMaxHeaderListSize(size_t value);
+ QpackEncoder* qpack_encoder();
+ QpackDecoder* qpack_decoder();
QuicHeadersStream* headers_stream() { return headers_stream_.get(); }
bool server_push_enabled() const { return server_push_enabled_; }
@@ -157,15 +181,12 @@
// Overridden to buffer incoming streams for version 99.
bool ShouldBufferIncomingStream(QuicStreamId id) const override;
- // This was formerly QuicHeadersStream::WriteHeaders. Needs to be
- // separate from QuicSpdySession::WriteHeaders because tests call
- // this but mock the latter.
- size_t WriteHeadersImpl(
+ size_t WriteHeadersOnHeadersStreamImpl(
QuicStreamId id,
spdy::SpdyHeaderBlock headers,
bool fin,
- int weight,
QuicStreamId parent_stream_id,
+ int weight,
bool exclusive,
QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
@@ -226,6 +247,10 @@
// Called when the size of the compressed frame payload is available.
void OnCompressedFrameSize(size_t frame_len);
+ std::unique_ptr<QpackEncoder> qpack_encoder_;
+ std::unique_ptr<QpackDecoder> qpack_decoder_;
+
+ // TODO(123528590): Remove this member.
std::unique_ptr<QuicHeadersStream> headers_stream_;
// The maximum size of a header block that will be accepted from the peer,
diff --git a/quic/core/http/quic_spdy_session_test.cc b/quic/core/http/quic_spdy_session_test.cc
index affa07a..d9c4ab1 100644
--- a/quic/core/http/quic_spdy_session_test.cc
+++ b/quic/core/http/quic_spdy_session_test.cc
@@ -98,6 +98,8 @@
MOCK_METHOD0(OnCanWrite, void());
+ bool HasPendingCryptoRetransmission() override { return false; }
+
MOCK_CONST_METHOD0(HasPendingRetransmission, bool());
private:
@@ -187,7 +189,8 @@
TestStream* stream = new TestStream(
id, this,
DetermineStreamType(id, connection()->transport_version(),
- /*is_incoming=*/true, BIDIRECTIONAL));
+ perspective(), /*is_incoming=*/true,
+ BIDIRECTIONAL));
ActivateStream(QuicWrapUnique(stream));
return stream;
}
@@ -195,10 +198,11 @@
TestStream* CreateIncomingStream(PendingStream pending) override {
QuicStreamId id = pending.id();
- TestStream* stream = new TestStream(
- std::move(pending), this,
- DetermineStreamType(id, connection()->transport_version(),
- /*is_incoming=*/true, BIDIRECTIONAL));
+ TestStream* stream =
+ new TestStream(std::move(pending), this,
+ DetermineStreamType(
+ id, connection()->transport_version(), perspective(),
+ /*is_incoming=*/true, BIDIRECTIONAL));
ActivateStream(QuicWrapUnique(stream));
return stream;
}
@@ -342,7 +346,7 @@
}
void CloseStream(QuicStreamId id) {
- if (transport_version() != QUIC_VERSION_99) {
+ if (!IsVersion99()) {
EXPECT_CALL(*connection_, SendControlFrame(_))
.WillOnce(Invoke(&session_, &TestSession::ClearControlFrame));
} else {
@@ -360,18 +364,19 @@
return connection_->transport_version();
}
+ bool IsVersion99() const { return transport_version() == QUIC_VERSION_99; }
+
QuicStreamId GetNthClientInitiatedBidirectionalId(int n) {
- return QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId(
- session_, n);
+ return GetNthClientInitiatedBidirectionalStreamId(transport_version(), n);
}
QuicStreamId GetNthServerInitiatedBidirectionalId(int n) {
- return QuicSpdySessionPeer::GetNthServerInitiatedBidirectionalStreamId(
- session_, n);
+ return GetNthServerInitiatedBidirectionalStreamId(
+ connection_->transport_version(), n);
}
QuicStreamId IdDelta() {
- return QuicSpdySessionPeer::StreamIdDelta(session_);
+ return QuicUtils::StreamIdDelta(connection_->transport_version());
}
MockQuicConnectionHelper helper_;
@@ -388,12 +393,12 @@
: QuicSpdySessionTestBase(Perspective::IS_SERVER) {}
};
-INSTANTIATE_TEST_CASE_P(Tests,
- QuicSpdySessionTestServer,
- ::testing::ValuesIn(AllSupportedVersions()));
+INSTANTIATE_TEST_SUITE_P(Tests,
+ QuicSpdySessionTestServer,
+ ::testing::ValuesIn(AllSupportedVersions()));
TEST_P(QuicSpdySessionTestServer, ShouldBufferIncomingStreamUnidirectional) {
- if (connection_->transport_version() != QUIC_VERSION_99) {
+ if (!IsVersion99()) {
return;
}
EXPECT_TRUE(session_.ShouldBufferIncomingStream(
@@ -402,7 +407,7 @@
}
TEST_P(QuicSpdySessionTestServer, ShouldBufferIncomingStreamBidirectional) {
- if (connection_->transport_version() != QUIC_VERSION_99) {
+ if (!IsVersion99()) {
return;
}
EXPECT_FALSE(session_.ShouldBufferIncomingStream(
@@ -416,7 +421,7 @@
}
TEST_P(QuicSpdySessionTestServer, SelfAddress) {
- EXPECT_EQ(QuicSocketAddress(), session_.self_address());
+ EXPECT_TRUE(session_.self_address().IsInitialized());
}
TEST_P(QuicSpdySessionTestServer, IsCryptoHandshakeConfirmed) {
@@ -481,7 +486,7 @@
}
TEST_P(QuicSpdySessionTestServer, MaximumAvailableOpenedStreams) {
- if (transport_version() == QUIC_VERSION_99) {
+ if (IsVersion99()) {
// For IETF QUIC, we should be able to obtain the max allowed
// stream ID, the next ID should fail. Since the actual limit
// is not the number of open streams, we allocate the max and the max+2.
@@ -532,7 +537,7 @@
// A stream ID which is too large to create.
stream_id2 = GetNthClientInitiatedBidirectionalId(
2 * session_.MaxAvailableBidirectionalStreams() + 4);
- if (transport_version() == QUIC_VERSION_99) {
+ if (IsVersion99()) {
EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, _, _));
} else {
EXPECT_CALL(*connection_,
@@ -670,7 +675,7 @@
}
TEST_P(QuicSpdySessionTestServer, OnCanWriteBundlesStreams) {
- if (transport_version() == QUIC_VERSION_99) {
+ if (IsVersion99()) {
EXPECT_CALL(*connection_, SendControlFrame(_))
.WillRepeatedly(Invoke(
this, &QuicSpdySessionTestServer::ClearMaxStreamIdControlFrame));
@@ -776,8 +781,6 @@
MockPacketWriter* writer = static_cast<MockPacketWriter*>(
QuicConnectionPeer::GetWriter(session_.connection()));
EXPECT_CALL(*writer, IsWriteBlocked()).WillRepeatedly(Return(true));
- EXPECT_CALL(*writer, IsWriteBlockedDataBuffered())
- .WillRepeatedly(Return(true));
EXPECT_CALL(*writer, WritePacket(_, _, _, _, _)).Times(0);
TestStream* stream2 = session_.CreateOutgoingBidirectionalStream();
@@ -908,7 +911,7 @@
}
TEST_P(QuicSpdySessionTestServer, SendGoAway) {
- if (transport_version() == QUIC_VERSION_99) {
+ if (IsVersion99()) {
// GoAway frames are not in version 99
return;
}
@@ -932,7 +935,7 @@
}
TEST_P(QuicSpdySessionTestServer, DoNotSendGoAwayTwice) {
- if (connection_->transport_version() == QUIC_VERSION_99) {
+ if (IsVersion99()) {
// TODO(b/118808809): Enable this test for version 99 when GOAWAY is
// supported.
return;
@@ -945,7 +948,7 @@
}
TEST_P(QuicSpdySessionTestServer, InvalidGoAway) {
- if (connection_->transport_version() == QUIC_VERSION_99) {
+ if (IsVersion99()) {
// TODO(b/118808809): Enable this test for version 99 when GOAWAY is
// supported.
return;
@@ -967,7 +970,7 @@
EXPECT_CALL(*connection_,
SendConnectivityProbingResponsePacket(new_peer_address));
- if (transport_version() == QUIC_VERSION_99) {
+ if (IsVersion99()) {
// Need to explicitly do this to emulate the reception of a PathChallenge,
// which stores its payload for use in generating the response.
connection_->OnPathChallengeFrame(
@@ -995,8 +998,12 @@
EXPECT_EQ(1u, session_.GetNumOpenIncomingStreams());
EXPECT_CALL(*connection_, SendControlFrame(_));
- EXPECT_CALL(*connection_,
- OnStreamReset(GetNthClientInitiatedBidirectionalId(0), _));
+ if (!IsVersion99()) {
+ // For version99, OnStreamReset gets called because of the STOP_SENDING,
+ // below. EXPECT the call there.
+ EXPECT_CALL(*connection_,
+ OnStreamReset(GetNthClientInitiatedBidirectionalId(0), _));
+ }
QuicRstStreamFrame rst1(kInvalidControlFrameId,
GetNthClientInitiatedBidirectionalId(0),
QUIC_ERROR_PROCESSING_STREAM, 0);
@@ -1005,7 +1012,7 @@
// Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
// RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes a
// one-way close.
- if (transport_version() == QUIC_VERSION_99) {
+ if (IsVersion99()) {
// Only needed for version 99/IETF QUIC.
QuicStopSendingFrame stop_sending(
kInvalidControlFrameId, GetNthClientInitiatedBidirectionalId(0),
@@ -1088,7 +1095,7 @@
EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
EXPECT_CALL(*connection_, SendControlFrame(_)).Times(AtLeast(1));
- stream2->WriteOrBufferBody(body, false, nullptr);
+ stream2->WriteOrBufferBody(body, false);
EXPECT_TRUE(stream2->flow_controller()->IsBlocked());
EXPECT_TRUE(session_.IsConnectionFlowControlBlocked());
EXPECT_TRUE(session_.IsStreamFlowControlBlocked());
@@ -1106,6 +1113,11 @@
TEST_P(QuicSpdySessionTestServer,
HandshakeUnblocksFlowControlBlockedCryptoStream) {
+ if (GetParam().transport_version >= QUIC_VERSION_47) {
+ // QUIC version 47 onwards uses CRYPTO frames for the handshake, so this
+ // test doesn't make sense for those versions.
+ return;
+ }
// Test that if the crypto stream is flow control blocked, then if the SHLO
// contains a larger send window offset, the stream becomes unblocked.
session_.set_writev_consumes_all_data(true);
@@ -1118,10 +1130,9 @@
EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked());
EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
- if (transport_version() == QUIC_VERSION_99) {
+ if (IsVersion99()) {
EXPECT_CALL(*connection_, SendControlFrame(_))
- .Times(1)
- .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame));
+ .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame));
} else {
EXPECT_CALL(*connection_, SendControlFrame(_))
.WillOnce(Invoke(&session_, &TestSession::ClearControlFrame));
@@ -1190,12 +1201,14 @@
EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
headers["header"] = QuicStrCat(random.RandUint64(), random.RandUint64(),
random.RandUint64());
- session_.WriteHeaders(stream_id, headers.Clone(), true, 0, nullptr);
+ session_.WriteHeadersOnHeadersStream(stream_id, headers.Clone(), true, 0,
+ nullptr);
stream_id += IdDelta();
}
// Write once more to ensure that the headers stream has buffered data. The
// random headers may have exactly filled the flow control window.
- session_.WriteHeaders(stream_id, std::move(headers), true, 0, nullptr);
+ session_.WriteHeadersOnHeadersStream(stream_id, std::move(headers), true, 0,
+ nullptr);
EXPECT_TRUE(headers_stream->HasBufferedData());
EXPECT_TRUE(headers_stream->flow_controller()->IsBlocked());
@@ -1231,25 +1244,21 @@
const QuicStreamOffset kByteOffset =
1 + kInitialSessionFlowControlWindowForTest / 2;
- if (transport_version() != QUIC_VERSION_99) {
- EXPECT_CALL(*connection_, SendControlFrame(_))
- .Times(2)
- .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame));
- } else {
- // V99 has an additional, STOP_SENDING, frame and an additional RST_STREAM
- // (the response to the STOP_SENDING) frame.
- EXPECT_CALL(*connection_, SendControlFrame(_))
- .Times(4)
- .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame));
+ EXPECT_CALL(*connection_, SendControlFrame(_))
+ .Times(2)
+ .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame));
+ if (!IsVersion99()) {
+ // For version99 the call to OnStreamReset happens as a result of receiving
+ // the STOP_SENDING, so set up the EXPECT there.
+ EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _));
}
- EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _));
QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream->id(),
QUIC_STREAM_CANCELLED, kByteOffset);
session_.OnRstStream(rst_frame);
// Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
// RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes a
// one-way close.
- if (transport_version() == QUIC_VERSION_99) {
+ if (IsVersion99()) {
// Only needed for version 99/IETF QUIC.
QuicStopSendingFrame stop_sending(
kInvalidControlFrameId, stream->id(),
@@ -1457,12 +1466,13 @@
GetNthClientInitiatedBidirectionalId(kMaxStreams);
// Create kMaxStreams data streams, and close them all without receiving a
// FIN or a RST_STREAM from the client.
- const QuicStreamId kNextId = QuicSpdySessionPeer::StreamIdDelta(session_);
+ const QuicStreamId kNextId =
+ QuicUtils::StreamIdDelta(connection_->transport_version());
for (QuicStreamId i = kFirstStreamId; i < kFinalStreamId; i += kNextId) {
QuicStreamFrame data1(i, false, 0, QuicStringPiece("HT"));
session_.OnStreamFrame(data1);
// EXPECT_EQ(1u, session_.GetNumOpenStreams());
- if (transport_version() != QUIC_VERSION_99) {
+ if (!IsVersion99()) {
EXPECT_CALL(*connection_, SendControlFrame(_))
.WillOnce(Invoke(&session_, &TestSession::ClearControlFrame));
} else {
@@ -1478,7 +1488,7 @@
session_.CloseStream(i);
}
// Try and open a stream that exceeds the limit.
- if (transport_version() != QUIC_VERSION_99) {
+ if (!IsVersion99()) {
// On versions other than 99, opening such a stream results in a
// RST_STREAM.
EXPECT_CALL(*connection_, SendControlFrame(_)).Times(1);
@@ -1499,7 +1509,7 @@
// Verify that a draining stream (which has received a FIN but not consumed
// it) does not count against the open quota (because it is closed from the
// protocol point of view).
- if (transport_version() == QUIC_VERSION_99) {
+ if (IsVersion99()) {
// Version 99 will result in a MAX_STREAM_ID frame as streams are consumed
// (via the OnStreamFrame call) and then released (via
// StreamDraining). Eventually this node will believe that the peer is
@@ -1532,9 +1542,9 @@
: QuicSpdySessionTestBase(Perspective::IS_CLIENT) {}
};
-INSTANTIATE_TEST_CASE_P(Tests,
- QuicSpdySessionTestClient,
- ::testing::ValuesIn(AllSupportedVersions()));
+INSTANTIATE_TEST_SUITE_P(Tests,
+ QuicSpdySessionTestClient,
+ ::testing::ValuesIn(AllSupportedVersions()));
TEST_P(QuicSpdySessionTestClient, AvailableStreamsClient) {
ASSERT_TRUE(session_.GetOrCreateDynamicStream(
@@ -1658,11 +1668,18 @@
// Lost data on cryption stream, streams 2 and 4.
EXPECT_CALL(*stream4, HasPendingRetransmission()).WillOnce(Return(true));
- EXPECT_CALL(*crypto_stream, HasPendingRetransmission())
- .WillOnce(Return(true));
+ if (connection_->transport_version() < QUIC_VERSION_47) {
+ EXPECT_CALL(*crypto_stream, HasPendingRetransmission())
+ .WillOnce(Return(true));
+ }
EXPECT_CALL(*stream2, HasPendingRetransmission()).WillOnce(Return(true));
session_.OnFrameLost(QuicFrame(frame3));
- session_.OnFrameLost(QuicFrame(frame1));
+ if (connection_->transport_version() < QUIC_VERSION_47) {
+ session_.OnFrameLost(QuicFrame(frame1));
+ } else {
+ QuicCryptoFrame crypto_frame(ENCRYPTION_NONE, 0, 1300);
+ session_.OnFrameLost(QuicFrame(&crypto_frame));
+ }
session_.OnFrameLost(QuicFrame(frame2));
EXPECT_TRUE(session_.WillingAndAbleToWrite());
@@ -1674,9 +1691,11 @@
// stream go first.
// Do not check congestion window when crypto stream has lost data.
EXPECT_CALL(*send_algorithm, CanSend(_)).Times(0);
- EXPECT_CALL(*crypto_stream, OnCanWrite());
- EXPECT_CALL(*crypto_stream, HasPendingRetransmission())
- .WillOnce(Return(false));
+ if (connection_->transport_version() < QUIC_VERSION_47) {
+ EXPECT_CALL(*crypto_stream, OnCanWrite());
+ EXPECT_CALL(*crypto_stream, HasPendingRetransmission())
+ .WillOnce(Return(false));
+ }
// Check congestion window for non crypto streams.
EXPECT_CALL(*send_algorithm, CanSend(_)).WillOnce(Return(true));
EXPECT_CALL(*stream4, OnCanWrite());
diff --git a/quic/core/http/quic_spdy_stream.cc b/quic/core/http/quic_spdy_stream.cc
index eb8135a..9e9f1b7 100644
--- a/quic/core/http/quic_spdy_stream.cc
+++ b/quic/core/http/quic_spdy_stream.cc
@@ -81,7 +81,9 @@
CloseConnectionOnWrongFrame("Headers");
}
- void OnHeadersFrameEnd() override { CloseConnectionOnWrongFrame("Headers"); }
+ void OnHeadersFrameEnd(QuicByteCount frame_len) override {
+ CloseConnectionOnWrongFrame("Headers");
+ }
void OnPushPromiseFrameStart(PushId push_id) override {
CloseConnectionOnWrongFrame("Push Promise");
@@ -121,7 +123,7 @@
trailers_consumed_(false),
http_decoder_visitor_(new HttpDecoderVisitor(this)),
body_buffer_(sequencer()),
- total_header_bytes_written_(0) {
+ ack_listener_(nullptr) {
DCHECK_NE(QuicUtils::GetCryptoStreamId(
spdy_session->connection()->transport_version()),
id);
@@ -129,7 +131,8 @@
// are complete.
sequencer()->SetBlockedUntilFlush();
- if (spdy_session_->connection()->transport_version() == QUIC_VERSION_99) {
+ if (VersionHasDataFrameHeader(
+ spdy_session_->connection()->transport_version())) {
sequencer()->set_level_triggered(true);
}
decoder_.set_visitor(http_decoder_visitor_.get());
@@ -146,7 +149,7 @@
trailers_consumed_(false),
http_decoder_visitor_(new HttpDecoderVisitor(this)),
body_buffer_(sequencer()),
- total_header_bytes_written_(0) {
+ ack_listener_(nullptr) {
DCHECK_NE(QuicUtils::GetCryptoStreamId(
spdy_session->connection()->transport_version()),
id());
@@ -154,7 +157,8 @@
// are complete.
sequencer()->SetBlockedUntilFlush();
- if (spdy_session_->connection()->transport_version() == QUIC_VERSION_99) {
+ if (VersionHasDataFrameHeader(
+ spdy_session_->connection()->transport_version())) {
sequencer()->set_level_triggered(true);
}
decoder_.set_visitor(http_decoder_visitor_.get());
@@ -166,8 +170,8 @@
SpdyHeaderBlock header_block,
bool fin,
QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
- size_t bytes_written = spdy_session_->WriteHeaders(
- id(), std::move(header_block), fin, priority(), std::move(ack_listener));
+ size_t bytes_written =
+ WriteHeadersImpl(std::move(header_block), fin, std::move(ack_listener));
if (fin) {
// TODO(rch): Add test to ensure fin_sent_ is set whenever a fin is sent.
set_fin_sent(true);
@@ -176,28 +180,32 @@
return bytes_written;
}
-void QuicSpdyStream::WriteOrBufferBody(
- QuicStringPiece data,
- bool fin,
- QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
- if (spdy_session_->connection()->transport_version() != QUIC_VERSION_99 ||
+void QuicSpdyStream::WriteOrBufferBody(QuicStringPiece data, bool fin) {
+ if (!VersionHasDataFrameHeader(
+ spdy_session_->connection()->transport_version()) ||
data.length() == 0) {
- WriteOrBufferData(data, fin, std::move(ack_listener));
+ WriteOrBufferData(data, fin, nullptr);
return;
}
QuicConnection::ScopedPacketFlusher flusher(
spdy_session_->connection(), QuicConnection::SEND_ACK_IF_PENDING);
+
+ // Write frame header.
std::unique_ptr<char[]> buffer;
QuicByteCount header_length =
encoder_.SerializeDataFrameHeader(data.length(), &buffer);
- WriteOrBufferData(QuicStringPiece(buffer.get(), header_length), false,
- nullptr);
+ unacked_frame_headers_offsets_.Add(
+ send_buffer().stream_offset(),
+ send_buffer().stream_offset() + header_length);
QUIC_DLOG(INFO) << "Stream " << id() << " is writing header of length "
<< header_length;
- total_header_bytes_written_ += header_length;
- WriteOrBufferData(data, fin, std::move(ack_listener));
+ WriteOrBufferData(QuicStringPiece(buffer.get(), header_length), false,
+ nullptr);
+
+ // Write body.
QUIC_DLOG(INFO) << "Stream " << id() << " is writing body of length "
<< data.length();
+ WriteOrBufferData(data, fin, nullptr);
}
size_t QuicSpdyStream::WriteTrailers(
@@ -221,8 +229,7 @@
// trailers are the last thing to be sent on a stream.
const bool kFin = true;
size_t bytes_written =
- spdy_session_->WriteHeaders(id(), std::move(trailer_block), kFin,
- priority(), std::move(ack_listener));
+ WriteHeadersImpl(std::move(trailer_block), kFin, std::move(ack_listener));
set_fin_sent(kFin);
// Trailers are the last thing to be sent on a stream, but if there is still
@@ -250,7 +257,8 @@
QuicConsumedData QuicSpdyStream::WriteBodySlices(QuicMemSliceSpan slices,
bool fin) {
- if (spdy_session_->connection()->transport_version() != QUIC_VERSION_99 ||
+ if (!VersionHasDataFrameHeader(
+ spdy_session_->connection()->transport_version()) ||
slices.empty()) {
return WriteMemSlices(slices, fin);
}
@@ -264,23 +272,30 @@
QuicConnection::ScopedPacketFlusher flusher(
spdy_session_->connection(), QuicConnection::SEND_ACK_IF_PENDING);
+
+ // Write frame header.
struct iovec header_iov = {static_cast<void*>(buffer.get()), header_length};
QuicMemSliceStorage storage(
&header_iov, 1,
spdy_session_->connection()->helper()->GetStreamSendBufferAllocator(),
GetQuicFlag(FLAGS_quic_send_buffer_max_data_slice_size));
- WriteMemSlices(storage.ToSpan(), false);
+ unacked_frame_headers_offsets_.Add(
+ send_buffer().stream_offset(),
+ send_buffer().stream_offset() + header_length);
QUIC_DLOG(INFO) << "Stream " << id() << " is writing header of length "
<< header_length;
- total_header_bytes_written_ += header_length;
- QUIC_DLOG(INFO) << "Stream" << id() << " is writing body of length "
+ WriteMemSlices(storage.ToSpan(), false);
+
+ // Write body.
+ QUIC_DLOG(INFO) << "Stream " << id() << " is writing body of length "
<< slices.total_length();
return WriteMemSlices(slices, fin);
}
size_t QuicSpdyStream::Readv(const struct iovec* iov, size_t iov_len) {
DCHECK(FinishedReadingHeaders());
- if (spdy_session_->connection()->transport_version() != QUIC_VERSION_99) {
+ if (!VersionHasDataFrameHeader(
+ spdy_session_->connection()->transport_version())) {
return sequencer()->Readv(iov, iov_len);
}
return body_buffer_.ReadBody(iov, iov_len);
@@ -288,7 +303,8 @@
int QuicSpdyStream::GetReadableRegions(iovec* iov, size_t iov_len) const {
DCHECK(FinishedReadingHeaders());
- if (spdy_session_->connection()->transport_version() != QUIC_VERSION_99) {
+ if (!VersionHasDataFrameHeader(
+ spdy_session_->connection()->transport_version())) {
return sequencer()->GetReadableRegions(iov, iov_len);
}
return body_buffer_.PeekBody(iov, iov_len);
@@ -296,8 +312,10 @@
void QuicSpdyStream::MarkConsumed(size_t num_bytes) {
DCHECK(FinishedReadingHeaders());
- if (spdy_session_->connection()->transport_version() != QUIC_VERSION_99) {
- return sequencer()->MarkConsumed(num_bytes);
+ if (!VersionHasDataFrameHeader(
+ spdy_session_->connection()->transport_version())) {
+ sequencer()->MarkConsumed(num_bytes);
+ return;
}
body_buffer_.MarkBodyConsumed(num_bytes);
}
@@ -310,7 +328,8 @@
}
bool QuicSpdyStream::HasBytesToRead() const {
- if (spdy_session_->connection()->transport_version() != QUIC_VERSION_99) {
+ if (!VersionHasDataFrameHeader(
+ spdy_session_->connection()->transport_version())) {
return sequencer()->HasBytesToRead();
}
return body_buffer_.HasBytesToRead();
@@ -321,7 +340,8 @@
}
uint64_t QuicSpdyStream::total_body_bytes_read() const {
- if (spdy_session_->connection()->transport_version() == QUIC_VERSION_99) {
+ if (VersionHasDataFrameHeader(
+ spdy_session_->connection()->transport_version())) {
return body_buffer_.total_body_bytes_received();
}
return sequencer()->NumBytesConsumed();
@@ -424,6 +444,14 @@
QuicStreamFrame(id(), fin, final_byte_offset, QuicStringPiece()));
}
+size_t QuicSpdyStream::WriteHeadersImpl(
+ spdy::SpdyHeaderBlock header_block,
+ bool fin,
+ QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
+ return spdy_session_->WriteHeadersOnHeadersStream(
+ id(), std::move(header_block), fin, priority(), std::move(ack_listener));
+}
+
void QuicSpdyStream::OnPriorityFrame(SpdyPriority priority) {
DCHECK_EQ(Perspective::IS_SERVER, session()->connection()->perspective());
SetPriority(priority);
@@ -442,7 +470,8 @@
}
void QuicSpdyStream::OnDataAvailable() {
- if (session()->connection()->transport_version() != QUIC_VERSION_99) {
+ if (!VersionHasDataFrameHeader(
+ session()->connection()->transport_version())) {
OnBodyAvailable();
return;
}
@@ -543,5 +572,52 @@
<< body_buffer_.total_body_bytes_received();
}
+bool QuicSpdyStream::OnStreamFrameAcked(QuicStreamOffset offset,
+ QuicByteCount data_length,
+ bool fin_acked,
+ QuicTime::Delta ack_delay_time,
+ QuicByteCount* newly_acked_length) {
+ const bool new_data_acked = QuicStream::OnStreamFrameAcked(
+ offset, data_length, fin_acked, ack_delay_time, newly_acked_length);
+
+ const QuicByteCount newly_acked_header_length =
+ GetNumFrameHeadersInInterval(offset, data_length);
+ DCHECK_LE(newly_acked_header_length, *newly_acked_length);
+ unacked_frame_headers_offsets_.Difference(offset, offset + data_length);
+ if (ack_listener_ != nullptr && new_data_acked) {
+ ack_listener_->OnPacketAcked(
+ *newly_acked_length - newly_acked_header_length, ack_delay_time);
+ }
+ return new_data_acked;
+}
+
+void QuicSpdyStream::OnStreamFrameRetransmitted(QuicStreamOffset offset,
+ QuicByteCount data_length,
+ bool fin_retransmitted) {
+ QuicStream::OnStreamFrameRetransmitted(offset, data_length,
+ fin_retransmitted);
+
+ const QuicByteCount retransmitted_header_length =
+ GetNumFrameHeadersInInterval(offset, data_length);
+ DCHECK_LE(retransmitted_header_length, data_length);
+
+ if (ack_listener_ != nullptr) {
+ ack_listener_->OnPacketRetransmitted(data_length -
+ retransmitted_header_length);
+ }
+}
+
+QuicByteCount QuicSpdyStream::GetNumFrameHeadersInInterval(
+ QuicStreamOffset offset,
+ QuicByteCount data_length) const {
+ QuicByteCount header_acked_length = 0;
+ QuicIntervalSet<QuicStreamOffset> newly_acked(offset, offset + data_length);
+ newly_acked.Intersection(unacked_frame_headers_offsets_);
+ for (const auto& interval : newly_acked) {
+ header_acked_length += interval.Length();
+ }
+ return header_acked_length;
+}
+
#undef ENDPOINT // undef for jumbo builds
} // namespace quic
diff --git a/quic/core/http/quic_spdy_stream.h b/quic/core/http/quic_spdy_stream.h
index eccec56..2bad21a 100644
--- a/quic/core/http/quic_spdy_stream.h
+++ b/quic/core/http/quic_spdy_stream.h
@@ -31,6 +31,7 @@
namespace quic {
namespace test {
+class QuicSpdyStreamPeer;
class QuicStreamPeer;
} // namespace test
@@ -117,10 +118,7 @@
QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
// Sends |data| to the peer, or buffers if it can't be sent immediately.
- void WriteOrBufferBody(
- QuicStringPiece data,
- bool fin,
- QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
+ void WriteOrBufferBody(QuicStringPiece data, bool fin);
// Writes the trailers contained in |trailer_block| to the dedicated
// headers stream. Trailers will always have the FIN set.
@@ -128,6 +126,18 @@
spdy::SpdyHeaderBlock trailer_block,
QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
+ // Override to report newly acked bytes via ack_listener_.
+ bool OnStreamFrameAcked(QuicStreamOffset offset,
+ QuicByteCount data_length,
+ bool fin_acked,
+ QuicTime::Delta ack_delay_time,
+ QuicByteCount* newly_acked_length) override;
+
+ // Override to report bytes retransmitted via ack_listener_.
+ void OnStreamFrameRetransmitted(QuicStreamOffset offset,
+ QuicByteCount data_length,
+ bool fin_retransmitted) override;
+
// Does the same thing as WriteOrBufferBody except this method takes iovec
// as the data input. Right now it only calls WritevData.
// TODO(renjietang): Write data frame header before writing body.
@@ -166,10 +176,6 @@
bool headers_decompressed() const { return headers_decompressed_; }
- size_t total_header_bytes_written() const {
- return total_header_bytes_written_;
- }
-
// Returns total amount of body bytes that have been read.
uint64_t total_body_bytes_read() const;
@@ -210,16 +216,36 @@
virtual void OnTrailingHeadersComplete(bool fin,
size_t frame_len,
const QuicHeaderList& header_list);
+ virtual size_t WriteHeadersImpl(
+ spdy::SpdyHeaderBlock header_block,
+ bool fin,
+ QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
+
QuicSpdySession* spdy_session() const { return spdy_session_; }
Visitor* visitor() { return visitor_; }
void set_headers_decompressed(bool val) { headers_decompressed_ = val; }
+ void set_ack_listener(
+ QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
+ ack_listener_ = std::move(ack_listener);
+ }
+
+ const QuicIntervalSet<QuicStreamOffset>& unacked_frame_headers_offsets() {
+ return unacked_frame_headers_offsets_;
+ }
+
private:
+ friend class test::QuicSpdyStreamPeer;
friend class test::QuicStreamPeer;
friend class QuicStreamUtils;
class HttpDecoderVisitor;
+ // Given the interval marked by [|offset|, |offset| + |data_length|), return
+ // the number of frame header bytes contained in it.
+ QuicByteCount GetNumFrameHeadersInInterval(QuicStreamOffset offset,
+ QuicByteCount data_length) const;
+
QuicSpdySession* spdy_session_;
Visitor* visitor_;
@@ -244,8 +270,13 @@
std::unique_ptr<HttpDecoderVisitor> http_decoder_visitor_;
// Buffer that contains decoded data of the stream.
QuicSpdyStreamBodyBuffer body_buffer_;
- // Total bytes of header written to the stream.
- size_t total_header_bytes_written_;
+
+ // Ack listener of this stream, and it is notified when any of written bytes
+ // are acked or retransmitted.
+ QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener_;
+
+ // Offset of unacked frame headers.
+ QuicIntervalSet<QuicStreamOffset> unacked_frame_headers_offsets_;
};
} // namespace quic
diff --git a/quic/core/http/quic_spdy_stream_test.cc b/quic/core/http/quic_spdy_stream_test.cc
index 07bb9ed..1aabe0e 100644
--- a/quic/core/http/quic_spdy_stream_test.cc
+++ b/quic/core/http/quic_spdy_stream_test.cc
@@ -12,6 +12,7 @@
#include "net/third_party/quiche/src/quic/core/quic_connection.h"
#include "net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.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/quic_write_blocked_list.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
@@ -24,6 +25,7 @@
#include "net/third_party/quiche/src/quic/test_tools/quic_flow_controller_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_session_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_spdy_stream_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"
@@ -32,7 +34,7 @@
using spdy::SpdyHeaderBlock;
using spdy::SpdyPriority;
using testing::_;
-using testing::AnyNumber;
+using testing::AtLeast;
using testing::Invoke;
using testing::Return;
using testing::StrictMock;
@@ -50,6 +52,11 @@
bool should_process_data)
: QuicSpdyStream(id, session, BIDIRECTIONAL),
should_process_data_(should_process_data) {}
+ ~TestStream() override = default;
+
+ using QuicSpdyStream::set_ack_listener;
+ using QuicStream::CloseWriteSide;
+ using QuicStream::WriteOrBufferData;
void OnBodyAvailable() override {
if (!should_process_data_) {
@@ -63,14 +70,23 @@
data_ += QuicString(buffer, bytes_read);
}
- using QuicSpdyStream::set_ack_listener;
- using QuicStream::CloseWriteSide;
- using QuicStream::WriteOrBufferData;
+ MOCK_METHOD1(WriteHeadersMock, void(bool fin));
+
+ size_t WriteHeadersImpl(spdy::SpdyHeaderBlock header_block,
+ bool fin,
+ QuicReferenceCountedPointer<QuicAckListenerInterface>
+ ack_listener) override {
+ saved_headers_ = std::move(header_block);
+ WriteHeadersMock(fin);
+ return 0;
+ }
const QuicString& data() const { return data_; }
+ const spdy::SpdyHeaderBlock& saved_headers() const { return saved_headers_; }
private:
bool should_process_data_;
+ spdy::SpdyHeaderBlock saved_headers_;
QuicString data_;
};
@@ -128,17 +144,21 @@
}
void Initialize(bool stream_should_process_data) {
- connection_ = new testing::StrictMock<MockQuicConnection>(
+ connection_ = new StrictMock<MockQuicConnection>(
&helper_, &alarm_factory_, Perspective::IS_SERVER,
SupportedVersions(GetParam()));
- session_ =
- QuicMakeUnique<testing::StrictMock<MockQuicSpdySession>>(connection_);
+ session_ = QuicMakeUnique<StrictMock<MockQuicSpdySession>>(connection_);
session_->Initialize();
- stream_ = new TestStream(GetNthClientInitiatedBidirectionalId(0),
- session_.get(), stream_should_process_data);
+ ON_CALL(*session_, WritevData(_, _, _, _, _))
+ .WillByDefault(Invoke(MockQuicSession::ConsumeData));
+
+ stream_ =
+ new StrictMock<TestStream>(GetNthClientInitiatedBidirectionalId(0),
+ session_.get(), stream_should_process_data);
session_->ActivateStream(QuicWrapUnique(stream_));
- stream2_ = new TestStream(GetNthClientInitiatedBidirectionalId(1),
- session_.get(), stream_should_process_data);
+ stream2_ =
+ new StrictMock<TestStream>(GetNthClientInitiatedBidirectionalId(1),
+ session_.get(), stream_should_process_data);
session_->ActivateStream(QuicWrapUnique(stream2_));
}
@@ -149,8 +169,12 @@
}
QuicStreamId GetNthClientInitiatedBidirectionalId(int n) {
- return QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId(
- *session_, n);
+ return GetNthClientInitiatedBidirectionalStreamId(
+ connection_->transport_version(), n);
+ }
+
+ bool HasFrameHeader() const {
+ return VersionHasDataFrameHeader(connection_->transport_version());
}
protected:
@@ -168,9 +192,8 @@
HttpEncoder encoder_;
};
-INSTANTIATE_TEST_CASE_P(Tests,
- QuicSpdyStreamTest,
- ::testing::ValuesIn(AllSupportedVersions()));
+INSTANTIATE_TEST_SUITE_P(Tests, QuicSpdyStreamTest,
+ ::testing::ValuesIn(AllSupportedVersions()));
TEST_P(QuicSpdyStreamTest, ProcessHeaderList) {
Initialize(kShouldProcessData);
@@ -288,9 +311,7 @@
QuicByteCount header_length =
encoder_.SerializeDataFrameHeader(body.length(), &buffer);
QuicString header = QuicString(buffer.get(), header_length);
- QuicString data = connection_->transport_version() == QUIC_VERSION_99
- ? header + body
- : body;
+ QuicString data = HasFrameHeader() ? header + body : body;
EXPECT_EQ("", stream_->data());
QuicHeaderList headers = ProcessHeaders(false, headers_);
@@ -310,9 +331,7 @@
QuicByteCount header_length =
encoder_.SerializeDataFrameHeader(body.length(), &buffer);
QuicString header = QuicString(buffer.get(), header_length);
- QuicString data = connection_->transport_version() == QUIC_VERSION_99
- ? header + body
- : body;
+ QuicString data = HasFrameHeader() ? header + body : body;
for (size_t fragment_size = 1; fragment_size < data.size(); ++fragment_size) {
Initialize(kShouldProcessData);
@@ -338,9 +357,7 @@
QuicByteCount header_length =
encoder_.SerializeDataFrameHeader(body.length(), &buffer);
QuicString header = QuicString(buffer.get(), header_length);
- QuicString data = connection_->transport_version() == QUIC_VERSION_99
- ? header + body
- : body;
+ QuicString data = HasFrameHeader() ? header + body : body;
for (size_t split_point = 1; split_point < data.size() - 1; ++split_point) {
Initialize(kShouldProcessData);
@@ -371,9 +388,7 @@
QuicByteCount header_length =
encoder_.SerializeDataFrameHeader(body.length(), &buf);
QuicString header = QuicString(buf.get(), header_length);
- QuicString data = connection_->transport_version() == QUIC_VERSION_99
- ? header + body
- : body;
+ QuicString data = HasFrameHeader() ? header + body : body;
ProcessHeaders(false, headers_);
QuicStreamFrame frame(GetNthClientInitiatedBidirectionalId(0), false, 0,
@@ -399,9 +414,7 @@
QuicByteCount header_length =
encoder_.SerializeDataFrameHeader(body.length(), &buf);
QuicString header = QuicString(buf.get(), header_length);
- QuicString data = connection_->transport_version() == QUIC_VERSION_99
- ? header + body
- : body;
+ QuicString data = HasFrameHeader() ? header + body : body;
ProcessHeaders(false, headers_);
QuicStreamFrame frame(GetNthClientInitiatedBidirectionalId(0), false, 0,
QuicStringPiece(data));
@@ -428,9 +441,7 @@
QuicByteCount header_length =
encoder_.SerializeDataFrameHeader(body.length(), &buf);
QuicString header = QuicString(buf.get(), header_length);
- QuicString data = connection_->transport_version() == QUIC_VERSION_99
- ? header + body
- : body;
+ QuicString data = HasFrameHeader() ? header + body : body;
ProcessHeaders(false, headers_);
QuicStreamFrame frame(GetNthClientInitiatedBidirectionalId(0), false, 0,
@@ -456,13 +467,9 @@
QuicByteCount header_length =
encoder_.SerializeDataFrameHeader(body1.length(), &buf);
QuicString header = QuicString(buf.get(), header_length);
- QuicString data1 = connection_->transport_version() == QUIC_VERSION_99
- ? header + body1
- : body1;
+ QuicString data1 = HasFrameHeader() ? header + body1 : body1;
header_length = encoder_.SerializeDataFrameHeader(body2.length(), &buf);
- QuicString data2 = connection_->transport_version() == QUIC_VERSION_99
- ? header + body2
- : body2;
+ QuicString data2 = HasFrameHeader() ? header + body2 : body2;
ProcessHeaders(false, headers_);
QuicStreamFrame frame1(GetNthClientInitiatedBidirectionalId(0), false, 0,
@@ -486,9 +493,7 @@
QuicByteCount header_length =
encoder_.SerializeDataFrameHeader(body.length(), &buf);
QuicString header = QuicString(buf.get(), header_length);
- QuicString data = connection_->transport_version() == QUIC_VERSION_99
- ? header + body
- : body;
+ QuicString data = HasFrameHeader() ? header + body : body;
ProcessHeaders(false, headers_);
QuicStreamFrame frame(GetNthClientInitiatedBidirectionalId(0), false, 0,
@@ -516,9 +521,7 @@
QuicByteCount header_length =
encoder_.SerializeDataFrameHeader(body.length(), &buf);
QuicString header = QuicString(buf.get(), header_length);
- QuicString data = connection_->transport_version() == QUIC_VERSION_99
- ? header + body
- : body;
+ QuicString data = HasFrameHeader() ? header + body : body;
ProcessHeaders(false, headers_);
QuicStreamFrame frame(GetNthClientInitiatedBidirectionalId(0), false, 0,
@@ -558,17 +561,15 @@
// Try to send more data than the flow control limit allows.
const uint64_t kOverflow = 15;
QuicString body(kWindow + kOverflow, 'a');
- bool is_version_99 = connection_->transport_version() == QUIC_VERSION_99;
- const uint64_t kHeaderLength = is_version_99 ? 2 : 0;
- if (is_version_99) {
- EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
- .WillOnce(Return(QuicConsumedData(2, false)));
+ const uint64_t kHeaderLength = HasFrameHeader() ? 2 : 0;
+ if (HasFrameHeader()) {
+ EXPECT_CALL(*session_, WritevData(_, _, kHeaderLength, _, NO_FIN));
}
EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
.WillOnce(Return(QuicConsumedData(kWindow - kHeaderLength, true)));
EXPECT_CALL(*connection_, SendControlFrame(_));
- stream_->WriteOrBufferBody(body, false, nullptr);
+ stream_->WriteOrBufferBody(body, false);
// Should have sent as much as possible, resulting in no send window left.
EXPECT_EQ(0u,
@@ -605,7 +606,7 @@
QuicByteCount header_length = 0;
QuicString data;
- if (connection_->transport_version() == QUIC_VERSION_99) {
+ if (HasFrameHeader()) {
std::unique_ptr<char[]> buffer;
header_length = encoder_.SerializeDataFrameHeader(body.length(), &buffer);
QuicString header = QuicString(buffer.get(), header_length);
@@ -654,7 +655,7 @@
QuicByteCount header_length = 0;
QuicString data;
- if (connection_->transport_version() == QUIC_VERSION_99) {
+ if (HasFrameHeader()) {
std::unique_ptr<char[]> buffer;
header_length = encoder_.SerializeDataFrameHeader(body.length(), &buffer);
QuicString header = QuicString(buffer.get(), header_length);
@@ -723,7 +724,7 @@
QuicString data2;
QuicString body2(1, 'a');
- if (connection_->transport_version() == QUIC_VERSION_99) {
+ if (HasFrameHeader()) {
body = QuicString(kWindow / 4 - 2, 'a');
std::unique_ptr<char[]> buffer;
header_length = encoder_.SerializeDataFrameHeader(body.length(), &buffer);
@@ -777,9 +778,7 @@
QuicByteCount header_length =
encoder_.SerializeDataFrameHeader(body.length(), &buf);
QuicString header = QuicString(buf.get(), header_length);
- QuicString data = connection_->transport_version() == QUIC_VERSION_99
- ? header + body
- : body;
+ QuicString data = HasFrameHeader() ? header + body : body;
QuicStreamFrame frame(GetNthClientInitiatedBidirectionalId(0), false, 0,
QuicStringPiece(data));
EXPECT_CALL(*connection_,
@@ -822,9 +821,7 @@
QuicByteCount header_length =
encoder_.SerializeDataFrameHeader(body.length(), &buf);
QuicString header = QuicString(buf.get(), header_length);
- QuicString data = connection_->transport_version() == QUIC_VERSION_99
- ? header + body
- : body;
+ QuicString data = HasFrameHeader() ? header + body : body;
EXPECT_LT(data.size(), kStreamWindow);
QuicStreamFrame frame(GetNthClientInitiatedBidirectionalId(0), false, 0,
@@ -853,10 +850,9 @@
EXPECT_CALL(*connection_,
SendBlocked(GetNthClientInitiatedBidirectionalId(0)))
.Times(0);
- EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
- .WillOnce(Return(QuicConsumedData(0, fin)));
+ EXPECT_CALL(*session_, WritevData(_, _, 0, _, FIN));
- stream_->WriteOrBufferBody(body, fin, nullptr);
+ stream_->WriteOrBufferBody(body, fin);
}
TEST_P(QuicSpdyStreamTest, ReceivingTrailersViaHeaderList) {
@@ -915,9 +911,7 @@
QuicByteCount header_length =
encoder_.SerializeDataFrameHeader(body.length(), &buf);
QuicString header = QuicString(buf.get(), header_length);
- QuicString data = connection_->transport_version() == QUIC_VERSION_99
- ? header + body
- : body;
+ QuicString data = HasFrameHeader() ? header + body : body;
// Receive trailing headers.
SpdyHeaderBlock trailers_block;
@@ -1052,9 +1046,7 @@
QuicByteCount header_length =
encoder_.SerializeDataFrameHeader(body.length(), &buf);
QuicString header = QuicString(buf.get(), header_length);
- QuicString data = connection_->transport_version() == QUIC_VERSION_99
- ? header + body
- : body;
+ QuicString data = HasFrameHeader() ? header + body : body;
QuicStreamFrame frame(GetNthClientInitiatedBidirectionalId(0), /*fin=*/true,
0, data);
@@ -1067,18 +1059,15 @@
// Test that writing trailers will send a FIN, as Trailers are the last thing
// to be sent on a stream.
Initialize(kShouldProcessData);
- EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
- .Times(AnyNumber())
- .WillRepeatedly(Invoke(MockQuicSession::ConsumeData));
// Write the initial headers, without a FIN.
- EXPECT_CALL(*session_, WriteHeadersMock(_, _, _, _, _));
+ EXPECT_CALL(*stream_, WriteHeadersMock(false));
stream_->WriteHeaders(SpdyHeaderBlock(), /*fin=*/false, nullptr);
// Writing trailers implicitly sends a FIN.
SpdyHeaderBlock trailers;
trailers["trailer key"] = "trailer value";
- EXPECT_CALL(*session_, WriteHeadersMock(_, _, true, _, _));
+ EXPECT_CALL(*stream_, WriteHeadersMock(true));
stream_->WriteTrailers(std::move(trailers), nullptr);
EXPECT_TRUE(stream_->fin_sent());
}
@@ -1087,23 +1076,21 @@
// Test that when writing trailers, the trailers that are actually sent to the
// peer contain the final offset field indicating last byte of data.
Initialize(kShouldProcessData);
- EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
- .Times(AnyNumber())
- .WillRepeatedly(Invoke(MockQuicSession::ConsumeData));
// Write the initial headers.
- EXPECT_CALL(*session_, WriteHeadersMock(_, _, _, _, _));
+ EXPECT_CALL(*stream_, WriteHeadersMock(false));
stream_->WriteHeaders(SpdyHeaderBlock(), /*fin=*/false, nullptr);
// Write non-zero body data to force a non-zero final offset.
- QuicString body(1024, 'x'); // 1 MB
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(AtLeast(1));
+ QuicString body(1024, 'x'); // 1 kB
QuicByteCount header_length = 0;
- if (connection_->transport_version() == QUIC_VERSION_99) {
+ if (HasFrameHeader()) {
std::unique_ptr<char[]> buf;
header_length = encoder_.SerializeDataFrameHeader(body.length(), &buf);
}
- stream_->WriteOrBufferBody(body, false, nullptr);
+ stream_->WriteOrBufferBody(body, false);
// The final offset field in the trailing headers is populated with the
// number of body bytes written (including queued bytes).
@@ -1112,31 +1099,29 @@
SpdyHeaderBlock trailers_with_offset(trailers.Clone());
trailers_with_offset[kFinalOffsetHeaderKey] =
QuicTextUtils::Uint64ToString(body.length() + header_length);
- EXPECT_CALL(*session_, WriteHeadersMock(_, _, true, _, _));
+ EXPECT_CALL(*stream_, WriteHeadersMock(true));
stream_->WriteTrailers(std::move(trailers), nullptr);
- EXPECT_EQ(trailers_with_offset, session_->GetWriteHeaders());
+ EXPECT_EQ(trailers_with_offset, stream_->saved_headers());
}
TEST_P(QuicSpdyStreamTest, WritingTrailersClosesWriteSide) {
// Test that if trailers are written after all other data has been written
// (headers and body), that this closes the stream for writing.
Initialize(kShouldProcessData);
- EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
- .Times(AnyNumber())
- .WillRepeatedly(Invoke(MockQuicSession::ConsumeData));
// Write the initial headers.
- EXPECT_CALL(*session_, WriteHeadersMock(_, _, _, _, _));
+ EXPECT_CALL(*stream_, WriteHeadersMock(false));
stream_->WriteHeaders(SpdyHeaderBlock(), /*fin=*/false, nullptr);
// Write non-zero body data.
- const int kBodySize = 1 * 1024; // 1 MB
- stream_->WriteOrBufferBody(QuicString(kBodySize, 'x'), false, nullptr);
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(AtLeast(1));
+ const int kBodySize = 1 * 1024; // 1 kB
+ stream_->WriteOrBufferBody(QuicString(kBodySize, 'x'), false);
EXPECT_EQ(0u, stream_->BufferedDataBytes());
// Headers and body have been fully written, there is no queued data. Writing
// trailers marks the end of this stream, and thus the write side is closed.
- EXPECT_CALL(*session_, WriteHeadersMock(_, _, true, _, _));
+ EXPECT_CALL(*stream_, WriteHeadersMock(true));
stream_->WriteTrailers(SpdyHeaderBlock(), nullptr);
EXPECT_TRUE(stream_->write_side_closed());
}
@@ -1146,35 +1131,30 @@
// while there are still body bytes queued.
testing::InSequence seq;
Initialize(kShouldProcessData);
- EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
- .Times(AnyNumber())
- .WillRepeatedly(Invoke(MockQuicSession::ConsumeData));
// Write the initial headers.
- EXPECT_CALL(*session_, WriteHeadersMock(_, _, _, _, _));
+ EXPECT_CALL(*stream_, WriteHeadersMock(false));
stream_->WriteHeaders(SpdyHeaderBlock(), /*fin=*/false, nullptr);
// Write non-zero body data, but only consume partially, ensuring queueing.
- const int kBodySize = 1 * 1024; // 1 KB
- if (connection_->transport_version() == QUIC_VERSION_99) {
- EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
- .WillOnce(Return(QuicConsumedData(3, false)));
+ const int kBodySize = 1 * 1024; // 1 kB
+ if (HasFrameHeader()) {
+ EXPECT_CALL(*session_, WritevData(_, _, 3, _, NO_FIN));
}
- EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+ EXPECT_CALL(*session_, WritevData(_, _, kBodySize, _, NO_FIN))
.WillOnce(Return(QuicConsumedData(kBodySize - 1, false)));
- stream_->WriteOrBufferBody(QuicString(kBodySize, 'x'), false, nullptr);
+ stream_->WriteOrBufferBody(QuicString(kBodySize, 'x'), false);
EXPECT_EQ(1u, stream_->BufferedDataBytes());
// Writing trailers will send a FIN, but not close the write side of the
// stream as there are queued bytes.
- EXPECT_CALL(*session_, WriteHeadersMock(_, _, true, _, _));
+ EXPECT_CALL(*stream_, WriteHeadersMock(true));
stream_->WriteTrailers(SpdyHeaderBlock(), nullptr);
EXPECT_TRUE(stream_->fin_sent());
EXPECT_FALSE(stream_->write_side_closed());
// Writing the queued bytes will close the write side of the stream.
- EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
- .WillOnce(Return(QuicConsumedData(1, false)));
+ EXPECT_CALL(*session_, WritevData(_, _, 1, _, NO_FIN));
stream_->OnCanWrite();
EXPECT_TRUE(stream_->write_side_closed());
}
@@ -1187,12 +1167,9 @@
// Test that it is not possible to write Trailers after a FIN has been sent.
Initialize(kShouldProcessData);
- EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
- .Times(AnyNumber())
- .WillRepeatedly(Invoke(MockQuicSession::ConsumeData));
// Write the initial headers, with a FIN.
- EXPECT_CALL(*session_, WriteHeadersMock(_, _, _, _, _));
+ EXPECT_CALL(*stream_, WriteHeadersMock(true));
stream_->WriteHeaders(SpdyHeaderBlock(), /*fin=*/true, nullptr);
EXPECT_TRUE(stream_->fin_sent());
@@ -1204,9 +1181,7 @@
TEST_P(QuicSpdyStreamTest, HeaderStreamNotiferCorrespondingSpdyStream) {
Initialize(kShouldProcessData);
- EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
- .Times(AnyNumber())
- .WillRepeatedly(Invoke(MockQuicSession::ConsumeData));
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(AtLeast(1));
testing::InSequence s;
QuicReferenceCountedPointer<MockAckListener> ack_listener1(
new MockAckListener());
@@ -1217,20 +1192,26 @@
session_->headers_stream()->WriteOrBufferData("Header1", false,
ack_listener1);
- stream_->WriteOrBufferBody("Test1", true, nullptr);
+ stream_->WriteOrBufferBody("Test1", true);
session_->headers_stream()->WriteOrBufferData("Header2", false,
ack_listener2);
- stream2_->WriteOrBufferBody("Test2", false, nullptr);
+ stream2_->WriteOrBufferBody("Test2", false);
QuicStreamFrame frame1(
QuicUtils::GetHeadersStreamId(connection_->transport_version()), false, 0,
"Header1");
- QuicStreamFrame frame2(stream_->id(), true, 0, "Test1");
+ QuicString header = "";
+ if (HasFrameHeader()) {
+ std::unique_ptr<char[]> buffer;
+ QuicByteCount header_length = encoder_.SerializeDataFrameHeader(5, &buffer);
+ header = QuicString(buffer.get(), header_length);
+ }
+ QuicStreamFrame frame2(stream_->id(), true, 0, header + "Test1");
QuicStreamFrame frame3(
QuicUtils::GetHeadersStreamId(connection_->transport_version()), false, 7,
"Header2");
- QuicStreamFrame frame4(stream2_->id(), false, 0, "Test2");
+ QuicStreamFrame frame4(stream2_->id(), false, 0, header + "Test2");
EXPECT_CALL(*ack_listener1, OnPacketRetransmitted(7));
session_->OnStreamFrameRetransmitted(frame1);
@@ -1251,12 +1232,10 @@
TEST_P(QuicSpdyStreamTest, StreamBecomesZombieWithWriteThatCloses) {
Initialize(kShouldProcessData);
- EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
- .Times(AnyNumber())
- .WillRepeatedly(Invoke(MockQuicSession::ConsumeData));
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(AtLeast(1));
QuicStreamPeer::CloseReadSide(stream_);
// This write causes stream to be closed.
- stream_->WriteOrBufferBody("Test1", true, nullptr);
+ stream_->WriteOrBufferBody("Test1", true);
// stream_ has unacked data and should become zombie.
EXPECT_TRUE(QuicContainsKey(QuicSessionPeer::zombie_streams(session_.get()),
stream_->id()));
@@ -1273,26 +1252,24 @@
testing::InSequence seq;
Initialize(kShouldProcessData);
- if (connection_->transport_version() == QUIC_VERSION_99) {
- EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
- .WillOnce(Return(QuicConsumedData(2, false)));
+ if (HasFrameHeader()) {
+ EXPECT_CALL(*session_, WritevData(_, _, 2, _, NO_FIN));
}
- EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
- .WillOnce(Return(QuicConsumedData(4, true)));
- stream_->WriteOrBufferBody("data", true, nullptr);
+ EXPECT_CALL(*session_, WritevData(_, _, 4, _, FIN));
+ stream_->WriteOrBufferBody("data", true);
stream_->OnPriorityFrame(kV3HighestPriority);
EXPECT_EQ(kV3HighestPriority, stream_->priority());
}
TEST_P(QuicSpdyStreamTest, SetPriorityBeforeUpdateStreamPriority) {
- MockQuicConnection* connection = new testing::StrictMock<MockQuicConnection>(
+ MockQuicConnection* connection = new StrictMock<MockQuicConnection>(
&helper_, &alarm_factory_, Perspective::IS_SERVER,
SupportedVersions(GetParam()));
std::unique_ptr<TestMockUpdateStreamSession> session(
- new testing::StrictMock<TestMockUpdateStreamSession>(connection));
- TestStream* stream = new TestStream(
- QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId(*session,
- 0),
+ new StrictMock<TestMockUpdateStreamSession>(connection));
+ auto stream = new StrictMock<TestStream>(
+ GetNthClientInitiatedBidirectionalStreamId(
+ session->connection()->transport_version(), 0),
session.get(),
/*should_process_data=*/true);
session->ActivateStream(QuicWrapUnique(stream));
@@ -1309,6 +1286,233 @@
stream->SetPriority(kV3LowestPriority);
}
+TEST_P(QuicSpdyStreamTest, StreamWaitsForAcks) {
+ Initialize(kShouldProcessData);
+ QuicReferenceCountedPointer<MockAckListener> mock_ack_listener(
+ new StrictMock<MockAckListener>);
+ stream_->set_ack_listener(mock_ack_listener);
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(AtLeast(1));
+ // Stream is not waiting for acks initially.
+ EXPECT_FALSE(stream_->IsWaitingForAcks());
+ EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
+
+ // Send kData1.
+ stream_->WriteOrBufferData("FooAndBar", false, nullptr);
+ EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size());
+ EXPECT_TRUE(stream_->IsWaitingForAcks());
+ EXPECT_CALL(*mock_ack_listener, OnPacketAcked(9, _));
+ QuicByteCount newly_acked_length = 0;
+ EXPECT_TRUE(stream_->OnStreamFrameAcked(0, 9, false, QuicTime::Delta::Zero(),
+ &newly_acked_length));
+ // Stream is not waiting for acks as all sent data is acked.
+ EXPECT_FALSE(stream_->IsWaitingForAcks());
+ EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
+
+ // Send kData2.
+ stream_->WriteOrBufferData("FooAndBar", false, nullptr);
+ EXPECT_TRUE(stream_->IsWaitingForAcks());
+ EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size());
+ // Send FIN.
+ stream_->WriteOrBufferData("", true, nullptr);
+ // Fin only frame is not stored in send buffer.
+ EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size());
+
+ // kData2 is retransmitted.
+ EXPECT_CALL(*mock_ack_listener, OnPacketRetransmitted(9));
+ stream_->OnStreamFrameRetransmitted(9, 9, false);
+
+ // kData2 is acked.
+ EXPECT_CALL(*mock_ack_listener, OnPacketAcked(9, _));
+ EXPECT_TRUE(stream_->OnStreamFrameAcked(9, 9, false, QuicTime::Delta::Zero(),
+ &newly_acked_length));
+ // Stream is waiting for acks as FIN is not acked.
+ EXPECT_TRUE(stream_->IsWaitingForAcks());
+ EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
+
+ // FIN is acked.
+ EXPECT_CALL(*mock_ack_listener, OnPacketAcked(0, _));
+ EXPECT_TRUE(stream_->OnStreamFrameAcked(18, 0, true, QuicTime::Delta::Zero(),
+ &newly_acked_length));
+ EXPECT_FALSE(stream_->IsWaitingForAcks());
+ EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
+}
+
+TEST_P(QuicSpdyStreamTest, StreamDataGetAckedMultipleTimes) {
+ Initialize(kShouldProcessData);
+ QuicReferenceCountedPointer<MockAckListener> mock_ack_listener(
+ new StrictMock<MockAckListener>);
+ stream_->set_ack_listener(mock_ack_listener);
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(AtLeast(1));
+ // Send [0, 27) and fin.
+ stream_->WriteOrBufferData("FooAndBar", false, nullptr);
+ stream_->WriteOrBufferData("FooAndBar", false, nullptr);
+ stream_->WriteOrBufferData("FooAndBar", true, nullptr);
+
+ // Ack [0, 9), [5, 22) and [18, 26)
+ // Verify [0, 9) 9 bytes are acked.
+ QuicByteCount newly_acked_length = 0;
+ EXPECT_CALL(*mock_ack_listener, OnPacketAcked(9, _));
+ EXPECT_TRUE(stream_->OnStreamFrameAcked(0, 9, false, QuicTime::Delta::Zero(),
+ &newly_acked_length));
+ EXPECT_EQ(2u, QuicStreamPeer::SendBuffer(stream_).size());
+ // Verify [9, 22) 13 bytes are acked.
+ EXPECT_CALL(*mock_ack_listener, OnPacketAcked(13, _));
+ EXPECT_TRUE(stream_->OnStreamFrameAcked(5, 17, false, QuicTime::Delta::Zero(),
+ &newly_acked_length));
+ EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size());
+ // Verify [22, 26) 4 bytes are acked.
+ EXPECT_CALL(*mock_ack_listener, OnPacketAcked(4, _));
+ EXPECT_TRUE(stream_->OnStreamFrameAcked(18, 8, false, QuicTime::Delta::Zero(),
+ &newly_acked_length));
+ EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size());
+ EXPECT_TRUE(stream_->IsWaitingForAcks());
+
+ // Ack [0, 27).
+ // Verify [26, 27) 1 byte is acked.
+ EXPECT_CALL(*mock_ack_listener, OnPacketAcked(1, _));
+ EXPECT_TRUE(stream_->OnStreamFrameAcked(26, 1, false, QuicTime::Delta::Zero(),
+ &newly_acked_length));
+ EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
+ EXPECT_TRUE(stream_->IsWaitingForAcks());
+
+ // Ack Fin. Verify OnPacketAcked is called.
+ EXPECT_CALL(*mock_ack_listener, OnPacketAcked(0, _));
+ EXPECT_TRUE(stream_->OnStreamFrameAcked(27, 0, true, QuicTime::Delta::Zero(),
+ &newly_acked_length));
+ EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
+ EXPECT_FALSE(stream_->IsWaitingForAcks());
+
+ // Ack [10, 27) and fin.
+ // No new data is acked, verify OnPacketAcked is not called.
+ EXPECT_CALL(*mock_ack_listener, OnPacketAcked(_, _)).Times(0);
+ EXPECT_FALSE(stream_->OnStreamFrameAcked(
+ 10, 17, true, QuicTime::Delta::Zero(), &newly_acked_length));
+ EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
+ EXPECT_FALSE(stream_->IsWaitingForAcks());
+}
+
+// HTTP/3 only.
+TEST_P(QuicSpdyStreamTest, HeadersAckNotReportedWriteOrBufferBody) {
+ Initialize(kShouldProcessData);
+ if (!HasFrameHeader()) {
+ return;
+ }
+ QuicReferenceCountedPointer<MockAckListener> mock_ack_listener(
+ new StrictMock<MockAckListener>);
+ stream_->set_ack_listener(mock_ack_listener);
+ QuicString body = "Test1";
+ QuicString body2(100, 'x');
+
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(AtLeast(1));
+ stream_->WriteOrBufferBody(body, false);
+ stream_->WriteOrBufferBody(body2, true);
+
+ std::unique_ptr<char[]> buffer;
+ QuicByteCount header_length =
+ encoder_.SerializeDataFrameHeader(body.length(), &buffer);
+ QuicString header = QuicString(buffer.get(), header_length);
+
+ header_length = encoder_.SerializeDataFrameHeader(body2.length(), &buffer);
+ QuicString header2 = QuicString(buffer.get(), header_length);
+
+ EXPECT_CALL(*mock_ack_listener, OnPacketAcked(body.length(), _));
+ QuicStreamFrame frame(stream_->id(), false, 0, header + body);
+ EXPECT_TRUE(
+ session_->OnFrameAcked(QuicFrame(frame), QuicTime::Delta::Zero()));
+
+ EXPECT_CALL(*mock_ack_listener, OnPacketAcked(0, _));
+ QuicStreamFrame frame2(stream_->id(), false, (header + body).length(),
+ header2);
+ EXPECT_TRUE(
+ session_->OnFrameAcked(QuicFrame(frame2), QuicTime::Delta::Zero()));
+
+ EXPECT_CALL(*mock_ack_listener, OnPacketAcked(body2.length(), _));
+ QuicStreamFrame frame3(stream_->id(), true,
+ (header + body).length() + header2.length(), body2);
+ EXPECT_TRUE(
+ session_->OnFrameAcked(QuicFrame(frame3), QuicTime::Delta::Zero()));
+
+ EXPECT_TRUE(
+ QuicSpdyStreamPeer::unacked_frame_headers_offsets(stream_).Empty());
+}
+
+// HTTP/3 only.
+TEST_P(QuicSpdyStreamTest, HeadersAckNotReportedWriteBodySlices) {
+ Initialize(kShouldProcessData);
+ if (!HasFrameHeader()) {
+ return;
+ }
+ QuicReferenceCountedPointer<MockAckListener> mock_ack_listener(
+ new StrictMock<MockAckListener>);
+ stream_->set_ack_listener(mock_ack_listener);
+ QuicString body = "Test1";
+ QuicString body2(100, 'x');
+ struct iovec body1_iov = {const_cast<char*>(body.data()), body.length()};
+ struct iovec body2_iov = {const_cast<char*>(body2.data()), body2.length()};
+ QuicMemSliceStorage storage(&body1_iov, 1,
+ helper_.GetStreamSendBufferAllocator(), 1024);
+ QuicMemSliceStorage storage2(&body2_iov, 1,
+ helper_.GetStreamSendBufferAllocator(), 1024);
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(AtLeast(1));
+ stream_->WriteBodySlices(storage.ToSpan(), false);
+ stream_->WriteBodySlices(storage2.ToSpan(), true);
+
+ std::unique_ptr<char[]> buffer;
+ QuicByteCount header_length =
+ encoder_.SerializeDataFrameHeader(body.length(), &buffer);
+ QuicString header = QuicString(buffer.get(), header_length);
+
+ header_length = encoder_.SerializeDataFrameHeader(body2.length(), &buffer);
+ QuicString header2 = QuicString(buffer.get(), header_length);
+
+ EXPECT_CALL(*mock_ack_listener,
+ OnPacketAcked(body.length() + body2.length(), _));
+ QuicStreamFrame frame(stream_->id(), true, 0,
+ header + body + header2 + body2);
+ EXPECT_TRUE(
+ session_->OnFrameAcked(QuicFrame(frame), QuicTime::Delta::Zero()));
+
+ EXPECT_TRUE(
+ QuicSpdyStreamPeer::unacked_frame_headers_offsets(stream_).Empty());
+}
+
+// HTTP/3 only.
+TEST_P(QuicSpdyStreamTest, HeaderBytesNotReportedOnRetransmission) {
+ Initialize(kShouldProcessData);
+ if (!HasFrameHeader()) {
+ return;
+ }
+ QuicReferenceCountedPointer<MockAckListener> mock_ack_listener(
+ new StrictMock<MockAckListener>);
+ stream_->set_ack_listener(mock_ack_listener);
+ QuicString body = "Test1";
+ QuicString body2(100, 'x');
+
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(AtLeast(1));
+ stream_->WriteOrBufferBody(body, false);
+ stream_->WriteOrBufferBody(body2, true);
+
+ std::unique_ptr<char[]> buffer;
+ QuicByteCount header_length =
+ encoder_.SerializeDataFrameHeader(body.length(), &buffer);
+ QuicString header = QuicString(buffer.get(), header_length);
+
+ header_length = encoder_.SerializeDataFrameHeader(body2.length(), &buffer);
+ QuicString header2 = QuicString(buffer.get(), header_length);
+
+ EXPECT_CALL(*mock_ack_listener, OnPacketRetransmitted(body.length()));
+ QuicStreamFrame frame(stream_->id(), false, 0, header + body);
+ session_->OnStreamFrameRetransmitted(frame);
+
+ EXPECT_CALL(*mock_ack_listener, OnPacketRetransmitted(body2.length()));
+ QuicStreamFrame frame2(stream_->id(), true, (header + body).length(),
+ header2 + body2);
+ session_->OnStreamFrameRetransmitted(frame2);
+
+ EXPECT_FALSE(
+ QuicSpdyStreamPeer::unacked_frame_headers_offsets(stream_).Empty());
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/quic/core/http/spdy_utils.cc b/quic/core/http/spdy_utils.cc
index d8fc79d..aa6d6e7 100644
--- a/quic/core/http/spdy_utils.cc
+++ b/quic/core/http/spdy_utils.cc
@@ -255,12 +255,12 @@
// Validate the scheme; this is to ensure a scheme of "foo://bar" is not
// parsed as a URL of "foo://bar://baz" when combined with a host of "baz".
std::string canonical_scheme;
- url::StdStringCanonOutput canon_output(&canonical_scheme);
+ url::StdStringCanonOutput canon_scheme_output(&canonical_scheme);
url::Component canon_component;
url::Component scheme_component(0, scheme.size());
- if (!url::CanonicalizeScheme(scheme.data(), scheme_component, &canon_output,
- &canon_component) ||
+ if (!url::CanonicalizeScheme(scheme.data(), scheme_component,
+ &canon_scheme_output, &canon_component) ||
!canon_component.is_nonempty() || canon_component.begin != 0) {
return QuicString();
}
@@ -304,13 +304,13 @@
}
}
- // Validate the host by attempting to canoncalize it. Invalid characters
+ // Validate the host by attempting to canonicalize it. Invalid characters
// will result in a canonicalization failure (e.g. '/')
std::string canon_host;
- canon_output = url::StdStringCanonOutput(&canon_host);
+ url::StdStringCanonOutput canon_host_output(&canon_host);
canon_component.reset();
- if (!url::CanonicalizeHost(authority.data(), host_component, &canon_output,
- &canon_component) ||
+ if (!url::CanonicalizeHost(authority.data(), host_component,
+ &canon_host_output, &canon_component) ||
!canon_component.is_nonempty() || canon_component.begin != 0) {
return QuicString();
}
diff --git a/quic/core/qpack/offline/qpack_offline_decoder_bin.cc b/quic/core/qpack/offline/qpack_offline_decoder_bin.cc
index 499c9fd..9d2be7c 100644
--- a/quic/core/qpack/offline/qpack_offline_decoder_bin.cc
+++ b/quic/core/qpack/offline/qpack_offline_decoder_bin.cc
@@ -12,18 +12,21 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
int main(int argc, char* argv[]) {
- InitGoogle(argv[0], &argc, &argv, false);
+ const char* usage =
+ "Usage: qpack_offline_decoder input_filename expected_headers_filename "
+ "....";
+ std::vector<quic::QuicString> args =
+ quic::QuicParseCommandLineFlags(usage, argc, argv);
- if (argc < 3 || argc % 2 != 1) {
- QUIC_LOG(ERROR) << "Usage: " << argv[0]
- << " input_filename expected_headers_filename ...";
+ if (args.size() < 2 || args.size() % 2 != 0) {
+ quic::QuicPrintCommandLineFlagHelp(usage);
return 1;
}
- int i;
- for (i = 0; 2 * i + 1 < argc; ++i) {
- const quic::QuicStringPiece input_filename(argv[2 * i + 1]);
- const quic::QuicStringPiece expected_headers_filename(argv[2 * i + 2]);
+ size_t i;
+ for (i = 0; 2 * i < args.size(); ++i) {
+ const quic::QuicStringPiece input_filename(args[2 * i]);
+ const quic::QuicStringPiece expected_headers_filename(args[2 * i + 1]);
// Every file represents a different connection,
// therefore every file needs a fresh decoding context.
diff --git a/quic/core/qpack/qpack_decoded_headers_accumulator.cc b/quic/core/qpack/qpack_decoded_headers_accumulator.cc
new file mode 100644
index 0000000..ac60fce
--- /dev/null
+++ b/quic/core/qpack/qpack_decoded_headers_accumulator.cc
@@ -0,0 +1,70 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.h"
+
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h"
+
+namespace quic {
+
+QpackDecodedHeadersAccumulator::QpackDecodedHeadersAccumulator(
+ QuicStreamId id,
+ QpackDecoder* qpack_decoder)
+ : decoder_(qpack_decoder->DecodeHeaderBlock(id, this)),
+ uncompressed_header_bytes_(0),
+ compressed_header_bytes_(0),
+ error_detected_(false) {
+ quic_header_list_.OnHeaderBlockStart();
+}
+
+void QpackDecodedHeadersAccumulator::OnHeaderDecoded(QuicStringPiece name,
+ QuicStringPiece value) {
+ DCHECK(!error_detected_);
+
+ uncompressed_header_bytes_ += name.size() + value.size();
+ quic_header_list_.OnHeader(name, value);
+}
+
+void QpackDecodedHeadersAccumulator::OnDecodingCompleted() {}
+
+void QpackDecodedHeadersAccumulator::OnDecodingErrorDetected(
+ QuicStringPiece error_message) {
+ DCHECK(!error_detected_);
+
+ error_detected_ = true;
+ // Copy error message to ensure it remains valid for the lifetime of |this|.
+ error_message_.assign(error_message.data(), error_message.size());
+}
+
+bool QpackDecodedHeadersAccumulator::Decode(QuicStringPiece data) {
+ DCHECK(!error_detected_);
+
+ compressed_header_bytes_ += data.size();
+ decoder_->Decode(data);
+
+ return !error_detected_;
+}
+
+bool QpackDecodedHeadersAccumulator::EndHeaderBlock() {
+ DCHECK(!error_detected_);
+
+ decoder_->EndHeaderBlock();
+
+ quic_header_list_.OnHeaderBlockEnd(uncompressed_header_bytes_,
+ compressed_header_bytes_);
+
+ return !error_detected_;
+}
+
+const QuicHeaderList& QpackDecodedHeadersAccumulator::quic_header_list() const {
+ DCHECK(!error_detected_);
+ return quic_header_list_;
+}
+
+QuicStringPiece QpackDecodedHeadersAccumulator::error_message() const {
+ DCHECK(error_detected_);
+ return error_message_;
+}
+
+} // namespace quic
diff --git a/quic/core/qpack/qpack_decoded_headers_accumulator.h b/quic/core/qpack/qpack_decoded_headers_accumulator.h
new file mode 100644
index 0000000..47d4f63
--- /dev/null
+++ b/quic/core/qpack/qpack_decoded_headers_accumulator.h
@@ -0,0 +1,64 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_CORE_QPACK_QPACK_DECODED_HEADERS_ACCUMULATOR_H_
+#define QUICHE_QUIC_CORE_QPACK_QPACK_DECODED_HEADERS_ACCUMULATOR_H_
+
+#include <cstddef>
+
+#include "net/third_party/quiche/src/quic/core/http/quic_header_list.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+
+namespace quic {
+
+class QpackDecoder;
+
+// A class that creates and owns a QpackProgressiveDecoder instance, accumulates
+// decoded headers in a QuicHeaderList, and keeps track of uncompressed and
+// compressed size so that it can be passed to QuicHeaderList::EndHeaderBlock().
+class QUIC_EXPORT_PRIVATE QpackDecodedHeadersAccumulator
+ : public QpackProgressiveDecoder::HeadersHandlerInterface {
+ public:
+ QpackDecodedHeadersAccumulator(QuicStreamId id, QpackDecoder* qpack_decoder);
+ virtual ~QpackDecodedHeadersAccumulator() = default;
+
+ // QpackProgressiveDecoder::HeadersHandlerInterface implementation.
+ // These methods should only be called by |decoder_|.
+ void OnHeaderDecoded(QuicStringPiece name, QuicStringPiece value) override;
+ void OnDecodingCompleted() override;
+ void OnDecodingErrorDetected(QuicStringPiece error_message) override;
+
+ // Decode payload data. Returns true on success, false on error.
+ // Must not be called if an error has been detected.
+ // Must not be called after EndHeaderBlock().
+ bool Decode(QuicStringPiece data);
+
+ // Signal end of HEADERS frame. Returns true on success, false on error.
+ // Must not be called if an error has been detected.
+ // Must not be called more that once.
+ bool EndHeaderBlock();
+
+ // Returns accumulated header list.
+ const QuicHeaderList& quic_header_list() const;
+
+ // Returns error message.
+ // Must not be called unless an error has been detected.
+ QuicStringPiece error_message() const;
+
+ private:
+ std::unique_ptr<QpackProgressiveDecoder> decoder_;
+ QuicHeaderList quic_header_list_;
+ size_t uncompressed_header_bytes_;
+ size_t compressed_header_bytes_;
+ bool error_detected_;
+ QuicString error_message_;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_CORE_QPACK_QPACK_DECODED_HEADERS_ACCUMULATOR_H_
diff --git a/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc b/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc
new file mode 100644
index 0000000..0c71b19
--- /dev/null
+++ b/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.h"
+
+#include <cstring>
+
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
+
+using ::testing::Eq;
+using ::testing::StrictMock;
+
+namespace quic {
+namespace test {
+namespace {
+
+QuicStreamId kTestStreamId = 1;
+
+// Header Acknowledgement decoder stream instruction with stream_id = 1.
+const char* const kHeaderAcknowledgement = "\x81";
+
+} // anonymous namespace
+
+class QpackDecodedHeadersAccumulatorTest : public QuicTest {
+ protected:
+ QpackDecodedHeadersAccumulatorTest()
+ : qpack_decoder_(&encoder_stream_error_delegate_,
+ &decoder_stream_sender_delegate_),
+ accumulator_(kTestStreamId, &qpack_decoder_) {}
+
+ NoopEncoderStreamErrorDelegate encoder_stream_error_delegate_;
+ StrictMock<MockDecoderStreamSenderDelegate> decoder_stream_sender_delegate_;
+ QpackDecoder qpack_decoder_;
+ QpackDecodedHeadersAccumulator accumulator_;
+};
+
+// HEADERS frame payload must have a complete Header Block Prefix.
+TEST_F(QpackDecodedHeadersAccumulatorTest, EmptyPayload) {
+ EXPECT_FALSE(accumulator_.EndHeaderBlock());
+ EXPECT_EQ("Incomplete header data prefix.", accumulator_.error_message());
+}
+
+// HEADERS frame payload must have a complete Header Block Prefix.
+TEST_F(QpackDecodedHeadersAccumulatorTest, TruncatedHeaderBlockPrefix) {
+ EXPECT_TRUE(accumulator_.Decode(QuicTextUtils::HexDecode("00")));
+ EXPECT_FALSE(accumulator_.EndHeaderBlock());
+ EXPECT_EQ("Incomplete header data prefix.", accumulator_.error_message());
+}
+
+TEST_F(QpackDecodedHeadersAccumulatorTest, EmptyHeaderList) {
+ EXPECT_CALL(decoder_stream_sender_delegate_,
+ WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
+
+ EXPECT_TRUE(accumulator_.Decode(QuicTextUtils::HexDecode("0000")));
+ EXPECT_TRUE(accumulator_.EndHeaderBlock());
+
+ EXPECT_TRUE(accumulator_.quic_header_list().empty());
+}
+
+// This payload is the prefix of a valid payload, but EndHeaderBlock() is called
+// before it can be completely decoded.
+TEST_F(QpackDecodedHeadersAccumulatorTest, TruncatedPayload) {
+ EXPECT_TRUE(accumulator_.Decode(QuicTextUtils::HexDecode("00002366")));
+ EXPECT_FALSE(accumulator_.EndHeaderBlock());
+ EXPECT_EQ("Incomplete header block.", accumulator_.error_message());
+}
+
+// This payload is invalid because it refers to a non-existing static entry.
+TEST_F(QpackDecodedHeadersAccumulatorTest, InvalidPayload) {
+ EXPECT_FALSE(accumulator_.Decode(QuicTextUtils::HexDecode("0000ff23ff24")));
+ EXPECT_EQ("Static table entry not found.", accumulator_.error_message());
+}
+
+TEST_F(QpackDecodedHeadersAccumulatorTest, Success) {
+ EXPECT_CALL(decoder_stream_sender_delegate_,
+ WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
+
+ QuicString encoded_data(QuicTextUtils::HexDecode("000023666f6f03626172"));
+ EXPECT_TRUE(accumulator_.Decode(encoded_data));
+ EXPECT_TRUE(accumulator_.EndHeaderBlock());
+
+ auto header_list = accumulator_.quic_header_list();
+ auto it = header_list.begin();
+ EXPECT_TRUE(it != header_list.end());
+ EXPECT_EQ("foo", it->first);
+ EXPECT_EQ("bar", it->second);
+ ++it;
+ EXPECT_TRUE(it == header_list.end());
+
+ EXPECT_EQ(strlen("foo") + strlen("bar"),
+ header_list.uncompressed_header_bytes());
+ EXPECT_EQ(encoded_data.size(), header_list.compressed_header_bytes());
+}
+
+} // namespace test
+} // namespace quic
diff --git a/quic/core/qpack/qpack_decoder_test.cc b/quic/core/qpack/qpack_decoder_test.cc
index 52f739c..7292c50 100644
--- a/quic/core/qpack/qpack_decoder_test.cc
+++ b/quic/core/qpack/qpack_decoder_test.cc
@@ -62,10 +62,8 @@
const FragmentMode fragment_mode_;
};
-INSTANTIATE_TEST_CASE_P(,
- QpackDecoderTest,
- Values(FragmentMode::kSingleChunk,
- FragmentMode::kOctetByOctet));
+INSTANTIATE_TEST_SUITE_P(, QpackDecoderTest, Values(FragmentMode::kSingleChunk,
+ FragmentMode::kOctetByOctet));
TEST_P(QpackDecoderTest, NoPrefix) {
EXPECT_CALL(handler_,
diff --git a/quic/core/qpack/qpack_decoder_test_utils.h b/quic/core/qpack/qpack_decoder_test_utils.h
index 937ecfc..ca5b608 100644
--- a/quic/core/qpack/qpack_decoder_test_utils.h
+++ b/quic/core/qpack/qpack_decoder_test_utils.h
@@ -96,9 +96,9 @@
public:
~NoOpHeadersHandler() override = default;
- void OnHeaderDecoded(QuicStringPiece name, QuicStringPiece value) override{};
- void OnDecodingCompleted() override{};
- void OnDecodingErrorDetected(QuicStringPiece error_message) override{};
+ void OnHeaderDecoded(QuicStringPiece name, QuicStringPiece value) override {}
+ void OnDecodingCompleted() override {}
+ void OnDecodingErrorDetected(QuicStringPiece error_message) override {}
};
void QpackDecode(
diff --git a/quic/core/qpack/qpack_encoder_test.cc b/quic/core/qpack/qpack_encoder_test.cc
index e3dba00..6dea968 100644
--- a/quic/core/qpack/qpack_encoder_test.cc
+++ b/quic/core/qpack/qpack_encoder_test.cc
@@ -37,10 +37,10 @@
const FragmentMode fragment_mode_;
};
-INSTANTIATE_TEST_CASE_P(,
- QpackEncoderTest,
- Values(FragmentMode::kSingleChunk,
- FragmentMode::kOctetByOctet));
+INSTANTIATE_TEST_SUITE_P(,
+ QpackEncoderTest,
+ Values(FragmentMode::kSingleChunk,
+ FragmentMode::kOctetByOctet));
TEST_P(QpackEncoderTest, Empty) {
spdy::SpdyHeaderBlock header_list;
diff --git a/quic/core/qpack/qpack_instruction_decoder_test.cc b/quic/core/qpack/qpack_instruction_decoder_test.cc
index d1fe9b5..08557ec 100644
--- a/quic/core/qpack/qpack_instruction_decoder_test.cc
+++ b/quic/core/qpack/qpack_instruction_decoder_test.cc
@@ -101,10 +101,10 @@
const FragmentMode fragment_mode_;
};
-INSTANTIATE_TEST_CASE_P(,
- QpackInstructionDecoderTest,
- Values(FragmentMode::kSingleChunk,
- FragmentMode::kOctetByOctet));
+INSTANTIATE_TEST_SUITE_P(,
+ QpackInstructionDecoderTest,
+ Values(FragmentMode::kSingleChunk,
+ FragmentMode::kOctetByOctet));
TEST_P(QpackInstructionDecoderTest, SBitAndVarint2) {
EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction1()));
diff --git a/quic/core/qpack/qpack_instruction_encoder_test.cc b/quic/core/qpack/qpack_instruction_encoder_test.cc
index 255520e..006476f 100644
--- a/quic/core/qpack/qpack_instruction_encoder_test.cc
+++ b/quic/core/qpack/qpack_instruction_encoder_test.cc
@@ -43,10 +43,10 @@
const FragmentMode fragment_mode_;
};
-INSTANTIATE_TEST_CASE_P(,
- QpackInstructionEncoderTest,
- Values(FragmentMode::kSingleChunk,
- FragmentMode::kOctetByOctet));
+INSTANTIATE_TEST_SUITE_P(,
+ QpackInstructionEncoderTest,
+ Values(FragmentMode::kSingleChunk,
+ FragmentMode::kOctetByOctet));
TEST_P(QpackInstructionEncoderTest, Varint) {
const QpackInstruction instruction{QpackInstructionOpcode{0x00, 0x80},
diff --git a/quic/core/qpack/qpack_round_trip_test.cc b/quic/core/qpack/qpack_round_trip_test.cc
index b9c6300..700ff85 100644
--- a/quic/core/qpack/qpack_round_trip_test.cc
+++ b/quic/core/qpack/qpack_round_trip_test.cc
@@ -56,7 +56,7 @@
const FragmentMode decoding_fragment_mode_;
};
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
,
QpackRoundTripTest,
Combine(Values(FragmentMode::kSingleChunk, FragmentMode::kOctetByOctet),
diff --git a/quic/core/quic_arena_scoped_ptr_test.cc b/quic/core/quic_arena_scoped_ptr_test.cc
index 52a8ae2..109fd37 100644
--- a/quic/core/quic_arena_scoped_ptr_test.cc
+++ b/quic/core/quic_arena_scoped_ptr_test.cc
@@ -42,10 +42,10 @@
QuicOneBlockArena<1024> arena_;
};
-INSTANTIATE_TEST_CASE_P(QuicArenaScopedPtrParamTest,
- QuicArenaScopedPtrParamTest,
- testing::Values(TestParam::kFromHeap,
- TestParam::kFromArena));
+INSTANTIATE_TEST_SUITE_P(QuicArenaScopedPtrParamTest,
+ QuicArenaScopedPtrParamTest,
+ testing::Values(TestParam::kFromHeap,
+ TestParam::kFromArena));
TEST_P(QuicArenaScopedPtrParamTest, NullObjects) {
QuicArenaScopedPtr<TestObject> def;
diff --git a/quic/core/quic_config.cc b/quic/core/quic_config.cc
index ce6f9ea..e53719c 100644
--- a/quic/core/quic_config.cc
+++ b/quic/core/quic_config.cc
@@ -14,6 +14,7 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_macros.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
@@ -492,7 +493,7 @@
}
// TODO(ianswett) Use this for silent close on mobile, or delete.
-ABSL_ATTRIBUTE_UNUSED void QuicConfig::SetSilentClose(bool silent_close) {
+QUIC_UNUSED void QuicConfig::SetSilentClose(bool silent_close) {
silent_close_.set(silent_close ? 1 : 0, silent_close ? 1 : 0);
}
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index d4c13c4..6346ae0 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -26,6 +26,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/platform/api/quic_bug_tracker.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_error_code_wrappers.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_exported_stats.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"
@@ -43,10 +44,6 @@
namespace {
-// Maximum number of acks received before sending an ack in response.
-// TODO(fayang): Remove this constant when deprecating QUIC_VERSION_35.
-const QuicPacketCount kMaxPacketsReceivedBeforeAckSend = 20;
-
// Maximum number of consecutive sent nonretransmittable packets.
const QuicPacketCount kMaxConsecutiveNonRetransmittablePackets = 19;
@@ -63,10 +60,6 @@
// One eighth RTT delay when doing ack decimation.
const float kShortAckDecimationDelay = 0.125;
-// Error code used in WriteResult to indicate that the packet writer rejected
-// the message as being too big.
-const int kMessageTooBigErrorCode = EMSGSIZE;
-
// The minimum release time into future in ms.
const int kMinReleaseTimeIntoFutureMs = 1;
@@ -338,9 +331,7 @@
processing_ack_frame_(false),
supports_release_time_(false),
release_time_into_future_(QuicTime::Delta::Zero()),
- no_version_negotiation_(supported_versions.size() == 1),
- clear_probing_mark_after_packet_processing_(GetQuicReloadableFlag(
- quic_clear_probing_mark_after_packet_processing)) {
+ no_version_negotiation_(supported_versions.size() == 1) {
if (ack_mode_ == ACK_DECIMATION) {
QUIC_RELOADABLE_FLAG_COUNT(quic_enable_ack_decimation);
}
@@ -466,8 +457,7 @@
if (config.HasClientSentConnectionOption(k5RTO, perspective_)) {
close_connection_after_five_rtos_ = true;
}
- if (transport_version() != QUIC_VERSION_35 &&
- config.HasClientSentConnectionOption(kNSTP, perspective_)) {
+ if (config.HasClientSentConnectionOption(kNSTP, perspective_)) {
no_stop_waiting_frames_ = true;
}
if (config.HasReceivedStatelessResetToken()) {
@@ -688,6 +678,7 @@
server_supported_versions_ = packet.versions;
if (GetQuicReloadableFlag(quic_no_client_conn_ver_negotiation)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_no_client_conn_ver_negotiation);
CloseConnection(
QUIC_INVALID_VERSION,
QuicStrCat(
@@ -815,6 +806,10 @@
if (level == ENCRYPTION_FORWARD_SECURE &&
perspective_ == Perspective::IS_SERVER) {
sent_packet_manager_.SetHandshakeConfirmed();
+ if (sent_packet_manager_.unacked_packets().use_uber_loss_algorithm()) {
+ // This may have changed the retransmission timer, so re-arm it.
+ SetRetransmissionAlarm();
+ }
}
}
@@ -909,11 +904,11 @@
return false;
}
- QUIC_BUG << ENDPOINT
- << "Received an unencrypted data frame: closing connection"
- << " packet_number:" << last_header_.packet_number
- << " stream_id:" << frame.stream_id
- << " received_packets:" << received_packet_manager_.ack_frame();
+ QUIC_PEER_BUG << ENDPOINT
+ << "Received an unencrypted data frame: closing connection"
+ << " packet_number:" << last_header_.packet_number
+ << " stream_id:" << frame.stream_id << " received_packets:"
+ << received_packet_manager_.ack_frame();
CloseConnection(QUIC_UNENCRYPTED_STREAM_DATA,
"Unencrypted stream data seen.",
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
@@ -926,8 +921,15 @@
}
bool QuicConnection::OnCryptoFrame(const QuicCryptoFrame& frame) {
- // TODO(nharper): Implement.
- return false;
+ DCHECK(connected_);
+
+ // Since a CRYPTO frame was received, this is not a connectivity probe.
+ // A probe only contains a PING and full padding.
+ UpdatePacketContent(NOT_PADDED_PING);
+
+ visitor_->OnCryptoFrame(frame);
+ should_last_packet_instigate_acks_ = true;
+ return connected_;
}
bool QuicConnection::OnAckFrameStart(QuicPacketNumber largest_acked,
@@ -1335,7 +1337,8 @@
if (debug_visitor_ != nullptr) {
debug_visitor_->OnMessageFrame(frame);
}
- visitor_->OnMessageReceived(frame.message_data);
+ visitor_->OnMessageReceived(
+ QuicStringPiece(frame.data, frame.message_length));
should_last_packet_instigate_acks_ = true;
return connected_;
}
@@ -1454,14 +1457,6 @@
void QuicConnection::MaybeQueueAck(bool was_missing) {
++num_packets_received_since_last_ack_sent_;
- // Always send an ack every 20 packets in order to allow the peer to discard
- // information from the SentPacketManager and provide an RTT measurement.
- if (transport_version() == QUIC_VERSION_35 &&
- num_packets_received_since_last_ack_sent_ >=
- kMaxPacketsReceivedBeforeAckSend) {
- ack_queued_ = true;
- }
-
// Determine whether the newly received packet was missing before recording
// the received packet.
if (was_missing) {
@@ -1478,10 +1473,9 @@
if (should_last_packet_instigate_acks_ && !ack_queued_) {
++num_retransmittable_packets_received_since_last_ack_sent_;
if (ack_mode_ != TCP_ACKING &&
- // TODO(fayang): Fix this as this check assumes the first received
- // packet is 1.
- last_header_.packet_number >
- QuicPacketNumber(min_received_before_ack_decimation_)) {
+ last_header_.packet_number >=
+ received_packet_manager_.PeerFirstSendingPacketNumber() +
+ min_received_before_ack_decimation_) {
// Ack up to 10 packets at once unless ack decimation is unlimited.
if (!unlimited_ack_decimation_ &&
num_retransmittable_packets_received_since_last_ack_sent_ >=
@@ -1566,7 +1560,9 @@
sent_packet_manager_.GetLeastUnacked() + max_tracked_packets_) {
CloseConnection(
QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS,
- QuicStrCat("More than ", max_tracked_packets_, " outstanding."),
+ QuicStrCat("More than ", max_tracked_packets_,
+ " outstanding, least_unacked: ",
+ sent_packet_manager_.GetLeastUnacked().ToUint64()),
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
}
}
@@ -1648,6 +1644,18 @@
pending_version_negotiation_packet_ = false;
}
+size_t QuicConnection::SendCryptoData(EncryptionLevel level,
+ size_t write_length,
+ QuicStreamOffset offset) {
+ if (write_length == 0) {
+ QUIC_BUG << "Attempt to send empty crypto frame";
+ return 0;
+ }
+
+ ScopedPacketFlusher flusher(this, SEND_ACK_IF_PENDING);
+ return packet_generator_.ConsumeCryptoData(level, write_length, offset);
+}
+
QuicConsumedData QuicConnection::SendStreamData(QuicStreamId id,
size_t write_length,
QuicStreamOffset offset,
@@ -1746,6 +1754,10 @@
return stats_;
}
+void QuicConnection::OnCoalescedPacket(const QuicEncryptedPacket& packet) {
+ QueueCoalescedPacket(packet);
+}
+
void QuicConnection::ProcessUdpPacket(const QuicSocketAddress& self_address,
const QuicSocketAddress& peer_address,
const QuicReceivedPacket& packet) {
@@ -1813,13 +1825,9 @@
<< "Unable to process packet. Last packet processed: "
<< last_header_.packet_number;
current_packet_data_ = nullptr;
- if (clear_probing_mark_after_packet_processing_) {
- if (is_current_packet_connectivity_probing_) {
- QUIC_RELOADABLE_FLAG_COUNT_N(
- quic_clear_probing_mark_after_packet_processing, 1, 2);
- }
- is_current_packet_connectivity_probing_ = false;
- }
+ is_current_packet_connectivity_probing_ = false;
+
+ MaybeProcessCoalescedPackets();
return;
}
@@ -1840,17 +1848,12 @@
}
}
+ MaybeProcessCoalescedPackets();
MaybeProcessUndecryptablePackets();
MaybeSendInResponseToPacket();
SetPingAlarm();
current_packet_data_ = nullptr;
- if (clear_probing_mark_after_packet_processing_) {
- if (is_current_packet_connectivity_probing_) {
- QUIC_RELOADABLE_FLAG_COUNT_N(
- quic_clear_probing_mark_after_packet_processing, 2, 2);
- }
- is_current_packet_connectivity_probing_ = false;
- }
+ is_current_packet_connectivity_probing_ = false;
}
void QuicConnection::OnBlockedWriterCanWrite() {
@@ -1965,16 +1968,17 @@
// Count those that would have been accepted if FLAGS..random_ipn
// were true -- to detect/diagnose potential issues prior to
// enabling the flag.
- if ((header.packet_number > QuicPacketNumber(1)) &&
- (header.packet_number <= MaxRandomInitialPacketNumber())) {
+ if (header.packet_number >
+ received_packet_manager_.PeerFirstSendingPacketNumber() &&
+ header.packet_number <= MaxRandomInitialPacketNumber()) {
QUIC_CODE_COUNT_N(had_possibly_random_ipn, 2, 2);
}
bool out_of_bound =
last_header_.packet_number.IsInitialized()
? !Near(header.packet_number, last_header_.packet_number)
- // TODO(fayang): Fix this as this check assume the first received
- // packet is 1.
- : header.packet_number > QuicPacketNumber(kMaxPacketGap);
+ : header.packet_number >=
+ (received_packet_manager_.PeerFirstSendingPacketNumber() +
+ kMaxPacketGap);
if (out_of_bound) {
QUIC_DLOG(INFO) << ENDPOINT << "Packet " << header.packet_number
<< " out of bounds. Discarding";
@@ -2390,8 +2394,7 @@
bool QuicConnection::IsMsgTooBig(const WriteResult& result) {
return (result.status == WRITE_STATUS_MSG_TOO_BIG) ||
- (IsWriteError(result.status) &&
- result.error_code == kMessageTooBigErrorCode);
+ (IsWriteError(result.status) && result.error_code == QUIC_EMSGSIZE);
}
bool QuicConnection::ShouldDiscardPacket(const SerializedPacket& packet) {
@@ -2426,7 +2429,7 @@
"Write failed with error: ", error_code, " (", strerror(error_code), ")");
QUIC_LOG_FIRST_N(ERROR, 2) << ENDPOINT << error_details;
switch (error_code) {
- case kMessageTooBigErrorCode:
+ case QUIC_EMSGSIZE:
CloseConnection(
QUIC_PACKET_WRITE_ERROR, error_details,
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET_WITH_NO_ACK);
@@ -2469,15 +2472,13 @@
return;
}
- if (transport_version() != QUIC_VERSION_35) {
- if (serialized_packet->retransmittable_frames.empty() &&
- !serialized_packet->original_packet_number.IsInitialized()) {
- // 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;
- }
+ if (serialized_packet->retransmittable_frames.empty() &&
+ !serialized_packet->original_packet_number.IsInitialized()) {
+ // 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);
}
@@ -2519,6 +2520,10 @@
void QuicConnection::OnHandshakeComplete() {
sent_packet_manager_.SetHandshakeConfirmed();
+ if (sent_packet_manager_.unacked_packets().use_uber_loss_algorithm()) {
+ // This may have changed the retransmission timer, so re-arm it.
+ SetRetransmissionAlarm();
+ }
// The client should immediately ack the SHLO to confirm the handshake is
// complete with the server.
if (perspective_ == Perspective::IS_CLIENT && !ack_queued_ &&
@@ -2712,6 +2717,44 @@
}
}
+void QuicConnection::QueueCoalescedPacket(const QuicEncryptedPacket& packet) {
+ QUIC_DVLOG(1) << ENDPOINT << "Queueing coalesced packet.";
+ coalesced_packets_.push_back(packet.Clone());
+}
+
+void QuicConnection::MaybeProcessCoalescedPackets() {
+ bool processed = false;
+ for (const auto& packet : coalesced_packets_) {
+ if (!connected_) {
+ return;
+ }
+
+ // }
+ // while (connected_ && !coalesced_packets_.empty()) {
+ QUIC_DVLOG(1) << ENDPOINT << "Processing coalesced packet";
+ // QuicEncryptedPacket* packet = coalesced_packets_.front().get();
+ if (framer_.ProcessPacket(*packet)) {
+ processed = true;
+ } else {
+ // If we are unable to decrypt this packet, it might be
+ // because the CHLO or SHLO packet was lost.
+ if (framer_.error() == QUIC_DECRYPTION_FAILURE) {
+ if (encryption_level_ != ENCRYPTION_FORWARD_SECURE &&
+ undecryptable_packets_.size() < max_undecryptable_packets_) {
+ QueueUndecryptablePacket(*packet);
+ } else if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnUndecryptablePacket();
+ }
+ }
+ }
+ // coalesced_packets_.pop_front();
+ }
+ coalesced_packets_.clear();
+ if (processed) {
+ MaybeProcessUndecryptablePackets();
+ }
+}
+
void QuicConnection::CloseConnection(
QuicErrorCode error,
const QuicString& error_details,
@@ -3088,9 +3131,7 @@
return true;
}
if (save_crypto_packets_as_termination_packets_ &&
- frame.type == STREAM_FRAME &&
- frame.stream_frame.stream_id ==
- QuicUtils::GetCryptoStreamId(transport_version())) {
+ QuicUtils::IsHandshakeFrame(frame, transport_version())) {
return true;
}
}
@@ -3535,13 +3576,13 @@
}
MessageStatus QuicConnection::SendMessage(QuicMessageId message_id,
- QuicStringPiece message) {
+ QuicMemSliceSpan message) {
if (transport_version() <= QUIC_VERSION_44) {
QUIC_BUG << "MESSAGE frame is not supported for version "
<< transport_version();
return MESSAGE_STATUS_UNSUPPORTED;
}
- if (message.length() > GetLargestMessagePayload()) {
+ if (message.total_length() > GetLargestMessagePayload()) {
return MESSAGE_STATUS_TOO_LARGE;
}
if (!CanWrite(HAS_RETRANSMITTABLE_DATA)) {
diff --git a/quic/core/quic_connection.h b/quic/core/quic_connection.h
index 221754f..d27d0b7 100644
--- a/quic/core/quic_connection.h
+++ b/quic/core/quic_connection.h
@@ -96,6 +96,9 @@
// A simple visitor interface for dealing with a data frame.
virtual void OnStreamFrame(const QuicStreamFrame& frame) = 0;
+ // Called when a CRYPTO frame containing handshake data is received.
+ virtual void OnCryptoFrame(const QuicCryptoFrame& frame) = 0;
+
// The session should process the WINDOW_UPDATE frame, adjusting both stream
// and connection level flow control windows.
virtual void OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) = 0;
@@ -231,9 +234,6 @@
// Called when a StreamFrame has been parsed.
virtual void OnStreamFrame(const QuicStreamFrame& frame) {}
- // Called when a AckFrame has been parsed.
- virtual void OnAckFrame(const QuicAckFrame& frame) {}
-
// Called when a StopWaitingFrame has been parsed.
virtual void OnStopWaitingFrame(const QuicStopWaitingFrame& frame) {}
@@ -380,6 +380,13 @@
// Sets the number of active streams on the connection for congestion control.
void SetNumOpenStreams(size_t num_streams);
+ // Sends crypto handshake messages of length |write_length| to the peer in as
+ // few packets as possible. Returns the number of bytes consumed from the
+ // data.
+ virtual size_t SendCryptoData(EncryptionLevel level,
+ size_t write_length,
+ QuicStreamOffset offset);
+
// Send the data of length |write_length| to the peer in as few packets as
// possible. Returns the number of bytes consumed from data, and a boolean
// indicating if the fin bit was consumed. This does not indicate the data
@@ -479,6 +486,7 @@
bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override;
void OnDecryptedPacket(EncryptionLevel level) override;
bool OnPacketHeader(const QuicPacketHeader& header) override;
+ void OnCoalescedPacket(const QuicEncryptedPacket& packet) override;
bool OnStreamFrame(const QuicStreamFrame& frame) override;
bool OnCryptoFrame(const QuicCryptoFrame& frame) override;
bool OnAckFrameStart(QuicPacketNumber largest_acked,
@@ -748,7 +756,7 @@
// Tries to send |message| and returns the message status.
virtual MessageStatus SendMessage(QuicMessageId message_id,
- QuicStringPiece message);
+ QuicMemSliceSpan message);
// Returns the largest payload that will fit into a single MESSAGE frame.
QuicPacketLength GetLargestMessagePayload() const;
@@ -847,6 +855,12 @@
// Attempts to process any queued undecryptable packets.
void MaybeProcessUndecryptablePackets();
+ // Queue a coalesced packet.
+ void QueueCoalescedPacket(const QuicEncryptedPacket& packet);
+
+ // Process previously queued coalesced packets.
+ void MaybeProcessCoalescedPackets();
+
enum PacketContent : uint8_t {
NO_FRAMES_RECEIVED,
// TODO(fkastenholz): Change name when we get rid of padded ping/
@@ -1156,6 +1170,10 @@
// sent with the INITIAL encryption and the CHLO message was lost.
QuicDeque<std::unique_ptr<QuicEncryptedPacket>> undecryptable_packets_;
+ // Collection of coalesced packets which were received while processing
+ // the current packet.
+ QuicDeque<std::unique_ptr<QuicEncryptedPacket>> coalesced_packets_;
+
// Maximum number of undecryptable packets the connection will store.
size_t max_undecryptable_packets_;
@@ -1400,9 +1418,6 @@
// provided in constructor.
const bool no_version_negotiation_;
- // Latched value of --quic_clear_probing_mark_after_packet_processing.
- const bool clear_probing_mark_after_packet_processing_;
-
// Payload of most recently transmitted QUIC_VERSION_99 connectivity
// probe packet (the PATH_CHALLENGE payload). This implementation transmits
// only one PATH_CHALLENGE per connectivity probe, so only one
diff --git a/quic/core/quic_connection_id.cc b/quic/core/quic_connection_id.cc
index a86a5dd..25c5b1f 100644
--- a/quic/core/quic_connection_id.cc
+++ b/quic/core/quic_connection_id.cc
@@ -19,18 +19,9 @@
namespace quic {
-QuicConnectionId::QuicConnectionId() {
- if (!QuicConnectionIdUseNetworkByteOrder()) {
- id64_ = 0;
- length_ = sizeof(uint64_t);
- return;
- }
- length_ = 0;
-}
+QuicConnectionId::QuicConnectionId() : length_(0) {}
QuicConnectionId::QuicConnectionId(const char* data, uint8_t length) {
- QUIC_BUG_IF(!QuicConnectionIdUseNetworkByteOrder())
- << "new constructor called when flag disabled";
if (length > kQuicMaxConnectionIdLength) {
QUIC_BUG << "Attempted to create connection ID of length " << length;
length = kQuicMaxConnectionIdLength;
@@ -39,48 +30,15 @@
if (length_ > 0) {
memcpy(data_, data, length_);
}
- QUIC_RESTART_FLAG_COUNT_N(quic_variable_length_connection_ids_server, 2, 3);
-}
-
-QuicConnectionId::QuicConnectionId(uint64_t connection_id64)
- : length_(sizeof(uint64_t)) {
- if (!QuicConnectionIdUseNetworkByteOrder()) {
- id64_ = connection_id64;
- return;
- }
- QUIC_BUG_IF(QuicConnectionIdSupportsVariableLength(Perspective::IS_CLIENT) &&
- QuicConnectionIdSupportsVariableLength(Perspective::IS_SERVER))
- << "old constructor called when flag enabled";
- const uint64_t connection_id64_net = QuicEndian::HostToNet64(connection_id64);
- memcpy(&data_, &connection_id64_net, sizeof(connection_id64_net));
}
QuicConnectionId::~QuicConnectionId() {}
-uint64_t QuicConnectionId::ToUInt64() const {
- if (!QuicConnectionIdUseNetworkByteOrder()) {
- return id64_;
- }
- QUIC_BUG_IF(QuicConnectionIdSupportsVariableLength(Perspective::IS_CLIENT) &&
- QuicConnectionIdSupportsVariableLength(Perspective::IS_SERVER))
- << "ToUInt64 called when flag enabled";
- uint64_t connection_id64_net = 0;
- memcpy(&connection_id64_net, &data_,
- std::min<size_t>(static_cast<size_t>(length_),
- sizeof(connection_id64_net)));
- return QuicEndian::NetToHost64(connection_id64_net);
-}
-
const char* QuicConnectionId::data() const {
- QUIC_BUG_IF(!QuicConnectionIdUseNetworkByteOrder())
- << "data called when flag disabled";
- QUIC_RESTART_FLAG_COUNT_N(quic_variable_length_connection_ids_server, 3, 3);
return data_;
}
char* QuicConnectionId::mutable_data() {
- QUIC_BUG_IF(!QuicConnectionIdUseNetworkByteOrder())
- << "mutable_data called when flag disabled";
return data_;
}
@@ -89,35 +47,24 @@
}
void QuicConnectionId::set_length(uint8_t length) {
- QUIC_BUG_IF(!QuicConnectionIdUseNetworkByteOrder())
- << "set_length called when flag disabled";
length_ = length;
}
bool QuicConnectionId::IsEmpty() const {
- if (!QuicConnectionIdUseNetworkByteOrder()) {
- return id64_ == 0;
- }
return length_ == 0;
}
size_t QuicConnectionId::Hash() const {
- if (!QuicConnectionIdUseNetworkByteOrder()) {
- return id64_;
- }
uint64_t data_bytes[3] = {0, 0, 0};
static_assert(sizeof(data_bytes) >= sizeof(data_), "sizeof(data_) changed");
memcpy(data_bytes, data_, length_);
- // This Hash function is designed to return the same value
- // as ToUInt64() when the connection ID length is 64 bits.
+ // This Hash function is designed to return the same value as the host byte
+ // order representation when the connection ID length is 64 bits.
return QuicEndian::NetToHost64(kQuicDefaultConnectionIdLength ^ length_ ^
data_bytes[0] ^ data_bytes[1] ^ data_bytes[2]);
}
QuicString QuicConnectionId::ToString() const {
- if (!QuicConnectionIdUseNetworkByteOrder()) {
- return QuicTextUtils::Uint64ToString(id64_);
- }
if (IsEmpty()) {
return QuicString("0");
}
@@ -130,9 +77,6 @@
}
bool QuicConnectionId::operator==(const QuicConnectionId& v) const {
- if (!QuicConnectionIdUseNetworkByteOrder()) {
- return id64_ == v.id64_;
- }
return length_ == v.length_ && memcmp(data_, v.data_, length_) == 0;
}
@@ -141,9 +85,6 @@
}
bool QuicConnectionId::operator<(const QuicConnectionId& v) const {
- if (!QuicConnectionIdUseNetworkByteOrder()) {
- return id64_ < v.id64_;
- }
if (length_ < v.length_) {
return true;
}
@@ -157,42 +98,6 @@
return QuicConnectionId();
}
-QuicConnectionId QuicConnectionIdFromUInt64(uint64_t connection_id64) {
- return QuicConnectionId(connection_id64);
-}
-
-uint64_t QuicConnectionIdToUInt64(QuicConnectionId connection_id) {
- return connection_id.ToUInt64();
-}
-
-bool QuicConnectionIdUseNetworkByteOrder() {
- const bool res = GetQuicRestartFlag(quic_connection_ids_network_byte_order);
- if (res) {
- QUIC_RESTART_FLAG_COUNT(quic_connection_ids_network_byte_order);
- }
- return res;
-}
-
-bool QuicConnectionIdSupportsVariableLength(Perspective perspective) {
- if (!QuicConnectionIdUseNetworkByteOrder()) {
- return false;
- }
- bool res;
- if (perspective == Perspective::IS_SERVER) {
- res = GetQuicRestartFlag(quic_variable_length_connection_ids_server);
- if (res) {
- QUIC_RESTART_FLAG_COUNT_N(quic_variable_length_connection_ids_server, 1,
- 3);
- }
- } else {
- res = GetQuicRestartFlag(quic_variable_length_connection_ids_client);
- if (res) {
- QUIC_RESTART_FLAG_COUNT(quic_variable_length_connection_ids_client);
- }
- }
- return res;
-}
-
static_assert(kQuicDefaultConnectionIdLength == sizeof(uint64_t),
"kQuicDefaultConnectionIdLength changed");
static_assert(kQuicDefaultConnectionIdLength == PACKET_8BYTE_CONNECTION_ID,
diff --git a/quic/core/quic_connection_id.h b/quic/core/quic_connection_id.h
index 5df72ec..06fecfb 100644
--- a/quic/core/quic_connection_id.h
+++ b/quic/core/quic_connection_id.h
@@ -25,17 +25,12 @@
class QUIC_EXPORT_PRIVATE QuicConnectionId {
public:
- // Creates a connection ID of length zero, unless the restart flag
- // quic_connection_ids_network_byte_order is false in which case
- // it returns an 8-byte all-zeroes connection ID.
+ // Creates a connection ID of length zero.
QuicConnectionId();
// Creates a connection ID from network order bytes.
QuicConnectionId(const char* data, uint8_t length);
- // Creator from host byte order uint64_t.
- explicit QuicConnectionId(uint64_t connection_id64);
-
~QuicConnectionId();
// Returns the length of the connection ID, in bytes.
@@ -51,14 +46,9 @@
// in network byte order.
char* mutable_data();
- // Returns whether the connection ID has length zero, unless the restart flag
- // quic_connection_ids_network_byte_order is false in which case
- // it checks if it is all zeroes.
+ // Returns whether the connection ID has length zero.
bool IsEmpty() const;
- // Converts to host byte order uint64_t.
- uint64_t ToUInt64() const;
-
// Hash() is required to use connection IDs as keys in hash tables.
size_t Hash() const;
@@ -77,11 +67,10 @@
bool operator<(const QuicConnectionId& v) const;
private:
- // The connection ID is currently represented in host byte order in |id64_|.
- // In the future, it will be saved in the first |length_| bytes of |data_|.
+ // The connection ID is represented in network byte order
+ // in the first |length_| bytes of |data_|.
char data_[kQuicMaxConnectionIdLength];
uint8_t length_;
- uint64_t id64_; // host byte order
};
// Creates a connection ID of length zero, unless the restart flag
@@ -89,16 +78,6 @@
// it returns an 8-byte all-zeroes connection ID.
QUIC_EXPORT_PRIVATE QuicConnectionId EmptyQuicConnectionId();
-// Converts connection ID from host-byte-order uint64_t to QuicConnectionId.
-// This is currently the identity function.
-QUIC_EXPORT_PRIVATE QuicConnectionId
-QuicConnectionIdFromUInt64(uint64_t connection_id64);
-
-// Converts connection ID from QuicConnectionId to host-byte-order uint64_t.
-// This is currently the identity function.
-QUIC_EXPORT_PRIVATE uint64_t
-QuicConnectionIdToUInt64(QuicConnectionId connection_id);
-
// QuicConnectionIdHash can be passed as hash argument to hash tables.
class QuicConnectionIdHash {
public:
@@ -107,16 +86,6 @@
}
};
-// Governs how connection IDs are represented in memory.
-// Checks gfe_restart_flag_quic_connection_ids_network_byte_order.
-QUIC_EXPORT_PRIVATE bool QuicConnectionIdUseNetworkByteOrder();
-
-enum class Perspective : uint8_t;
-// Governs how connection IDs are created.
-// Checks gfe_restart_flag_quic_variable_length_connection_ids_(client|server).
-QUIC_EXPORT_PRIVATE bool QuicConnectionIdSupportsVariableLength(
- Perspective perspective);
-
} // namespace quic
#endif // QUICHE_QUIC_CORE_QUIC_CONNECTION_ID_H_
diff --git a/quic/core/quic_connection_id_test.cc b/quic/core/quic_connection_id_test.cc
index 017e59e..1c7c761 100644
--- a/quic/core/quic_connection_id_test.cc
+++ b/quic/core/quic_connection_id_test.cc
@@ -37,18 +37,10 @@
TEST_F(QuicConnectionIdTest, ZeroIsNotEmpty) {
QuicConnectionId connection_id = test::TestConnectionId(0);
- if (!GetQuicRestartFlag(quic_connection_ids_network_byte_order)) {
- // Zero is empty when connection IDs are represented in host byte order.
- return;
- }
EXPECT_FALSE(connection_id.IsEmpty());
}
TEST_F(QuicConnectionIdTest, Data) {
- if (!GetQuicRestartFlag(quic_connection_ids_network_byte_order)) {
- // These methods are not allowed when the flag is off.
- return;
- }
char connection_id_data[kQuicDefaultConnectionIdLength];
memset(connection_id_data, 0x42, sizeof(connection_id_data));
QuicConnectionId connection_id1 =
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index fe851fd..c56d2c1 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -19,6 +19,7 @@
#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/platform/api/quic_error_code_wrappers.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_logging.h"
@@ -102,8 +103,7 @@
bool SetIV(QuicStringPiece iv) override { return true; }
- bool EncryptPacket(QuicTransportVersion /*version*/,
- uint64_t packet_number,
+ bool EncryptPacket(uint64_t packet_number,
QuicStringPiece associated_data,
QuicStringPiece plaintext,
char* output,
@@ -167,8 +167,7 @@
return true;
}
- bool DecryptPacket(QuicTransportVersion /*version*/,
- uint64_t packet_number,
+ bool DecryptPacket(uint64_t packet_number,
QuicStringPiece associated_data,
QuicStringPiece ciphertext,
char* output,
@@ -332,10 +331,10 @@
}
if (next_packet_too_large_) {
next_packet_too_large_ = false;
- return WriteResult(WRITE_STATUS_ERROR, EMSGSIZE);
+ return WriteResult(WRITE_STATUS_ERROR, QUIC_EMSGSIZE);
}
if (always_get_packet_too_large_) {
- return WriteResult(WRITE_STATUS_ERROR, EMSGSIZE);
+ return WriteResult(WRITE_STATUS_ERROR, QUIC_EMSGSIZE);
}
if (IsWriteBlocked()) {
return WriteResult(is_write_blocked_data_buffered_
@@ -357,10 +356,6 @@
return WriteResult(WRITE_STATUS_OK, last_packet_size_);
}
- bool IsWriteBlockedDataBuffered() const override {
- return is_write_blocked_data_buffered_;
- }
-
bool ShouldWriteFail() { return write_should_fail_; }
bool IsWriteBlocked() const override { return write_blocked_; }
@@ -433,6 +428,10 @@
return framer_.stream_frames();
}
+ const std::vector<std::unique_ptr<QuicCryptoFrame>>& crypto_frames() const {
+ return framer_.crypto_frames();
+ }
+
const std::vector<QuicPingFrame>& ping_frames() const {
return framer_.ping_frames();
}
@@ -643,8 +642,23 @@
// split needlessly across packet boundaries). As a result, we have separate
// tests for some cases for this stream.
QuicConsumedData SendCryptoStreamData() {
- return SendStreamDataWithString(
- QuicUtils::GetCryptoStreamId(transport_version()), "chlo", 0, NO_FIN);
+ QuicStreamOffset offset = 0;
+ QuicStringPiece data("chlo");
+ if (transport_version() < QUIC_VERSION_47) {
+ return SendStreamDataWithString(
+ QuicUtils::GetCryptoStreamId(transport_version()), data, offset,
+ NO_FIN);
+ }
+ producer_.SaveCryptoData(ENCRYPTION_NONE, offset, data);
+ size_t bytes_written;
+ if (notifier_) {
+ bytes_written =
+ notifier_->WriteCryptoData(ENCRYPTION_NONE, data.length(), offset);
+ } else {
+ bytes_written = QuicConnection::SendCryptoData(ENCRYPTION_NONE,
+ data.length(), offset);
+ }
+ return QuicConsumedData(bytes_written, /*fin_consumed*/ false);
}
void set_version(ParsedQuicVersion version) {
@@ -987,7 +1001,7 @@
QuicPacketCreatorPeer::FillPacketHeader(&peer_creator_, &header);
char encrypted_buffer[kMaxPacketSize];
size_t length = peer_framer_.BuildDataPacket(
- header, frames, encrypted_buffer, kMaxPacketSize);
+ header, frames, encrypted_buffer, kMaxPacketSize, ENCRYPTION_NONE);
DCHECK_GT(length, 0u);
const size_t encrypted_length = peer_framer_.EncryptInPlace(
@@ -1135,7 +1149,7 @@
QuicStopWaitingFrame* frame,
EncryptionLevel level) {
return ProcessFramePacketAtLevel(number, QuicFrame(frame),
- ENCRYPTION_INITIAL);
+ ENCRYPTION_ZERO_RTT);
}
void ProcessGoAwayPacket(QuicGoAwayFrame* frame) {
@@ -1336,9 +1350,9 @@
};
// Run all end to end tests with all supported versions.
-INSTANTIATE_TEST_CASE_P(SupportedVersion,
- QuicConnectionTest,
- ::testing::ValuesIn(GetTestParams()));
+INSTANTIATE_TEST_SUITE_P(SupportedVersion,
+ QuicConnectionTest,
+ ::testing::ValuesIn(GetTestParams()));
TEST_P(QuicConnectionTest, SelfAddressChangeAtClient) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
@@ -1621,9 +1635,6 @@
connection_.GetStats().num_connectivity_probing_received;
ProcessReceivedPacket(kSelfAddress, kPeerAddress, *received);
- if (!GetQuicReloadableFlag(quic_clear_probing_mark_after_packet_processing)) {
- EXPECT_FALSE(connection_.IsCurrentPacketConnectivityProbing());
- }
EXPECT_EQ(num_probing_received,
connection_.GetStats().num_connectivity_probing_received);
EXPECT_EQ(kPeerAddress, connection_.peer_address());
@@ -1723,9 +1734,6 @@
connection_.GetStats().num_connectivity_probing_received;
ProcessReceivedPacket(kSelfAddress, kNewPeerAddress, *received);
- if (!GetQuicReloadableFlag(quic_clear_probing_mark_after_packet_processing)) {
- EXPECT_TRUE(connection_.IsCurrentPacketConnectivityProbing());
- }
EXPECT_EQ(num_probing_received + 1,
connection_.GetStats().num_connectivity_probing_received);
EXPECT_EQ(kPeerAddress, connection_.peer_address());
@@ -1786,9 +1794,6 @@
connection_.GetStats().num_connectivity_probing_received;
ProcessReceivedPacket(kSelfAddress, kNewPeerAddress, *received);
- if (!GetQuicReloadableFlag(quic_clear_probing_mark_after_packet_processing)) {
- EXPECT_TRUE(connection_.IsCurrentPacketConnectivityProbing());
- }
EXPECT_EQ(num_probing_received + 1,
connection_.GetStats().num_connectivity_probing_received);
EXPECT_EQ(kPeerAddress, connection_.peer_address());
@@ -1881,9 +1886,6 @@
connection_.GetStats().num_connectivity_probing_received;
ProcessReceivedPacket(kSelfAddress, kPeerAddress, *received);
- if (!GetQuicReloadableFlag(quic_clear_probing_mark_after_packet_processing)) {
- EXPECT_FALSE(connection_.IsCurrentPacketConnectivityProbing());
- }
EXPECT_EQ(num_probing_received,
connection_.GetStats().num_connectivity_probing_received);
EXPECT_EQ(kPeerAddress, connection_.peer_address());
@@ -1929,9 +1931,6 @@
connection_.GetStats().num_connectivity_probing_received;
ProcessReceivedPacket(kNewSelfAddress, kPeerAddress, *received);
- if (!GetQuicReloadableFlag(quic_clear_probing_mark_after_packet_processing)) {
- EXPECT_TRUE(connection_.IsCurrentPacketConnectivityProbing());
- }
EXPECT_EQ(num_probing_received + 1,
connection_.GetStats().num_connectivity_probing_received);
EXPECT_EQ(kPeerAddress, connection_.peer_address());
@@ -1995,6 +1994,13 @@
header.version_flag = true;
header.packet_number = QuicPacketNumber(1);
+ if (QuicVersionHasLongHeaderLengths(
+ peer_framer_.version().transport_version)) {
+ header.long_packet_type = INITIAL;
+ header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1;
+ header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2;
+ }
+
QuicFrames frames;
QuicPaddingFrame padding;
frames.push_back(QuicFrame(frame1_));
@@ -2028,6 +2034,13 @@
header.version_flag = true;
header.packet_number = QuicPacketNumber(1);
+ if (QuicVersionHasLongHeaderLengths(
+ peer_framer_.version().transport_version)) {
+ header.long_packet_type = INITIAL;
+ header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1;
+ header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2;
+ }
+
QuicFrames frames;
QuicPaddingFrame padding;
frames.push_back(QuicFrame(frame1_));
@@ -2192,20 +2205,38 @@
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessPacket(3);
- // Should ack immediately since we have missing packets.
- EXPECT_EQ(1u, writer_->packets_write_attempts());
+ if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) {
+ // Should not cause an ack.
+ EXPECT_EQ(0u, writer_->packets_write_attempts());
+ } else {
+ // Should ack immediately since we have missing packets.
+ EXPECT_EQ(1u, writer_->packets_write_attempts());
+ }
ProcessPacket(2);
- // Should ack immediately since we have missing packets.
- EXPECT_EQ(2u, writer_->packets_write_attempts());
+ if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) {
+ // Should ack immediately, since this fills the last hole.
+ EXPECT_EQ(1u, writer_->packets_write_attempts());
+ } else {
+ // Should ack immediately since we have missing packets.
+ EXPECT_EQ(2u, writer_->packets_write_attempts());
+ }
ProcessPacket(1);
// Should ack immediately, since this fills the last hole.
- EXPECT_EQ(3u, writer_->packets_write_attempts());
+ if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) {
+ EXPECT_EQ(2u, writer_->packets_write_attempts());
+ } else {
+ EXPECT_EQ(3u, writer_->packets_write_attempts());
+ }
ProcessPacket(4);
// Should not cause an ack.
- EXPECT_EQ(3u, writer_->packets_write_attempts());
+ if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) {
+ EXPECT_EQ(2u, writer_->packets_write_attempts());
+ } else {
+ EXPECT_EQ(3u, writer_->packets_write_attempts());
+ }
}
TEST_P(QuicConnectionTest, OutOfOrderAckReceiptCausesNoAck) {
@@ -2293,33 +2324,7 @@
ProcessAckPacket(&frame2);
}
-TEST_P(QuicConnectionTest, 20AcksCausesAckSend) {
- if (connection_.version().transport_version != QUIC_VERSION_35) {
- return;
- }
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- SendStreamDataToPeer(1, "foo", 0, NO_FIN, nullptr);
-
- QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_);
- // But an ack with no missing packets will not send an ack.
- QuicAckFrame frame = InitAckFrame(1);
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
- for (int i = 0; i < 19; ++i) {
- ProcessAckPacket(&frame);
- EXPECT_FALSE(ack_alarm->IsSet());
- }
- EXPECT_EQ(1u, writer_->packets_write_attempts());
- // The 20th ack packet will cause an ack to be sent.
- ProcessAckPacket(&frame);
- EXPECT_EQ(2u, writer_->packets_write_attempts());
-}
-
TEST_P(QuicConnectionTest, AckSentEveryNthPacket) {
- if (connection_.version().transport_version == QUIC_VERSION_35) {
- return;
- }
-
connection_.set_ack_frequency_before_ack_decimation(3);
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
@@ -2363,10 +2368,6 @@
}
TEST_P(QuicConnectionTest, AckNeedsRetransmittableFrames) {
- if (connection_.version().transport_version == QUIC_VERSION_35) {
- return;
- }
-
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(99);
@@ -2676,10 +2677,14 @@
// Parse the last packet and ensure it's the crypto stream frame.
EXPECT_EQ(2u, writer_->frame_count());
- ASSERT_EQ(1u, writer_->stream_frames().size());
ASSERT_EQ(1u, writer_->padding_frames().size());
- EXPECT_EQ(QuicUtils::GetCryptoStreamId(connection_.transport_version()),
- writer_->stream_frames()[0]->stream_id);
+ if (connection_.transport_version() < QUIC_VERSION_47) {
+ ASSERT_EQ(1u, writer_->stream_frames().size());
+ EXPECT_EQ(QuicUtils::GetCryptoStreamId(connection_.transport_version()),
+ writer_->stream_frames()[0]->stream_id);
+ } else {
+ EXPECT_EQ(1u, writer_->crypto_frames().size());
+ }
}
TEST_P(QuicConnectionTest, FramePackingCryptoThenNonCrypto) {
@@ -3574,9 +3579,9 @@
NO_FIN, nullptr);
EXPECT_EQ(0x01010101u, writer_->final_bytes_of_last_packet());
- connection_.SetEncrypter(ENCRYPTION_INITIAL,
+ connection_.SetEncrypter(ENCRYPTION_ZERO_RTT,
QuicMakeUnique<TaggingEncrypter>(0x02));
- connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
SendStreamDataToPeer(3, "foo", 0, NO_FIN, nullptr);
EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet());
@@ -3594,7 +3599,7 @@
// Packet should have been sent with ENCRYPTION_NONE.
EXPECT_EQ(0x01010101u, writer_->final_bytes_of_previous_packet());
- // Packet should have been sent with ENCRYPTION_INITIAL.
+ // Packet should have been sent with ENCRYPTION_ZERO_RTT.
EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet());
}
@@ -3615,9 +3620,9 @@
EXPECT_EQ(1u, connection_.NumQueuedPackets());
// Switch to the new encrypter.
- connection_.SetEncrypter(ENCRYPTION_INITIAL,
+ connection_.SetEncrypter(ENCRYPTION_ZERO_RTT,
QuicMakeUnique<TaggingEncrypter>(0x02));
- connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
// Now become writeable and flush the packets.
writer_->SetWritable();
@@ -3635,9 +3640,7 @@
connection_.SetEncrypter(ENCRYPTION_NONE,
QuicMakeUnique<TaggingEncrypter>(0x01));
QuicPacketNumber packet_number;
- SendStreamDataToPeer(
- QuicUtils::GetCryptoStreamId(connection_.transport_version()), "foo", 0,
- NO_FIN, &packet_number);
+ connection_.SendCryptoStreamData();
// Simulate the retransmission alarm firing and the socket blocking.
BlockOnNextWrite();
@@ -3668,9 +3671,9 @@
QuicUtils::GetCryptoStreamId(connection_.transport_version()), "foo", 0,
NO_FIN, nullptr);
- connection_.SetEncrypter(ENCRYPTION_INITIAL,
+ connection_.SetEncrypter(ENCRYPTION_ZERO_RTT,
QuicMakeUnique<TaggingEncrypter>(0x02));
- connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
SendStreamDataToPeer(2, "bar", 0, NO_FIN, nullptr);
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
@@ -3687,27 +3690,27 @@
use_tagging_decrypter();
const uint8_t tag = 0x07;
- peer_framer_.SetEncrypter(ENCRYPTION_INITIAL,
+ peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT,
QuicMakeUnique<TaggingEncrypter>(tag));
// Process an encrypted packet which can not yet be decrypted which should
// result in the packet being buffered.
- ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_INITIAL);
+ ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
// Transition to the new encryption state and process another encrypted packet
// which should result in the original packet being processed.
- connection_.SetDecrypter(ENCRYPTION_INITIAL,
+ connection_.SetDecrypter(ENCRYPTION_ZERO_RTT,
QuicMakeUnique<StrictTaggingDecrypter>(tag));
- connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
- connection_.SetEncrypter(ENCRYPTION_INITIAL,
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
+ connection_.SetEncrypter(ENCRYPTION_ZERO_RTT,
QuicMakeUnique<TaggingEncrypter>(tag));
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(2);
- ProcessDataPacketAtLevel(2, !kHasStopWaiting, ENCRYPTION_INITIAL);
+ ProcessDataPacketAtLevel(2, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
// Finally, process a third packet and note that we do not reprocess the
// buffered packet.
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(3, !kHasStopWaiting, ENCRYPTION_INITIAL);
+ ProcessDataPacketAtLevel(3, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
}
TEST_P(QuicConnectionTest, TestRetransmitOrder) {
@@ -3752,23 +3755,23 @@
use_tagging_decrypter();
const uint8_t tag = 0x07;
- peer_framer_.SetEncrypter(ENCRYPTION_INITIAL,
+ peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT,
QuicMakeUnique<TaggingEncrypter>(tag));
// Process an encrypted packet which can not yet be decrypted which should
// result in the packet being buffered.
for (uint64_t i = 1; i <= 100; ++i) {
- ProcessDataPacketAtLevel(i, !kHasStopWaiting, ENCRYPTION_INITIAL);
+ ProcessDataPacketAtLevel(i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
}
// Transition to the new encryption state and process another encrypted packet
// which should result in the original packets being processed.
EXPECT_FALSE(connection_.GetProcessUndecryptablePacketsAlarm()->IsSet());
- connection_.SetDecrypter(ENCRYPTION_INITIAL,
+ connection_.SetDecrypter(ENCRYPTION_ZERO_RTT,
QuicMakeUnique<StrictTaggingDecrypter>(tag));
EXPECT_TRUE(connection_.GetProcessUndecryptablePacketsAlarm()->IsSet());
- connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
- connection_.SetEncrypter(ENCRYPTION_INITIAL,
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
+ connection_.SetEncrypter(ENCRYPTION_ZERO_RTT,
QuicMakeUnique<TaggingEncrypter>(tag));
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(100);
@@ -3777,7 +3780,7 @@
// Finally, process a third packet and note that we do not reprocess the
// buffered packet.
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(102, !kHasStopWaiting, ENCRYPTION_INITIAL);
+ ProcessDataPacketAtLevel(102, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
}
TEST_P(QuicConnectionTest, SetRTOAfterWritingToSocket) {
@@ -4932,7 +4935,9 @@
connection_.version().transport_version, kIncludeVersion,
!kIncludeDiversificationNonce, PACKET_8BYTE_CONNECTION_ID,
PACKET_0BYTE_CONNECTION_ID,
- QuicPacketCreatorPeer::GetPacketNumberLength(creator_), &payload_length);
+ QuicPacketCreatorPeer::GetPacketNumberLength(creator_),
+ QuicPacketCreatorPeer::GetRetryTokenLengthLength(creator_),
+ QuicPacketCreatorPeer::GetLengthLength(creator_), &payload_length);
connection_.SetMaxPacketLength(length);
// Queue the first packet.
@@ -4959,7 +4964,9 @@
connection_.version().transport_version, kIncludeVersion,
!kIncludeDiversificationNonce, PACKET_8BYTE_CONNECTION_ID,
PACKET_0BYTE_CONNECTION_ID,
- QuicPacketCreatorPeer::GetPacketNumberLength(creator_), &payload_length);
+ QuicPacketCreatorPeer::GetPacketNumberLength(creator_),
+ QuicPacketCreatorPeer::GetRetryTokenLengthLength(creator_),
+ QuicPacketCreatorPeer::GetLengthLength(creator_), &payload_length);
// GetPacketLengthForOneStream() assumes a stream offset of 0 in determining
// packet length. The size of the offset field in a stream frame is
// 0 for offset 0, and 2 for non-zero offsets up through 16K (for
@@ -5049,17 +5056,17 @@
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
const uint8_t tag = 0x07;
- connection_.SetDecrypter(ENCRYPTION_INITIAL,
+ connection_.SetDecrypter(ENCRYPTION_ZERO_RTT,
QuicMakeUnique<StrictTaggingDecrypter>(tag));
- peer_framer_.SetEncrypter(ENCRYPTION_INITIAL,
+ peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT,
QuicMakeUnique<TaggingEncrypter>(tag));
// Process a packet from the non-crypto stream.
frame1_.stream_id = 3;
- // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used
+ // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used
// instead of ENCRYPTION_NONE.
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_INITIAL);
+ ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
// Check if delayed ack timer is running for the expected interval.
EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
@@ -5087,17 +5094,17 @@
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
const uint8_t tag = 0x07;
- connection_.SetDecrypter(ENCRYPTION_INITIAL,
+ connection_.SetDecrypter(ENCRYPTION_ZERO_RTT,
QuicMakeUnique<StrictTaggingDecrypter>(tag));
- peer_framer_.SetEncrypter(ENCRYPTION_INITIAL,
+ peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT,
QuicMakeUnique<TaggingEncrypter>(tag));
// Process a packet from the non-crypto stream.
frame1_.stream_id = 3;
- // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used
+ // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used
// instead of ENCRYPTION_NONE.
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_INITIAL);
+ ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
// Check if delayed ack timer is running for the expected interval.
EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
@@ -5119,7 +5126,7 @@
// ack alarm to be set delayed ack time in the future.
ack_time = clock_.ApproximateNow() + DefaultDelayedAckTime();
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(2, !kHasStopWaiting, ENCRYPTION_INITIAL);
+ ProcessDataPacketAtLevel(2, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
// Check if delayed ack timer is running for the expected interval.
EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
@@ -5141,7 +5148,7 @@
clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1);
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(3, !kHasStopWaiting, ENCRYPTION_INITIAL);
+ ProcessDataPacketAtLevel(3, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
// Check if delayed ack timer is running for the expected interval.
EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
@@ -5163,9 +5170,9 @@
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
const uint8_t tag = 0x07;
- connection_.SetDecrypter(ENCRYPTION_INITIAL,
+ connection_.SetDecrypter(ENCRYPTION_ZERO_RTT,
QuicMakeUnique<StrictTaggingDecrypter>(tag));
- peer_framer_.SetEncrypter(ENCRYPTION_INITIAL,
+ peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT,
QuicMakeUnique<TaggingEncrypter>(tag));
// Process a packet from the non-crypto stream.
frame1_.stream_id = 3;
@@ -5174,14 +5181,14 @@
uint64_t kFirstDecimatedPacket = 101;
for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL);
+ ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
}
EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
- // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used
+ // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used
// instead of ENCRYPTION_NONE.
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(kFirstDecimatedPacket, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
+ ENCRYPTION_ZERO_RTT);
// Check if delayed ack timer is running for the expected interval.
EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
@@ -5192,7 +5199,7 @@
EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
+ ENCRYPTION_ZERO_RTT);
}
// Check that ack is sent and that delayed ack alarm is reset.
if (GetParam().no_stop_waiting) {
@@ -5222,17 +5229,17 @@
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
const uint8_t tag = 0x07;
- connection_.SetDecrypter(ENCRYPTION_INITIAL,
+ connection_.SetDecrypter(ENCRYPTION_ZERO_RTT,
QuicMakeUnique<StrictTaggingDecrypter>(tag));
- peer_framer_.SetEncrypter(ENCRYPTION_INITIAL,
+ peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT,
QuicMakeUnique<TaggingEncrypter>(tag));
// Process a packet from the non-crypto stream.
frame1_.stream_id = 3;
- // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used
+ // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used
// instead of ENCRYPTION_NONE.
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_INITIAL);
+ ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
// Check if delayed ack timer is running for the expected interval.
EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
@@ -5254,7 +5261,7 @@
// ack alarm to be set delayed ack time in the future.
ack_time = clock_.ApproximateNow() + DefaultDelayedAckTime();
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(2, !kHasStopWaiting, ENCRYPTION_INITIAL);
+ ProcessDataPacketAtLevel(2, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
// Check if delayed ack timer is running for the expected interval.
EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
@@ -5276,7 +5283,7 @@
clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1);
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(3, !kHasStopWaiting, ENCRYPTION_INITIAL);
+ ProcessDataPacketAtLevel(3, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
// Check if delayed ack timer is running for the expected interval.
EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
@@ -5290,14 +5297,14 @@
uint64_t kFirstDecimatedPacket = 101;
for (unsigned int i = 0; i < kFirstDecimatedPacket - 4; ++i) {
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(4 + i, !kHasStopWaiting, ENCRYPTION_INITIAL);
+ ProcessDataPacketAtLevel(4 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
}
EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
- // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used
+ // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used
// instead of ENCRYPTION_NONE.
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(kFirstDecimatedPacket, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
+ ENCRYPTION_ZERO_RTT);
// Check if delayed ack timer is running for the expected interval.
EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
@@ -5308,7 +5315,7 @@
EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
+ ENCRYPTION_ZERO_RTT);
}
// Check that ack is sent and that delayed ack alarm is reset.
if (GetParam().no_stop_waiting) {
@@ -5326,7 +5333,7 @@
ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1);
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(kFirstDecimatedPacket + 10, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
+ ENCRYPTION_ZERO_RTT);
// Check if delayed ack timer is running for the expected interval.
EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
@@ -5355,9 +5362,9 @@
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
const uint8_t tag = 0x07;
- connection_.SetDecrypter(ENCRYPTION_INITIAL,
+ connection_.SetDecrypter(ENCRYPTION_ZERO_RTT,
QuicMakeUnique<StrictTaggingDecrypter>(tag));
- peer_framer_.SetEncrypter(ENCRYPTION_INITIAL,
+ peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT,
QuicMakeUnique<TaggingEncrypter>(tag));
// Process a packet from the non-crypto stream.
frame1_.stream_id = 3;
@@ -5366,14 +5373,14 @@
uint64_t kFirstDecimatedPacket = 101;
for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL);
+ ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
}
EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
- // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used
+ // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used
// instead of ENCRYPTION_NONE.
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(kFirstDecimatedPacket, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
+ ENCRYPTION_ZERO_RTT);
// Check if delayed ack timer is running for the expected interval.
EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
@@ -5385,7 +5392,7 @@
EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
+ ENCRYPTION_ZERO_RTT);
}
// The delayed ack timer should still be set to the expected deadline.
EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
@@ -5408,9 +5415,9 @@
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
const uint8_t tag = 0x07;
- connection_.SetDecrypter(ENCRYPTION_INITIAL,
+ connection_.SetDecrypter(ENCRYPTION_ZERO_RTT,
QuicMakeUnique<StrictTaggingDecrypter>(tag));
- peer_framer_.SetEncrypter(ENCRYPTION_INITIAL,
+ peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT,
QuicMakeUnique<TaggingEncrypter>(tag));
// Process a packet from the non-crypto stream.
frame1_.stream_id = 3;
@@ -5419,14 +5426,14 @@
uint64_t kFirstDecimatedPacket = 101;
for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL);
+ ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
}
EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
- // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used
+ // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used
// instead of ENCRYPTION_NONE.
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(kFirstDecimatedPacket, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
+ ENCRYPTION_ZERO_RTT);
// Check if delayed ack timer is running for the expected interval.
EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
@@ -5437,7 +5444,7 @@
EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
+ ENCRYPTION_ZERO_RTT);
}
// Check that ack is sent and that delayed ack alarm is reset.
if (GetParam().no_stop_waiting) {
@@ -5471,9 +5478,9 @@
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
const uint8_t tag = 0x07;
- connection_.SetDecrypter(ENCRYPTION_INITIAL,
+ connection_.SetDecrypter(ENCRYPTION_ZERO_RTT,
QuicMakeUnique<StrictTaggingDecrypter>(tag));
- peer_framer_.SetEncrypter(ENCRYPTION_INITIAL,
+ peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT,
QuicMakeUnique<TaggingEncrypter>(tag));
// Process a packet from the non-crypto stream.
frame1_.stream_id = 3;
@@ -5482,7 +5489,7 @@
uint64_t kFirstDecimatedPacket = 101;
for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL);
+ ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
}
EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
@@ -5492,7 +5499,7 @@
// Process packet 10 first and ensure the alarm is one eighth min_rtt.
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(kFirstDecimatedPacket + 9 + (j * 11),
- !kHasStopWaiting, ENCRYPTION_INITIAL);
+ !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5);
EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
@@ -5505,7 +5512,7 @@
// The ACK shouldn't be sent until the 10th packet is processed.
EXPECT_TRUE(writer_->ack_frames().empty());
ProcessDataPacketAtLevel(kFirstDecimatedPacket + i + (j * 11),
- !kHasStopWaiting, ENCRYPTION_INITIAL);
+ !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
}
// Check that ack is sent and that delayed ack alarm is reset.
if (GetParam().no_stop_waiting) {
@@ -5540,9 +5547,9 @@
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
const uint8_t tag = 0x07;
- connection_.SetDecrypter(ENCRYPTION_INITIAL,
+ connection_.SetDecrypter(ENCRYPTION_ZERO_RTT,
QuicMakeUnique<StrictTaggingDecrypter>(tag));
- peer_framer_.SetEncrypter(ENCRYPTION_INITIAL,
+ peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT,
QuicMakeUnique<TaggingEncrypter>(tag));
// Process a packet from the non-crypto stream.
frame1_.stream_id = 3;
@@ -5551,14 +5558,14 @@
uint64_t kFirstDecimatedPacket = 101;
for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL);
+ ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
}
EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
- // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used
+ // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used
// instead of ENCRYPTION_NONE.
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(kFirstDecimatedPacket, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
+ ENCRYPTION_ZERO_RTT);
// Check if delayed ack timer is running for the expected interval.
EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
@@ -5567,7 +5574,7 @@
// Process packet 10 first and ensure the alarm is one eighth min_rtt.
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(kFirstDecimatedPacket + 19, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
+ ENCRYPTION_ZERO_RTT);
ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5);
EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
@@ -5577,7 +5584,7 @@
EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
+ ENCRYPTION_ZERO_RTT);
}
// Check that ack is sent and that delayed ack alarm is reset.
if (GetParam().no_stop_waiting) {
@@ -5595,7 +5602,7 @@
EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(kFirstDecimatedPacket + 10, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
+ ENCRYPTION_ZERO_RTT);
// Check that ack is sent and that delayed ack alarm is reset.
if (GetParam().no_stop_waiting) {
EXPECT_EQ(1u, writer_->frame_count());
@@ -5629,9 +5636,9 @@
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
const uint8_t tag = 0x07;
- connection_.SetDecrypter(ENCRYPTION_INITIAL,
+ connection_.SetDecrypter(ENCRYPTION_ZERO_RTT,
QuicMakeUnique<StrictTaggingDecrypter>(tag));
- peer_framer_.SetEncrypter(ENCRYPTION_INITIAL,
+ peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT,
QuicMakeUnique<TaggingEncrypter>(tag));
// Process a packet from the non-crypto stream.
frame1_.stream_id = 3;
@@ -5640,14 +5647,14 @@
uint64_t kFirstDecimatedPacket = 101;
for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL);
+ ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
}
EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
- // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used
+ // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used
// instead of ENCRYPTION_NONE.
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(kFirstDecimatedPacket, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
+ ENCRYPTION_ZERO_RTT);
// Check if delayed ack timer is running for the expected interval.
EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
@@ -5656,7 +5663,7 @@
// Process packet 10 first and ensure the alarm is one eighth min_rtt.
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(kFirstDecimatedPacket + 9, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
+ ENCRYPTION_ZERO_RTT);
ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5);
EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
@@ -5666,7 +5673,7 @@
EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
+ ENCRYPTION_ZERO_RTT);
}
// Check that ack is sent and that delayed ack alarm is reset.
if (GetParam().no_stop_waiting) {
@@ -5702,9 +5709,9 @@
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
const uint8_t tag = 0x07;
- connection_.SetDecrypter(ENCRYPTION_INITIAL,
+ connection_.SetDecrypter(ENCRYPTION_ZERO_RTT,
QuicMakeUnique<StrictTaggingDecrypter>(tag));
- peer_framer_.SetEncrypter(ENCRYPTION_INITIAL,
+ peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT,
QuicMakeUnique<TaggingEncrypter>(tag));
// Process a packet from the non-crypto stream.
frame1_.stream_id = 3;
@@ -5713,14 +5720,14 @@
uint64_t kFirstDecimatedPacket = 101;
for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL);
+ ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
}
EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
- // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used
+ // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used
// instead of ENCRYPTION_NONE.
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(kFirstDecimatedPacket, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
+ ENCRYPTION_ZERO_RTT);
// Check if delayed ack timer is running for the expected interval.
EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
@@ -5729,7 +5736,7 @@
// Process packet 10 first and ensure the alarm is one eighth min_rtt.
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(kFirstDecimatedPacket + 19, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
+ ENCRYPTION_ZERO_RTT);
ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5);
EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
@@ -5739,7 +5746,7 @@
EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
+ ENCRYPTION_ZERO_RTT);
}
// Check that ack is sent and that delayed ack alarm is reset.
if (GetParam().no_stop_waiting) {
@@ -5757,7 +5764,7 @@
EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
ProcessDataPacketAtLevel(kFirstDecimatedPacket + 10, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
+ ENCRYPTION_ZERO_RTT);
// Check that ack is sent and that delayed ack alarm is reset.
if (GetParam().no_stop_waiting) {
EXPECT_EQ(1u, writer_->frame_count());
@@ -5810,23 +5817,46 @@
TEST_P(QuicConnectionTest, NoAckOnOldNacks) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
// Drop one packet, triggering a sequence of acks.
+ if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ } else {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ }
ProcessPacket(2);
size_t frames_per_ack = GetParam().no_stop_waiting ? 1 : 2;
- EXPECT_EQ(frames_per_ack, writer_->frame_count());
- EXPECT_FALSE(writer_->ack_frames().empty());
- writer_->Reset();
+ if (!GetQuicRestartFlag(quic_enable_accept_random_ipn)) {
+ EXPECT_EQ(frames_per_ack, writer_->frame_count());
+ EXPECT_FALSE(writer_->ack_frames().empty());
+ writer_->Reset();
+ }
+
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
ProcessPacket(3);
EXPECT_EQ(frames_per_ack, writer_->frame_count());
EXPECT_FALSE(writer_->ack_frames().empty());
writer_->Reset();
+
+ if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ } else {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ }
ProcessPacket(4);
- EXPECT_EQ(frames_per_ack, writer_->frame_count());
- EXPECT_FALSE(writer_->ack_frames().empty());
- writer_->Reset();
+ if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) {
+ EXPECT_EQ(0u, writer_->frame_count());
+ } else {
+ EXPECT_EQ(frames_per_ack, writer_->frame_count());
+ EXPECT_FALSE(writer_->ack_frames().empty());
+ writer_->Reset();
+ }
+
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
ProcessPacket(5);
EXPECT_EQ(frames_per_ack, writer_->frame_count());
EXPECT_FALSE(writer_->ack_frames().empty());
writer_->Reset();
+
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
// Now only set the timer on the 6th packet, instead of sending another ack.
ProcessPacket(6);
EXPECT_EQ(0u, writer_->frame_count());
@@ -5904,7 +5934,11 @@
EXPECT_EQ(4u, writer_->frame_count());
EXPECT_FALSE(writer_->stop_waiting_frames().empty());
}
- EXPECT_EQ(1u, writer_->stream_frames().size());
+ if (connection_.transport_version() < QUIC_VERSION_47) {
+ EXPECT_EQ(1u, writer_->stream_frames().size());
+ } else {
+ EXPECT_EQ(1u, writer_->crypto_frames().size());
+ }
EXPECT_EQ(1u, writer_->padding_frames().size());
ASSERT_FALSE(writer_->ack_frames().empty());
EXPECT_EQ(QuicPacketNumber(2u), LargestAcked(writer_->ack_frames().front()));
@@ -5933,7 +5967,11 @@
EXPECT_EQ(4u, writer_->frame_count());
EXPECT_FALSE(writer_->stop_waiting_frames().empty());
}
- EXPECT_EQ(1u, writer_->stream_frames().size());
+ if (connection_.transport_version() < QUIC_VERSION_47) {
+ EXPECT_EQ(1u, writer_->stream_frames().size());
+ } else {
+ EXPECT_EQ(1u, writer_->crypto_frames().size());
+ }
EXPECT_EQ(1u, writer_->padding_frames().size());
ASSERT_FALSE(writer_->ack_frames().empty());
EXPECT_EQ(QuicPacketNumber(2u), LargestAcked(writer_->ack_frames().front()));
@@ -6214,6 +6252,13 @@
header.version_flag = true;
header.packet_number = QuicPacketNumber(12);
+ if (QuicVersionHasLongHeaderLengths(
+ peer_framer_.version().transport_version)) {
+ header.long_packet_type = INITIAL;
+ header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1;
+ header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2;
+ }
+
QuicFrames frames;
frames.push_back(QuicFrame(frame1_));
std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
@@ -6259,6 +6304,13 @@
header.version_flag = true;
header.packet_number = QuicPacketNumber(12);
+ if (QuicVersionHasLongHeaderLengths(
+ peer_framer_.version().transport_version)) {
+ header.long_packet_type = INITIAL;
+ header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1;
+ header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2;
+ }
+
QuicFrames frames;
frames.push_back(QuicFrame(frame1_));
std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
@@ -6311,6 +6363,13 @@
header.version_flag = true;
header.packet_number = QuicPacketNumber(12);
+ if (QuicVersionHasLongHeaderLengths(
+ peer_framer_.version().transport_version)) {
+ header.long_packet_type = INITIAL;
+ header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1;
+ header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2;
+ }
+
QuicFrames frames;
frames.push_back(QuicFrame(frame1_));
std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
@@ -7586,6 +7645,7 @@
}
QuicString message(connection_.GetLargestMessagePayload() * 2, 'a');
QuicStringPiece message_data(message);
+ QuicMemSliceStorage storage(nullptr, 0, nullptr, 0);
{
QuicConnection::ScopedPacketFlusher flusher(&connection_,
QuicConnection::SEND_ACK);
@@ -7594,22 +7654,32 @@
// get sent, one contains stream frame, and the other only contains the
// message frame.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
- EXPECT_EQ(MESSAGE_STATUS_SUCCESS,
- connection_.SendMessage(
- 1, QuicStringPiece(message_data.data(),
- connection_.GetLargestMessagePayload())));
+ EXPECT_EQ(
+ MESSAGE_STATUS_SUCCESS,
+ connection_.SendMessage(
+ 1, MakeSpan(connection_.helper()->GetStreamSendBufferAllocator(),
+ QuicStringPiece(message_data.data(),
+ connection_.GetLargestMessagePayload()),
+ &storage)));
}
// Fail to send a message if connection is congestion control blocked.
EXPECT_CALL(*send_algorithm_, CanSend(_)).WillOnce(Return(false));
- EXPECT_EQ(MESSAGE_STATUS_BLOCKED, connection_.SendMessage(2, "message"));
+ EXPECT_EQ(
+ MESSAGE_STATUS_BLOCKED,
+ connection_.SendMessage(
+ 2, MakeSpan(connection_.helper()->GetStreamSendBufferAllocator(),
+ "message", &storage)));
// Always fail to send a message which cannot fit into one packet.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
EXPECT_EQ(
MESSAGE_STATUS_TOO_LARGE,
connection_.SendMessage(
- 3, QuicStringPiece(message_data.data(),
- connection_.GetLargestMessagePayload() + 1)));
+ 3,
+ MakeSpan(connection_.helper()->GetStreamSendBufferAllocator(),
+ QuicStringPiece(message_data.data(),
+ connection_.GetLargestMessagePayload() + 1),
+ &storage)));
}
// Test to check that the path challenge/path response logic works
diff --git a/quic/core/quic_control_frame_manager.cc b/quic/core/quic_control_frame_manager.cc
index c2b5192..8d4ba53 100644
--- a/quic/core/quic_control_frame_manager.cc
+++ b/quic/core/quic_control_frame_manager.cc
@@ -88,25 +88,6 @@
new QuicStopSendingFrame(++last_control_frame_id_, stream_id, code)));
}
-void QuicControlFrameManager::WriteOrBufferRstStreamStopSending(
- QuicStreamId stream_id,
- QuicRstStreamErrorCode error_code,
- QuicStreamOffset bytes_written) {
- const bool had_buffered_frames = HasBufferedFrames();
- QUIC_DVLOG(1) << "Queuing RST_STREAM_FRAME";
- control_frames_.emplace_back(QuicFrame(new QuicRstStreamFrame(
- ++last_control_frame_id_, stream_id, error_code, bytes_written)));
- if (session_->connection()->transport_version() == QUIC_VERSION_99) {
- QUIC_DVLOG(1) << "Version 99, Queuing STOP_SENDING";
- control_frames_.emplace_back(QuicFrame(new QuicStopSendingFrame(
- ++last_control_frame_id_, stream_id, error_code)));
- }
- if (had_buffered_frames) {
- return;
- }
- WriteBufferedFrames();
-}
-
void QuicControlFrameManager::WritePing() {
QUIC_DVLOG(1) << "Writing PING_FRAME";
if (HasBufferedFrames()) {
diff --git a/quic/core/quic_control_frame_manager.h b/quic/core/quic_control_frame_manager.h
index ace08c6..618f3f9 100644
--- a/quic/core/quic_control_frame_manager.h
+++ b/quic/core/quic_control_frame_manager.h
@@ -61,13 +61,6 @@
// immediately.
void WriteOrBufferMaxStreamId(QuicStreamId id);
- // Tries to send a packet with both a RST_STREAM and, if version 99, an
- // IETF-QUIC STOP_SENDING frame. The frames are buffered if they can not
- // be sent immediately.
- void WriteOrBufferRstStreamStopSending(QuicControlFrameId stream_id,
- QuicRstStreamErrorCode error_code,
- QuicStreamOffset bytes_written);
-
// Tries to send an IETF-QUIC STOP_SENDING frame. The frame is buffered if it
// can not be sent immediately.
void WriteOrBufferStopSending(uint16_t code, QuicStreamId stream_id);
diff --git a/quic/core/quic_crypto_client_handshaker.cc b/quic/core/quic_crypto_client_handshaker.cc
index 81487df..43948c2 100644
--- a/quic/core/quic_crypto_client_handshaker.cc
+++ b/quic/core/quic_crypto_client_handshaker.cc
@@ -95,7 +95,7 @@
proof_handler_(proof_handler),
verify_ok_(false),
stateless_reject_received_(false),
- proof_verify_start_time_(QuicWallTime::Zero()),
+ proof_verify_start_time_(QuicTime::Zero()),
num_scup_messages_received_(0),
encryption_established_(false),
handshake_confirmed_(false),
@@ -272,7 +272,7 @@
// the proof.
DCHECK(crypto_config_->proof_verifier());
// Track proof verification time when cached server config is used.
- proof_verify_start_time_ = session()->connection()->clock()->WallNow();
+ proof_verify_start_time_ = session()->connection()->clock()->Now();
chlo_hash_ = cached->chlo_hash();
// If the cached state needs to be verified, do it now.
next_state_ = STATE_VERIFY_PROOF;
@@ -381,15 +381,15 @@
SendHandshakeMessage(out);
// Be prepared to decrypt with the new server write key.
session()->connection()->SetAlternativeDecrypter(
- ENCRYPTION_INITIAL,
+ ENCRYPTION_ZERO_RTT,
std::move(crypto_negotiated_params_->initial_crypters.decrypter),
true /* latch once used */);
// Send subsequent packets under encryption on the assumption that the
// server will accept the handshake.
session()->connection()->SetEncrypter(
- ENCRYPTION_INITIAL,
+ ENCRYPTION_ZERO_RTT,
std::move(crypto_negotiated_params_->initial_crypters.encrypter));
- session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
+ session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
// TODO(ianswett): Merge ENCRYPTION_REESTABLISHED and
// ENCRYPTION_FIRST_ESTABLSIHED
@@ -498,12 +498,10 @@
void QuicCryptoClientHandshaker::DoVerifyProofComplete(
QuicCryptoClientConfig::CachedState* cached) {
- if (!proof_verify_start_time_.IsZero()) {
+ if (proof_verify_start_time_.IsInitialized()) {
QUIC_CLIENT_HISTOGRAM_TIMES(
"QuicSession.VerifyProofTime.CachedServerConfig",
- QuicTime::Delta::FromMicroseconds(
- session()->connection()->clock()->WallNow().ToUNIXMicroseconds() -
- proof_verify_start_time_.ToUNIXMicroseconds()),
+ (session()->connection()->clock()->Now() - proof_verify_start_time_),
QuicTime::Delta::FromMilliseconds(1), QuicTime::Delta::FromSeconds(10),
50, "");
}
diff --git a/quic/core/quic_crypto_client_handshaker.h b/quic/core/quic_crypto_client_handshaker.h
index 14fe0a8..c84c2cd 100644
--- a/quic/core/quic_crypto_client_handshaker.h
+++ b/quic/core/quic_crypto_client_handshaker.h
@@ -222,7 +222,7 @@
// STATE_VERIFY_PROOF*, and subsequent STATE_SEND_CHLO state.
bool stateless_reject_received_;
- QuicWallTime proof_verify_start_time_;
+ QuicTime proof_verify_start_time_;
int num_scup_messages_received_;
diff --git a/quic/core/quic_crypto_handshaker.cc b/quic/core/quic_crypto_handshaker.cc
index dab2741..fa0f78a 100644
--- a/quic/core/quic_crypto_handshaker.cc
+++ b/quic/core/quic_crypto_handshaker.cc
@@ -26,8 +26,8 @@
session()->OnCryptoHandshakeMessageSent(message);
last_sent_handshake_message_tag_ = message.tag();
const QuicData& data = message.GetSerialized();
- stream_->WriteOrBufferData(QuicStringPiece(data.data(), data.length()), false,
- nullptr);
+ stream_->WriteCryptoData(session_->connection()->encryption_level(),
+ data.AsStringPiece());
}
void QuicCryptoHandshaker::OnError(CryptoFramer* framer) {
diff --git a/quic/core/quic_crypto_server_handshaker.cc b/quic/core/quic_crypto_server_handshaker.cc
index e79a60c..08ef18b 100644
--- a/quic/core/quic_crypto_server_handshaker.cc
+++ b/quic/core/quic_crypto_server_handshaker.cc
@@ -225,13 +225,13 @@
//
// NOTE: the SHLO will be encrypted with the new server write key.
session()->connection()->SetEncrypter(
- ENCRYPTION_INITIAL,
+ ENCRYPTION_ZERO_RTT,
std::move(crypto_negotiated_params_->initial_crypters.encrypter));
- session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
+ session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
// Set the decrypter immediately so that we no longer accept unencrypted
// packets.
session()->connection()->SetDecrypter(
- ENCRYPTION_INITIAL,
+ ENCRYPTION_ZERO_RTT,
std::move(crypto_negotiated_params_->initial_crypters.decrypter));
session()->connection()->SetDiversificationNonce(*diversification_nonce);
@@ -310,9 +310,13 @@
QUIC_DVLOG(1) << "Server: Sending server config update: "
<< message.DebugString();
- const QuicData& data = message.GetSerialized();
- stream_->WriteOrBufferData(QuicStringPiece(data.data(), data.length()), false,
- nullptr);
+ if (transport_version() < QUIC_VERSION_47) {
+ const QuicData& data = message.GetSerialized();
+ stream_->WriteOrBufferData(QuicStringPiece(data.data(), data.length()),
+ false, nullptr);
+ } else {
+ SendHandshakeMessage(message);
+ }
++num_server_config_update_messages_sent_;
}
@@ -352,6 +356,11 @@
QuicLongHeaderType QuicCryptoServerHandshaker::GetLongHeaderType(
QuicStreamOffset /*offset*/) const {
if (last_sent_handshake_message_tag() == kSREJ) {
+ if (QuicVersionHasLongHeaderLengths(
+ session()->connection()->transport_version())) {
+ return HANDSHAKE;
+ }
+ // TODO(b/123493765): we should probably not be sending RETRY here.
return RETRY;
}
if (last_sent_handshake_message_tag() == kSHLO) {
diff --git a/quic/core/quic_crypto_server_stream_test.cc b/quic/core/quic_crypto_server_stream_test.cc
index 33635d8..c0a3e08 100644
--- a/quic/core/quic_crypto_server_stream_test.cc
+++ b/quic/core/quic_crypto_server_stream_test.cc
@@ -189,7 +189,7 @@
ParsedQuicVersionVector supported_versions_ = AllSupportedVersions();
};
-INSTANTIATE_TEST_CASE_P(Tests, QuicCryptoServerStreamTest, testing::Bool());
+INSTANTIATE_TEST_SUITE_P(Tests, QuicCryptoServerStreamTest, testing::Bool());
TEST_P(QuicCryptoServerStreamTest, NotInitiallyConected) {
Initialize();
@@ -497,9 +497,9 @@
std::unique_ptr<FailingProofSource>(new FailingProofSource)) {}
};
-INSTANTIATE_TEST_CASE_P(MoreTests,
- QuicCryptoServerStreamTestWithFailingProofSource,
- testing::Bool());
+INSTANTIATE_TEST_SUITE_P(MoreTests,
+ QuicCryptoServerStreamTestWithFailingProofSource,
+ testing::Bool());
TEST_P(QuicCryptoServerStreamTestWithFailingProofSource, Test) {
Initialize();
@@ -531,9 +531,9 @@
QuicCryptoServerConfigPeer crypto_config_peer_;
};
-INSTANTIATE_TEST_CASE_P(YetMoreTests,
- QuicCryptoServerStreamTestWithFakeProofSource,
- testing::Bool());
+INSTANTIATE_TEST_SUITE_P(YetMoreTests,
+ QuicCryptoServerStreamTestWithFakeProofSource,
+ testing::Bool());
// 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
diff --git a/quic/core/quic_crypto_stream.cc b/quic/core/quic_crypto_stream.cc
index 8199571..43d1f1a 100644
--- a/quic/core/quic_crypto_stream.cc
+++ b/quic/core/quic_crypto_stream.cc
@@ -27,7 +27,10 @@
session->connection()->transport_version()),
session,
/*is_static=*/true,
- BIDIRECTIONAL) {
+ BIDIRECTIONAL),
+ substreams_{{this, ENCRYPTION_NONE},
+ {this, ENCRYPTION_ZERO_RTT},
+ {this, ENCRYPTION_FORWARD_SECURE}} {
// The crypto stream is exempt from connection level flow control.
DisableConnectionFlowControlForThisStream();
}
@@ -43,56 +46,57 @@
/*include_diversification_nonce=*/true,
version > QUIC_VERSION_43 ? PACKET_4BYTE_PACKET_NUMBER
: PACKET_1BYTE_PACKET_NUMBER,
+ VARIABLE_LENGTH_INTEGER_LENGTH_1, VARIABLE_LENGTH_INTEGER_LENGTH_2,
/*offset=*/0);
}
-void QuicCryptoStream::OnDataAvailable() {
- struct iovec iov;
- // When calling CryptoMessageParser::ProcessInput, an EncryptionLevel needs to
- // be provided. Note that in the general case, the following code may be
- // incorrect. When a stream frame is added to the sequencer, the encryption
- // level provided by the connection will be the encryption level that the
- // frame was received under, but stream frames can be received out of order.
- // If a later stream frame at a higher encryption level is received before an
- // earlier stream frame at a lower encryption level, this code will call
- // CryptoMessageParser::Process input with the data from both frames, but
- // indicate that they both were received at the higher encryption level.
- //
- // For QUIC crypto, this is not a problem, because the CryptoFramer (which
- // implements CryptoMessageParser) ignores the EncryptionLevel passed into
- // ProcessInput.
- //
- // For the TLS handshake, this does not cause an issue for the transition from
- // initial encryption (ClientHello, HelloRetryRequest, and ServerHello) to
- // handshake encryption, as all data from the initial encryption level is
- // needed to derive the handshake encryption keys. For the transition from
- // handshake encryption to 1-RTT application data encryption, all messages at
- // the handshake encryption level *except* the client Finished are needed. The
- // only place this logic would be broken is if a server receives a crypto
- // handshake message that is encrypted under the 1-RTT data keys before
- // receiving the client's Finished message (under handshake encryption keys).
- // Right now, this implementation of TLS in QUIC does not support doing that,
- // but it is possible (although unlikely) that other implementations could.
- // Therefore, this needs to be fixed before the TLS handshake is enabled.
- //
- // TODO(nharper): Use a more robust and correct mechanism to provide the
- // EncryptionLevel to CryptoMessageParser::ProcessInput. This must be done
- // before enabling the TLS handshake.
+void QuicCryptoStream::OnCryptoFrame(const QuicCryptoFrame& frame) {
+ QUIC_BUG_IF(session()->connection()->transport_version() < QUIC_VERSION_47)
+ << "Versions less than 47 shouldn't receive CRYPTO frames";
EncryptionLevel level = session()->connection()->last_decrypted_level();
- while (sequencer()->GetReadableRegion(&iov)) {
+ substreams_[level].sequencer.OnCryptoFrame(frame);
+}
+
+void QuicCryptoStream::OnStreamFrame(const QuicStreamFrame& frame) {
+ if (session()->connection()->transport_version() >= QUIC_VERSION_47) {
+ QUIC_PEER_BUG
+ << "Crypto data received in stream frame instead of crypto frame";
+ CloseConnectionWithDetails(QUIC_INVALID_STREAM_DATA,
+ "Unexpected stream frame");
+ }
+ QuicStream::OnStreamFrame(frame);
+}
+
+void QuicCryptoStream::OnDataAvailable() {
+ EncryptionLevel level = session()->connection()->last_decrypted_level();
+ if (session()->connection()->transport_version() < QUIC_VERSION_47) {
+ // Versions less than 47 only support QUIC crypto, which ignores the
+ // EncryptionLevel passed into CryptoMessageParser::ProcessInput (and
+ // OnDataAvailableInSequencer).
+ OnDataAvailableInSequencer(sequencer(), level);
+ return;
+ }
+ OnDataAvailableInSequencer(&substreams_[level].sequencer, level);
+}
+
+void QuicCryptoStream::OnDataAvailableInSequencer(
+ QuicStreamSequencer* sequencer,
+ EncryptionLevel level) {
+ struct iovec iov;
+ while (sequencer->GetReadableRegion(&iov)) {
QuicStringPiece data(static_cast<char*>(iov.iov_base), iov.iov_len);
if (!crypto_message_parser()->ProcessInput(data, level)) {
CloseConnectionWithDetails(crypto_message_parser()->error(),
crypto_message_parser()->error_detail());
return;
}
- sequencer()->MarkConsumed(iov.iov_len);
+ sequencer->MarkConsumed(iov.iov_len);
if (handshake_confirmed() &&
crypto_message_parser()->InputBytesRemaining() == 0) {
// If the handshake is complete and the current message has been fully
// processed then no more handshake messages are likely to arrive soon
// so release the memory in the stream sequencer.
- sequencer()->ReleaseBufferIfEmpty();
+ sequencer->ReleaseBufferIfEmpty();
}
}
}
@@ -113,33 +117,90 @@
void QuicCryptoStream::WriteCryptoData(EncryptionLevel level,
QuicStringPiece data) {
- // TODO(nharper): This approach to writing data, by setting the encryption
- // level, calling WriteOrBufferData, and then restoring the encryption level,
- // is fragile and assumes that the data gets received by the peer when
- // WriteOrBufferData is called. There is no guarantee that data will get
- // retransmitted at the correct level. This needs to be redone with the
- // cleanup for OnDataAvailable by managing the streams/crypto frames for
- // encryption levels separately.
+ if (session()->connection()->transport_version() < QUIC_VERSION_47) {
+ // The QUIC crypto handshake takes care of setting the appropriate
+ // encryption level before writing data. Since that is the only handshake
+ // supported in versions less than 47, |level| can be ignored here.
+ WriteOrBufferData(data, /* fin */ false, /* ack_listener */ nullptr);
+ return;
+ }
+ if (data.empty()) {
+ QUIC_BUG << "Empty crypto data being written";
+ return;
+ }
+ // Append |data| to the send buffer for this encryption level.
+ struct iovec iov(QuicUtils::MakeIovec(data));
+ QuicStreamSendBuffer* send_buffer = &substreams_[level].send_buffer;
+ QuicStreamOffset offset = send_buffer->stream_offset();
+ send_buffer->SaveStreamData(&iov, /*iov_count=*/1, /*iov_offset=*/0,
+ data.length());
+ if (kMaxStreamLength - offset < data.length()) {
+ QUIC_BUG << "Writing too much crypto handshake data";
+ // TODO(nharper): Switch this to an IETF QUIC error code, possibly
+ // INTERNAL_ERROR?
+ CloseConnectionWithDetails(QUIC_STREAM_LENGTH_OVERFLOW,
+ "Writing too much crypto handshake data");
+ }
+
+ // Set long header type based on the encryption level.
+ if (level != ENCRYPTION_FORWARD_SECURE) {
+ QuicStreamOffset fake_offset = level == ENCRYPTION_NONE ? 0 : 1;
+ // Implementations of GetLongHeaderType either don't care at all about the
+ // offset, or only care whether or not it's 0. However, they do care that it
+ // is an absolute offset from the start of unencrypted crypto data, not the
+ // offset at a particular encryption level.
+ QuicLongHeaderType type = GetLongHeaderType(fake_offset);
+ session()->connection()->SetLongHeaderType(type);
+ }
EncryptionLevel current_level = session()->connection()->encryption_level();
session()->connection()->SetDefaultEncryptionLevel(level);
- WriteOrBufferData(data, /* fin */ false, /* ack_listener */ nullptr);
- if (current_level == ENCRYPTION_FORWARD_SECURE && level != current_level) {
- session()->connection()->SetDefaultEncryptionLevel(current_level);
- }
+ size_t bytes_consumed =
+ session()->connection()->SendCryptoData(level, data.length(), offset);
+ session()->connection()->SetDefaultEncryptionLevel(current_level);
+
+ send_buffer->OnStreamDataConsumed(bytes_consumed);
}
void QuicCryptoStream::OnSuccessfulVersionNegotiation(
const ParsedQuicVersion& version) {}
+bool QuicCryptoStream::OnCryptoFrameAcked(const QuicCryptoFrame& frame,
+ QuicTime::Delta ack_delay_time) {
+ QuicByteCount newly_acked_length = 0;
+ if (!substreams_[frame.level].send_buffer.OnStreamDataAcked(
+ frame.offset, frame.data_length, &newly_acked_length)) {
+ CloseConnectionWithDetails(QUIC_INTERNAL_ERROR,
+ "Trying to ack unsent crypto data.");
+ return false;
+ }
+ return newly_acked_length > 0;
+}
+
void QuicCryptoStream::NeuterUnencryptedStreamData() {
- for (const auto& interval : bytes_consumed_[ENCRYPTION_NONE]) {
+ if (session()->connection()->transport_version() < QUIC_VERSION_47) {
+ for (const auto& interval : bytes_consumed_[ENCRYPTION_NONE]) {
+ QuicByteCount newly_acked_length = 0;
+ send_buffer().OnStreamDataAcked(
+ interval.min(), interval.max() - interval.min(), &newly_acked_length);
+ }
+ return;
+ }
+ QuicStreamSendBuffer* send_buffer = &substreams_[ENCRYPTION_NONE].send_buffer;
+ // TODO(nharper): Consider adding a Clear() method to QuicStreamSendBuffer to
+ // replace the following code.
+ QuicIntervalSet<QuicStreamOffset> to_ack = send_buffer->bytes_acked();
+ to_ack.Complement(0, send_buffer->stream_offset());
+ for (const auto& interval : to_ack) {
QuicByteCount newly_acked_length = 0;
- send_buffer().OnStreamDataAcked(
+ send_buffer->OnStreamDataAcked(
interval.min(), interval.max() - interval.min(), &newly_acked_length);
}
}
void QuicCryptoStream::OnStreamDataConsumed(size_t bytes_consumed) {
+ if (session()->connection()->transport_version() >= QUIC_VERSION_47) {
+ QUIC_BUG << "Stream data consumed when CRYPTO frames should be in use";
+ }
if (bytes_consumed > 0) {
bytes_consumed_[session()->connection()->encryption_level()].Add(
stream_bytes_written(), stream_bytes_written() + bytes_consumed);
@@ -147,6 +208,38 @@
QuicStream::OnStreamDataConsumed(bytes_consumed);
}
+bool QuicCryptoStream::HasPendingCryptoRetransmission() {
+ if (session()->connection()->transport_version() < QUIC_VERSION_47) {
+ return false;
+ }
+ for (EncryptionLevel level :
+ {ENCRYPTION_NONE, ENCRYPTION_ZERO_RTT, ENCRYPTION_FORWARD_SECURE}) {
+ if (substreams_[level].send_buffer.HasPendingRetransmission()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void QuicCryptoStream::WritePendingCryptoRetransmission() {
+ QUIC_BUG_IF(session()->connection()->transport_version() < QUIC_VERSION_47)
+ << "Versions less than 47 don't write CRYPTO frames";
+ EncryptionLevel current_encryption_level =
+ session()->connection()->encryption_level();
+ for (EncryptionLevel level :
+ {ENCRYPTION_NONE, ENCRYPTION_ZERO_RTT, ENCRYPTION_FORWARD_SECURE}) {
+ QuicStreamSendBuffer* send_buffer = &substreams_[level].send_buffer;
+ session()->connection()->SetDefaultEncryptionLevel(level);
+ while (send_buffer->HasPendingRetransmission()) {
+ auto pending = send_buffer->NextPendingRetransmission();
+ size_t bytes_consumed = session()->connection()->SendCryptoData(
+ level, pending.length, pending.offset);
+ send_buffer->OnStreamDataRetransmitted(pending.offset, bytes_consumed);
+ }
+ }
+ session()->connection()->SetDefaultEncryptionLevel(current_encryption_level);
+}
+
void QuicCryptoStream::WritePendingRetransmission() {
while (HasPendingRetransmission()) {
StreamPendingRetransmission pending =
@@ -236,5 +329,97 @@
return true;
}
+uint64_t QuicCryptoStream::crypto_bytes_read() const {
+ if (session()->connection()->transport_version() < QUIC_VERSION_47) {
+ return stream_bytes_read();
+ }
+ return substreams_[ENCRYPTION_NONE].sequencer.NumBytesConsumed() +
+ substreams_[ENCRYPTION_ZERO_RTT].sequencer.NumBytesConsumed() +
+ substreams_[ENCRYPTION_FORWARD_SECURE].sequencer.NumBytesConsumed();
+}
+
+uint64_t QuicCryptoStream::BytesReadOnLevel(EncryptionLevel level) const {
+ return substreams_[level].sequencer.NumBytesConsumed();
+}
+
+bool QuicCryptoStream::WriteCryptoFrame(EncryptionLevel level,
+ QuicStreamOffset offset,
+ QuicByteCount data_length,
+ QuicDataWriter* writer) {
+ QUIC_BUG_IF(session()->connection()->transport_version() < QUIC_VERSION_47)
+ << "Versions less than 47 don't write CRYPTO frames (2)";
+ return substreams_[level].send_buffer.WriteStreamData(offset, data_length,
+ writer);
+}
+
+void QuicCryptoStream::OnCryptoFrameLost(QuicCryptoFrame* crypto_frame) {
+ QUIC_BUG_IF(session()->connection()->transport_version() < QUIC_VERSION_47)
+ << "Versions less than 47 don't lose CRYPTO frames";
+ substreams_[crypto_frame->level].send_buffer.OnStreamDataLost(
+ crypto_frame->offset, crypto_frame->data_length);
+}
+
+void QuicCryptoStream::RetransmitData(QuicCryptoFrame* crypto_frame) {
+ QUIC_BUG_IF(session()->connection()->transport_version() < QUIC_VERSION_47)
+ << "Versions less than 47 don't retransmit CRYPTO frames";
+ QuicIntervalSet<QuicStreamOffset> retransmission(
+ crypto_frame->offset, crypto_frame->offset + crypto_frame->data_length);
+ QuicStreamSendBuffer* send_buffer =
+ &substreams_[crypto_frame->level].send_buffer;
+ retransmission.Difference(send_buffer->bytes_acked());
+ if (retransmission.Empty()) {
+ return;
+ }
+ EncryptionLevel current_encryption_level =
+ session()->connection()->encryption_level();
+ for (const auto& interval : retransmission) {
+ size_t retransmission_offset = interval.min();
+ size_t retransmission_length = interval.max() - interval.min();
+ session()->connection()->SetDefaultEncryptionLevel(crypto_frame->level);
+ size_t bytes_consumed = session()->connection()->SendCryptoData(
+ crypto_frame->level, retransmission_length, retransmission_offset);
+ send_buffer->OnStreamDataRetransmitted(retransmission_offset,
+ bytes_consumed);
+ }
+ session()->connection()->SetDefaultEncryptionLevel(current_encryption_level);
+}
+
+bool QuicCryptoStream::IsFrameOutstanding(EncryptionLevel level,
+ size_t offset,
+ size_t length) const {
+ if (session()->connection()->transport_version() < QUIC_VERSION_47) {
+ // This only happens if a client was originally configured for a version
+ // greater than 45, but received a version negotiation packet and is
+ // attempting to retransmit for a version less than 47. Outside of tests,
+ // this is a misconfiguration of the client, and this connection will be
+ // doomed. Return false here to avoid trying to retransmit CRYPTO frames on
+ // the wrong transport version.
+ return false;
+ }
+ return substreams_[level].send_buffer.IsStreamDataOutstanding(offset, length);
+}
+
+bool QuicCryptoStream::IsWaitingForAcks() const {
+ if (session()->connection()->transport_version() < QUIC_VERSION_47) {
+ return QuicStream::IsWaitingForAcks();
+ }
+ for (EncryptionLevel level :
+ {ENCRYPTION_NONE, ENCRYPTION_ZERO_RTT, ENCRYPTION_FORWARD_SECURE}) {
+ if (substreams_[level].send_buffer.stream_bytes_outstanding()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+QuicCryptoStream::CryptoSubstream::CryptoSubstream(
+ QuicCryptoStream* crypto_stream,
+ EncryptionLevel)
+ : sequencer(crypto_stream),
+ send_buffer(crypto_stream->session()
+ ->connection()
+ ->helper()
+ ->GetStreamSendBufferAllocator()) {}
+
#undef ENDPOINT // undef for jumbo builds
} // namespace quic
diff --git a/quic/core/quic_crypto_stream.h b/quic/core/quic_crypto_stream.h
index 0593f44..cfd81c7 100644
--- a/quic/core/quic_crypto_stream.h
+++ b/quic/core/quic_crypto_stream.h
@@ -45,8 +45,16 @@
QuicTransportVersion version);
// QuicStream implementation
+ void OnStreamFrame(const QuicStreamFrame& frame) override;
void OnDataAvailable() override;
+ // Called when a CRYPTO frame is received.
+ void OnCryptoFrame(const QuicCryptoFrame& frame);
+
+ // Called when a CRYPTO frame is ACKed.
+ bool OnCryptoFrameAcked(const QuicCryptoFrame& frame,
+ QuicTime::Delta ack_delay_time);
+
// Performs key extraction to derive a new secret of |result_len| bytes
// dependent on |label|, |context|, and the stream's negotiated subkey secret.
// Returns false if the handshake has not been confirmed or the parameters are
@@ -86,6 +94,13 @@
// Override to record the encryption level of consumed data.
void OnStreamDataConsumed(size_t bytes_consumed) override;
+ // Returns whether there are any bytes pending retransmission in CRYPTO
+ // frames.
+ virtual bool HasPendingCryptoRetransmission();
+
+ // Writes any pending CRYPTO frame retransmissions.
+ void WritePendingCryptoRetransmission();
+
// Override to retransmit lost crypto data with the appropriate encryption
// level.
void WritePendingRetransmission() override;
@@ -95,11 +110,66 @@
QuicByteCount data_length,
bool fin) override;
+ // Returns the number of bytes of handshake data that have been received from
+ // the peer in either CRYPTO or STREAM frames.
+ uint64_t crypto_bytes_read() const;
+
+ // Returns the number of bytes of handshake data that have been received from
+ // the peer in CRYPTO frames at a particular encryption level.
+ QuicByteCount BytesReadOnLevel(EncryptionLevel level) const;
+
+ // Writes |data_length| of data of a crypto frame to |writer|. The data
+ // written is from the send buffer for encryption level |level| and starts at
+ // |offset|.
+ bool WriteCryptoFrame(EncryptionLevel level,
+ QuicStreamOffset offset,
+ QuicByteCount data_length,
+ QuicDataWriter* writer);
+
+ // Called when data from a CRYPTO frame is considered lost. The lost data is
+ // identified by the encryption level, offset, and length in |crypto_frame|.
+ void OnCryptoFrameLost(QuicCryptoFrame* crypto_frame);
+
+ // Called to retransmit any outstanding data in the range indicated by the
+ // encryption level, offset, and length in |crypto_frame|.
+ void RetransmitData(QuicCryptoFrame* crypto_frame);
+
+ // Returns true if any portion of the data at encryption level |level|
+ // starting at |offset| for |length| bytes is outstanding.
+ bool IsFrameOutstanding(EncryptionLevel level,
+ size_t offset,
+ size_t length) const;
+
+ // Returns true if the crypto handshake is still waiting for acks of sent
+ // data, and false if all data has been acked.
+ bool IsWaitingForAcks() const;
+
private:
+ // Data sent and received in CRYPTO frames is sent at multiple encryption
+ // levels. Some of the state for the single logical crypto stream is split
+ // across encryption levels, and a CryptoSubstream is used to manage that
+ // state for a particular encryption level.
+ struct CryptoSubstream {
+ CryptoSubstream(QuicCryptoStream* crypto_stream, EncryptionLevel);
+
+ QuicStreamSequencer sequencer;
+ QuicStreamSendBuffer send_buffer;
+ };
+
+ // Helper method for OnDataAvailable. Calls CryptoMessageParser::ProcessInput
+ // with the data available in |sequencer| and |level|, and marks the data
+ // passed to ProcessInput as consumed.
+ void OnDataAvailableInSequencer(QuicStreamSequencer* sequencer,
+ EncryptionLevel level);
+
// Consumed data according to encryption levels.
// TODO(fayang): This is not needed once switching from QUIC crypto to
// TLS 1.3, which never encrypts crypto data.
QuicIntervalSet<QuicStreamOffset> bytes_consumed_[NUM_ENCRYPTION_LEVELS];
+
+ // Keeps state for data sent/received in CRYPTO frames at each encryption
+ // level.
+ CryptoSubstream substreams_[NUM_ENCRYPTION_LEVELS];
};
} // namespace quic
diff --git a/quic/core/quic_crypto_stream_test.cc b/quic/core/quic_crypto_stream_test.cc
index 6ce0b41..eb1a672 100644
--- a/quic/core/quic_crypto_stream_test.cc
+++ b/quic/core/quic_crypto_stream_test.cc
@@ -11,6 +11,7 @@
#include "base/macros.h"
#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h"
#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
+#include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
@@ -104,10 +105,15 @@
}
TEST_F(QuicCryptoStreamTest, ProcessRawData) {
- stream_->OnStreamFrame(QuicStreamFrame(
- QuicUtils::GetCryptoStreamId(connection_->transport_version()),
- /*fin=*/false,
- /*offset=*/0, message_data_->AsStringPiece()));
+ if (connection_->transport_version() < QUIC_VERSION_47) {
+ stream_->OnStreamFrame(QuicStreamFrame(
+ QuicUtils::GetCryptoStreamId(connection_->transport_version()),
+ /*fin=*/false,
+ /*offset=*/0, message_data_->AsStringPiece()));
+ } else {
+ stream_->OnCryptoFrame(QuicCryptoFrame(ENCRYPTION_NONE, /*offset*/ 0,
+ message_data_->AsStringPiece()));
+ }
ASSERT_EQ(1u, stream_->messages()->size());
const CryptoHandshakeMessage& message = (*stream_->messages())[0];
EXPECT_EQ(kSHLO, message.tag());
@@ -126,9 +132,13 @@
EXPECT_CALL(*connection_, CloseConnection(QUIC_CRYPTO_TAGS_OUT_OF_ORDER,
testing::_, testing::_));
- stream_->OnStreamFrame(QuicStreamFrame(
- QuicUtils::GetCryptoStreamId(connection_->transport_version()),
- /*fin=*/false, /*offset=*/0, bad));
+ if (connection_->transport_version() < QUIC_VERSION_47) {
+ stream_->OnStreamFrame(QuicStreamFrame(
+ QuicUtils::GetCryptoStreamId(connection_->transport_version()),
+ /*fin=*/false, /*offset=*/0, bad));
+ } else {
+ stream_->OnCryptoFrame(QuicCryptoFrame(ENCRYPTION_NONE, /*offset*/ 0, bad));
+ }
}
TEST_F(QuicCryptoStreamTest, NoConnectionLevelFlowControl) {
@@ -137,6 +147,9 @@
}
TEST_F(QuicCryptoStreamTest, RetransmitCryptoData) {
+ if (connection_->transport_version() >= QUIC_VERSION_47) {
+ return;
+ }
InSequence s;
// Send [0, 1350) in ENCRYPTION_NONE.
EXPECT_EQ(ENCRYPTION_NONE, connection_->encryption_level());
@@ -148,9 +161,9 @@
1350, 0, _))
.WillOnce(Invoke(MockQuicSession::ConsumeData));
stream_->WriteOrBufferData(data, false, nullptr);
- // Send [1350, 2700) in ENCRYPTION_INITIAL.
- connection_->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
- EXPECT_EQ(ENCRYPTION_INITIAL, connection_->encryption_level());
+ // Send [1350, 2700) in ENCRYPTION_ZERO_RTT.
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
+ EXPECT_EQ(ENCRYPTION_ZERO_RTT, connection_->encryption_level());
EXPECT_CALL(
session_,
WritevData(_,
@@ -192,7 +205,62 @@
EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level());
}
+TEST_F(QuicCryptoStreamTest, RetransmitCryptoDataInCryptoFrames) {
+ if (connection_->transport_version() < QUIC_VERSION_47) {
+ return;
+ }
+ EXPECT_CALL(*connection_, SendCryptoData(_, _, _)).Times(0);
+ InSequence s;
+ // Send [0, 1350) in ENCRYPTION_NONE.
+ EXPECT_EQ(ENCRYPTION_NONE, connection_->encryption_level());
+ QuicString data(1350, 'a');
+ EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_NONE, 1350, 0))
+ .WillOnce(Invoke(connection_,
+ &MockQuicConnection::QuicConnection_SendCryptoData));
+ stream_->WriteCryptoData(ENCRYPTION_NONE, data);
+ // Send [1350, 2700) in ENCRYPTION_ZERO_RTT.
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
+ std::unique_ptr<NullEncrypter> encrypter =
+ QuicMakeUnique<NullEncrypter>(Perspective::IS_CLIENT);
+ connection_->SetEncrypter(ENCRYPTION_ZERO_RTT, std::move(encrypter));
+ EXPECT_EQ(ENCRYPTION_ZERO_RTT, connection_->encryption_level());
+ EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 1350, 0))
+ .WillOnce(Invoke(connection_,
+ &MockQuicConnection::QuicConnection_SendCryptoData));
+ stream_->WriteCryptoData(ENCRYPTION_ZERO_RTT, data);
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level());
+
+ // Lost [0, 1000).
+ QuicCryptoFrame lost_frame(ENCRYPTION_NONE, 0, 1000);
+ stream_->OnCryptoFrameLost(&lost_frame);
+ EXPECT_TRUE(stream_->HasPendingCryptoRetransmission());
+ // Lost [1200, 2000).
+ lost_frame = QuicCryptoFrame(ENCRYPTION_NONE, 1200, 150);
+ stream_->OnCryptoFrameLost(&lost_frame);
+ lost_frame = QuicCryptoFrame(ENCRYPTION_ZERO_RTT, 0, 650);
+ stream_->OnCryptoFrameLost(&lost_frame);
+ EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_NONE, 1000, 0))
+ .WillOnce(Invoke(connection_,
+ &MockQuicConnection::QuicConnection_SendCryptoData));
+ // Verify [1200, 2000) are sent in [1200, 1350) and [1350, 2000) because of
+ // they are in different encryption levels.
+ EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_NONE, 150, 1200))
+ .WillOnce(Invoke(connection_,
+ &MockQuicConnection::QuicConnection_SendCryptoData));
+ EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 650, 0))
+ .WillOnce(Invoke(connection_,
+ &MockQuicConnection::QuicConnection_SendCryptoData));
+ stream_->WritePendingCryptoRetransmission();
+ EXPECT_FALSE(stream_->HasPendingCryptoRetransmission());
+ // Verify connection's encryption level has restored.
+ EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level());
+}
+
TEST_F(QuicCryptoStreamTest, NeuterUnencryptedStreamData) {
+ if (connection_->transport_version() >= QUIC_VERSION_47) {
+ return;
+ }
// Send [0, 1350) in ENCRYPTION_NONE.
EXPECT_EQ(ENCRYPTION_NONE, connection_->encryption_level());
QuicString data(1350, 'a');
@@ -203,9 +271,9 @@
1350, 0, _))
.WillOnce(Invoke(MockQuicSession::ConsumeData));
stream_->WriteOrBufferData(data, false, nullptr);
- // Send [1350, 2700) in ENCRYPTION_INITIAL.
- connection_->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
- EXPECT_EQ(ENCRYPTION_INITIAL, connection_->encryption_level());
+ // Send [1350, 2700) in ENCRYPTION_ZERO_RTT.
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
+ EXPECT_EQ(ENCRYPTION_ZERO_RTT, connection_->encryption_level());
EXPECT_CALL(
session_,
WritevData(_,
@@ -231,7 +299,53 @@
EXPECT_TRUE(stream_->HasPendingRetransmission());
}
+TEST_F(QuicCryptoStreamTest, NeuterUnencryptedCryptoData) {
+ if (connection_->transport_version() < QUIC_VERSION_47) {
+ return;
+ }
+ // Send [0, 1350) in ENCRYPTION_NONE.
+ EXPECT_EQ(ENCRYPTION_NONE, connection_->encryption_level());
+ QuicString data(1350, 'a');
+ EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_NONE, 1350, 0))
+ .WillOnce(Invoke(connection_,
+ &MockQuicConnection::QuicConnection_SendCryptoData));
+ stream_->WriteCryptoData(ENCRYPTION_NONE, data);
+ // Send [1350, 2700) in ENCRYPTION_ZERO_RTT.
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
+ std::unique_ptr<NullEncrypter> encrypter =
+ QuicMakeUnique<NullEncrypter>(Perspective::IS_CLIENT);
+ connection_->SetEncrypter(ENCRYPTION_ZERO_RTT, std::move(encrypter));
+ EXPECT_EQ(ENCRYPTION_ZERO_RTT, connection_->encryption_level());
+ EXPECT_CALL(*connection_, SendCryptoData(_, _, _)).Times(0);
+ EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 1350, 0))
+ .WillOnce(Invoke(connection_,
+ &MockQuicConnection::QuicConnection_SendCryptoData));
+ stream_->WriteCryptoData(ENCRYPTION_ZERO_RTT, data);
+
+ // Lost [0, 1350).
+ QuicCryptoFrame lost_frame(ENCRYPTION_NONE, 0, 1350);
+ stream_->OnCryptoFrameLost(&lost_frame);
+ EXPECT_TRUE(stream_->HasPendingCryptoRetransmission());
+ // Neuters [0, 1350).
+ stream_->NeuterUnencryptedStreamData();
+ EXPECT_FALSE(stream_->HasPendingCryptoRetransmission());
+ // Lost [0, 1350) again.
+ stream_->OnCryptoFrameLost(&lost_frame);
+ EXPECT_FALSE(stream_->HasPendingCryptoRetransmission());
+
+ // Lost [1350, 2000), which starts at offset 0 at the ENCRYPTION_ZERO_RTT
+ // level.
+ lost_frame = QuicCryptoFrame(ENCRYPTION_ZERO_RTT, 0, 650);
+ stream_->OnCryptoFrameLost(&lost_frame);
+ EXPECT_TRUE(stream_->HasPendingCryptoRetransmission());
+ stream_->NeuterUnencryptedStreamData();
+ EXPECT_TRUE(stream_->HasPendingCryptoRetransmission());
+}
+
TEST_F(QuicCryptoStreamTest, RetransmitStreamData) {
+ if (connection_->transport_version() >= QUIC_VERSION_47) {
+ return;
+ }
InSequence s;
// Send [0, 1350) in ENCRYPTION_NONE.
EXPECT_EQ(ENCRYPTION_NONE, connection_->encryption_level());
@@ -243,9 +357,9 @@
1350, 0, _))
.WillOnce(Invoke(MockQuicSession::ConsumeData));
stream_->WriteOrBufferData(data, false, nullptr);
- // Send [1350, 2700) in ENCRYPTION_INITIAL.
- connection_->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
- EXPECT_EQ(ENCRYPTION_INITIAL, connection_->encryption_level());
+ // Send [1350, 2700) in ENCRYPTION_ZERO_RTT.
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
+ EXPECT_EQ(ENCRYPTION_ZERO_RTT, connection_->encryption_level());
EXPECT_CALL(
session_,
WritevData(_,
@@ -257,7 +371,10 @@
EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level());
// Ack [2000, 2500).
- stream_->OnStreamFrameAcked(2000, 500, false, QuicTime::Delta::Zero());
+ QuicByteCount newly_acked_length = 0;
+ stream_->OnStreamFrameAcked(2000, 500, false, QuicTime::Delta::Zero(),
+ &newly_acked_length);
+ EXPECT_EQ(500u, newly_acked_length);
// Force crypto stream to send [1350, 2700) and only [1350, 1500) is consumed.
EXPECT_CALL(
@@ -298,8 +415,69 @@
EXPECT_TRUE(stream_->RetransmitStreamData(0, 0, false));
}
+TEST_F(QuicCryptoStreamTest, RetransmitStreamDataWithCryptoFrames) {
+ if (connection_->transport_version() < QUIC_VERSION_47) {
+ return;
+ }
+ InSequence s;
+ // Send [0, 1350) in ENCRYPTION_NONE.
+ EXPECT_EQ(ENCRYPTION_NONE, connection_->encryption_level());
+ QuicString data(1350, 'a');
+ EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_NONE, 1350, 0))
+ .WillOnce(Invoke(connection_,
+ &MockQuicConnection::QuicConnection_SendCryptoData));
+ stream_->WriteCryptoData(ENCRYPTION_NONE, data);
+ // Send [1350, 2700) in ENCRYPTION_ZERO_RTT.
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
+ std::unique_ptr<NullEncrypter> encrypter =
+ QuicMakeUnique<NullEncrypter>(Perspective::IS_CLIENT);
+ connection_->SetEncrypter(ENCRYPTION_ZERO_RTT, std::move(encrypter));
+ EXPECT_EQ(ENCRYPTION_ZERO_RTT, connection_->encryption_level());
+ EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 1350, 0))
+ .WillOnce(Invoke(connection_,
+ &MockQuicConnection::QuicConnection_SendCryptoData));
+ stream_->WriteCryptoData(ENCRYPTION_ZERO_RTT, data);
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level());
+
+ // Ack [2000, 2500).
+ QuicCryptoFrame acked_frame(ENCRYPTION_ZERO_RTT, 650, 500);
+ EXPECT_TRUE(
+ stream_->OnCryptoFrameAcked(acked_frame, QuicTime::Delta::Zero()));
+
+ // Retransmit only [1350, 1500).
+ EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 150, 0))
+ .WillOnce(Invoke(connection_,
+ &MockQuicConnection::QuicConnection_SendCryptoData));
+ QuicCryptoFrame frame_to_retransmit(ENCRYPTION_ZERO_RTT, 0, 150);
+ stream_->RetransmitData(&frame_to_retransmit);
+
+ // Verify connection's encryption level has restored.
+ EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level());
+
+ // Retransmit [1350, 2700) again and all data is sent.
+ EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 650, 0))
+ .WillOnce(Invoke(connection_,
+ &MockQuicConnection::QuicConnection_SendCryptoData));
+ EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 200, 1150))
+ .WillOnce(Invoke(connection_,
+ &MockQuicConnection::QuicConnection_SendCryptoData));
+ frame_to_retransmit = QuicCryptoFrame(ENCRYPTION_ZERO_RTT, 0, 1350);
+ stream_->RetransmitData(&frame_to_retransmit);
+ // Verify connection's encryption level has restored.
+ EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level());
+
+ EXPECT_CALL(*connection_, SendCryptoData(_, _, _)).Times(0);
+ // Force to send an empty frame.
+ QuicCryptoFrame empty_frame(ENCRYPTION_FORWARD_SECURE, 0, 0);
+ stream_->RetransmitData(&empty_frame);
+}
+
// Regression test for b/115926584.
TEST_F(QuicCryptoStreamTest, HasUnackedCryptoData) {
+ if (connection_->transport_version() >= QUIC_VERSION_47) {
+ return;
+ }
QuicString data(1350, 'a');
EXPECT_CALL(
session_,
@@ -325,6 +503,21 @@
EXPECT_TRUE(session_.HasUnackedCryptoData());
}
+TEST_F(QuicCryptoStreamTest, HasUnackedCryptoDataWithCryptoFrames) {
+ if (connection_->transport_version() < QUIC_VERSION_47) {
+ return;
+ }
+ // Send [0, 1350) in ENCRYPTION_NONE.
+ EXPECT_EQ(ENCRYPTION_NONE, connection_->encryption_level());
+ QuicString data(1350, 'a');
+ EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_NONE, 1350, 0))
+ .WillOnce(Invoke(connection_,
+ &MockQuicConnection::QuicConnection_SendCryptoData));
+ stream_->WriteCryptoData(ENCRYPTION_NONE, data);
+ EXPECT_TRUE(stream_->IsWaitingForAcks());
+ EXPECT_TRUE(session_.HasUnackedCryptoData());
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/quic/core/quic_data_reader.cc b/quic/core/quic_data_reader.cc
index 13a4c5a..191c755 100644
--- a/quic/core/quic_data_reader.cc
+++ b/quic/core/quic_data_reader.cc
@@ -12,6 +12,9 @@
namespace quic {
+QuicDataReader::QuicDataReader(const char* data, const size_t len)
+ : QuicDataReader(data, len, NETWORK_BYTE_ORDER) {}
+
QuicDataReader::QuicDataReader(const char* data,
const size_t len,
Endianness endianness)
@@ -129,17 +132,7 @@
}
bool QuicDataReader::ReadConnectionId(QuicConnectionId* connection_id,
- uint8_t length,
- Perspective perspective) {
- if (!QuicConnectionIdSupportsVariableLength(perspective)) {
- uint64_t connection_id64 = 0;
- if (!ReadBytes(&connection_id64, sizeof(connection_id64))) {
- return false;
- }
- *connection_id =
- QuicConnectionIdFromUInt64(QuicEndian::NetToHost64(connection_id64));
- return true;
- }
+ uint8_t length) {
DCHECK_LE(length, kQuicMaxConnectionIdLength);
const bool ok = ReadBytes(connection_id->mutable_data(), length);
@@ -159,7 +152,7 @@
return payload;
}
-QuicStringPiece QuicDataReader::PeekRemainingPayload() {
+QuicStringPiece QuicDataReader::PeekRemainingPayload() const {
return QuicStringPiece(data_ + pos_, len_ - pos_);
}
@@ -183,20 +176,29 @@
return len_ == pos_;
}
-int QuicDataReader::PeekVarInt62Length() {
+QuicVariableLengthIntegerLength QuicDataReader::PeekVarInt62Length() {
DCHECK_EQ(endianness_, NETWORK_BYTE_ORDER);
const unsigned char* next =
reinterpret_cast<const unsigned char*>(data_ + pos_);
if (BytesRemaining() == 0) {
- return 0;
+ return VARIABLE_LENGTH_INTEGER_LENGTH_0;
}
- return 1 << ((*next & 0b11000000) >> 6);
+ return static_cast<QuicVariableLengthIntegerLength>(
+ 1 << ((*next & 0b11000000) >> 6));
}
size_t QuicDataReader::BytesRemaining() const {
return len_ - pos_;
}
+bool QuicDataReader::TruncateRemaining(size_t truncation_length) {
+ if (truncation_length > BytesRemaining()) {
+ return false;
+ }
+ len_ = pos_ + truncation_length;
+ return true;
+}
+
bool QuicDataReader::CanRead(size_t bytes) const {
return bytes <= (len_ - pos_);
}
diff --git a/quic/core/quic_data_reader.h b/quic/core/quic_data_reader.h
index ca9f323..fff0ffd 100644
--- a/quic/core/quic_data_reader.h
+++ b/quic/core/quic_data_reader.h
@@ -32,6 +32,10 @@
// called after failure, as they will also fail immediately.
class QUIC_EXPORT_PRIVATE QuicDataReader {
public:
+ // Constructs a reader using NETWORK_BYTE_ORDER endianness.
+ // Caller must provide an underlying buffer to work on.
+ QuicDataReader(const char* data, const size_t len);
+ // Constructs a reader using the specified endianness.
// Caller must provide an underlying buffer to work on.
QuicDataReader(const char* data, const size_t len, Endianness endianness);
QuicDataReader(const QuicDataReader&) = delete;
@@ -75,11 +79,7 @@
// Reads connection ID into the given output parameter.
// Forwards the internal iterator on success.
// Returns true on success, false otherwise.
- // TODO(dschinazi) b/120240679 - remove perspective once these flags are
- // deprecated: quic_variable_length_connection_ids_(client|server).
- bool ReadConnectionId(QuicConnectionId* connection_id,
- uint8_t length,
- Perspective perspective);
+ bool ReadConnectionId(QuicConnectionId* connection_id, uint8_t length);
// Reads tag represented as 32-bit unsigned integer into given output
// parameter. Tags are in big endian on the wire (e.g., CHLO is
@@ -101,7 +101,7 @@
// This should be kept in mind when handling memory management!
//
// DOES NOT forward the internal iterator.
- QuicStringPiece PeekRemainingPayload();
+ QuicStringPiece PeekRemainingPayload() const;
// Reads a given number of bytes into the given buffer. The buffer
// must be of adequate size.
@@ -115,11 +115,17 @@
// Returns the length in bytes of a variable length integer based on the next
// two bits available. Returns 1, 2, 4, or 8 on success, and 0 on failure.
- int PeekVarInt62Length();
+ QuicVariableLengthIntegerLength PeekVarInt62Length();
// Returns the number of bytes remaining to be read.
size_t BytesRemaining() const;
+ // Truncates the reader down by reducing its internal length.
+ // If called immediately after calling this, BytesRemaining will
+ // return |truncation_length|. If truncation_length is less than the
+ // current value of BytesRemaining, this does nothing and returns false.
+ bool TruncateRemaining(size_t truncation_length);
+
// Returns the next byte that to be read. Must not be called when there are no
// bytes to be read.
//
@@ -158,7 +164,7 @@
const char* data_;
// The length of the data buffer that we're reading from.
- const size_t len_;
+ size_t len_;
// The location of the next read from our data buffer.
size_t pos_;
diff --git a/quic/core/quic_data_writer.cc b/quic/core/quic_data_writer.cc
index 865b262..c7bedb5 100644
--- a/quic/core/quic_data_writer.cc
+++ b/quic/core/quic_data_writer.cc
@@ -15,6 +15,9 @@
namespace quic {
+QuicDataWriter::QuicDataWriter(size_t size, char* buffer)
+ : QuicDataWriter(size, buffer, NETWORK_BYTE_ORDER) {}
+
QuicDataWriter::QuicDataWriter(size_t size, char* buffer, Endianness endianness)
: buffer_(buffer), capacity_(size), length_(0), endianness_(endianness) {}
@@ -171,14 +174,7 @@
return WriteRepeatedByte(0x00, count);
}
-bool QuicDataWriter::WriteConnectionId(QuicConnectionId connection_id,
- Perspective perspective) {
- if (!QuicConnectionIdSupportsVariableLength(perspective)) {
- uint64_t connection_id64 =
- QuicEndian::HostToNet64(QuicConnectionIdToUInt64(connection_id));
-
- return WriteBytes(&connection_id64, sizeof(connection_id64));
- }
+bool QuicDataWriter::WriteConnectionId(QuicConnectionId connection_id) {
return WriteBytes(connection_id.data(), connection_id.length());
}
@@ -283,23 +279,58 @@
return false;
}
+bool QuicDataWriter::WriteVarInt62(
+ uint64_t value,
+ QuicVariableLengthIntegerLength write_length) {
+ DCHECK_EQ(endianness_, NETWORK_BYTE_ORDER);
+
+ size_t remaining = capacity_ - length_;
+ if (remaining < write_length) {
+ return false;
+ }
+
+ const QuicVariableLengthIntegerLength min_length = GetVarInt62Len(value);
+ if (write_length < min_length) {
+ QUIC_BUG << "Cannot write value " << value << " with write_length "
+ << write_length;
+ return false;
+ }
+ if (write_length == min_length) {
+ return WriteVarInt62(value);
+ }
+
+ if (write_length == VARIABLE_LENGTH_INTEGER_LENGTH_2) {
+ return WriteUInt8(0b01000000) && WriteUInt8(value);
+ }
+ if (write_length == VARIABLE_LENGTH_INTEGER_LENGTH_4) {
+ return WriteUInt8(0b10000000) && WriteUInt8(0) && WriteUInt16(value);
+ }
+ if (write_length == VARIABLE_LENGTH_INTEGER_LENGTH_8) {
+ return WriteUInt8(0b11000000) && WriteUInt8(0) && WriteUInt16(0) &&
+ WriteUInt32(value);
+ }
+
+ QUIC_BUG << "Invalid write_length " << static_cast<int>(write_length);
+ return false;
+}
+
// static
-int QuicDataWriter::GetVarInt62Len(uint64_t value) {
+QuicVariableLengthIntegerLength QuicDataWriter::GetVarInt62Len(uint64_t value) {
if ((value & kVarInt62ErrorMask) != 0) {
QUIC_BUG << "Attempted to encode a value, " << value
<< ", that is too big for VarInt62";
- return 0;
+ return VARIABLE_LENGTH_INTEGER_LENGTH_0;
}
if ((value & kVarInt62Mask8Bytes) != 0) {
- return 8;
+ return VARIABLE_LENGTH_INTEGER_LENGTH_8;
}
if ((value & kVarInt62Mask4Bytes) != 0) {
- return 4;
+ return VARIABLE_LENGTH_INTEGER_LENGTH_4;
}
if ((value & kVarInt62Mask2Bytes) != 0) {
- return 2;
+ return VARIABLE_LENGTH_INTEGER_LENGTH_2;
}
- return 1;
+ return VARIABLE_LENGTH_INTEGER_LENGTH_1;
}
bool QuicDataWriter::WriteStringPieceVarInt62(
diff --git a/quic/core/quic_data_writer.h b/quic/core/quic_data_writer.h
index 9423553..e107fcb 100644
--- a/quic/core/quic_data_writer.h
+++ b/quic/core/quic_data_writer.h
@@ -38,7 +38,11 @@
// of the QuicDataWriter.
class QUIC_EXPORT_PRIVATE QuicDataWriter {
public:
- // Creates a QuicDataWriter where |buffer| is not owned.
+ // Creates a QuicDataWriter where |buffer| is not owned
+ // using NETWORK_BYTE_ORDER endianness.
+ QuicDataWriter(size_t size, char* buffer);
+ // Creates a QuicDataWriter where |buffer| is not owned
+ // using the specified endianness.
QuicDataWriter(size_t size, char* buffer, Endianness endianness);
QuicDataWriter(const QuicDataWriter&) = delete;
QuicDataWriter& operator=(const QuicDataWriter&) = delete;
@@ -68,6 +72,13 @@
// buffer.
bool WriteVarInt62(uint64_t value);
+ // Same as WriteVarInt62(uint64_t), but forces an encoding size to write to.
+ // This is not as optimized as WriteVarInt62(uint64_t).
+ // Returns false if the value does not fit in the specified write_length or if
+ // there is no room in the buffer.
+ bool WriteVarInt62(uint64_t value,
+ QuicVariableLengthIntegerLength write_length);
+
// Writes a string piece as a consecutive length/content pair. The
// length is VarInt62 encoded.
bool WriteStringPieceVarInt62(const QuicStringPiece& string_piece);
@@ -76,7 +87,7 @@
// the given value using IETF VarInt62 encoding. Returns the number
// of bytes required to encode the given integer or 0 if the value
// is too large to encode.
- static int GetVarInt62Len(uint64_t value);
+ static QuicVariableLengthIntegerLength GetVarInt62Len(uint64_t value);
// Writes least significant |num_bytes| of a 64-bit unsigned integer in the
// correct byte order.
@@ -96,10 +107,7 @@
bool WritePaddingBytes(size_t count);
// Write connection ID to the payload.
- // TODO(dschinazi) b/120240679 - remove perspective once these flags are
- // deprecated: quic_variable_length_connection_ids_(client|server).
- bool WriteConnectionId(QuicConnectionId connection_id,
- Perspective perspective);
+ bool WriteConnectionId(QuicConnectionId connection_id);
// Write tag as a 32-bit unsigned integer to the payload. As tags are already
// converted to big endian (e.g., CHLO is 'C','H','L','O') in memory by TAG or
diff --git a/quic/core/quic_data_writer_test.cc b/quic/core/quic_data_writer_test.cc
index 9fe05e6..978143e 100644
--- a/quic/core/quic_data_writer_test.cc
+++ b/quic/core/quic_data_writer_test.cc
@@ -37,9 +37,8 @@
class QuicDataWriterTest : public QuicTestWithParam<TestParams> {};
-INSTANTIATE_TEST_CASE_P(QuicDataWriterTests,
- QuicDataWriterTest,
- ::testing::ValuesIn(GetTestParams()));
+INSTANTIATE_TEST_SUITE_P(QuicDataWriterTests, QuicDataWriterTest,
+ ::testing::ValuesIn(GetTestParams()));
TEST_P(QuicDataWriterTest, SanityCheckUFloat16Consts) {
// Check the arithmetic on the constants - otherwise the values below make
@@ -256,99 +255,16 @@
ASSERT_LE(connection_id.length(), kQuicMaxConnectionIdLength);
char buffer[kQuicMaxConnectionIdLength];
QuicDataWriter writer(connection_id.length(), buffer, GetParam().endianness);
- EXPECT_TRUE(writer.WriteConnectionId(connection_id, Perspective::IS_CLIENT));
+ EXPECT_TRUE(writer.WriteConnectionId(connection_id));
test::CompareCharArraysWithHexError("connection_id", buffer,
connection_id.length(), big_endian,
connection_id.length());
QuicConnectionId read_connection_id;
QuicDataReader reader(buffer, connection_id.length(), GetParam().endianness);
- EXPECT_TRUE(reader.ReadConnectionId(
- &read_connection_id, QUIC_ARRAYSIZE(big_endian), Perspective::IS_CLIENT));
+ EXPECT_TRUE(
+ reader.ReadConnectionId(&read_connection_id, QUIC_ARRAYSIZE(big_endian)));
EXPECT_EQ(connection_id, read_connection_id);
-
- // TODO(dschinazi) b/120240679 - remove this second read once these flags are
- // deprecated: quic_variable_length_connection_ids_(client|server).
- QuicConnectionId read_connection_id2;
- QuicDataReader reader2(buffer, connection_id.length(), GetParam().endianness);
- EXPECT_TRUE(reader2.ReadConnectionId(&read_connection_id2,
- QUIC_ARRAYSIZE(big_endian),
- Perspective::IS_SERVER));
- EXPECT_EQ(connection_id, read_connection_id2);
-}
-
-// TODO(dschinazi) b/120240679 - remove this test once these flags are
-// deprecated: quic_variable_length_connection_ids_(client|server).
-TEST_P(QuicDataWriterTest, WriteConnectionIdServerAllowingVariableLength) {
- if (!GetQuicRestartFlag(quic_connection_ids_network_byte_order)) {
- // This test is pointless if the flag is off.
- return;
- }
- SetQuicRestartFlag(quic_variable_length_connection_ids_client, false);
- SetQuicRestartFlag(quic_variable_length_connection_ids_server, true);
- QuicConnectionId connection_id =
- TestConnectionId(UINT64_C(0x0011223344556677));
- char big_endian[] = {
- 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
- };
- EXPECT_EQ(connection_id.length(), QUIC_ARRAYSIZE(big_endian));
- ASSERT_LE(connection_id.length(), kQuicMaxConnectionIdLength);
- char buffer[kQuicMaxConnectionIdLength];
- QuicDataWriter writer(connection_id.length(), buffer, GetParam().endianness);
- EXPECT_TRUE(writer.WriteConnectionId(connection_id, Perspective::IS_SERVER));
- test::CompareCharArraysWithHexError("connection_id", buffer,
- connection_id.length(), big_endian,
- connection_id.length());
-
- QuicConnectionId read_connection_id;
- QuicDataReader reader(buffer, connection_id.length(), GetParam().endianness);
- EXPECT_TRUE(reader.ReadConnectionId(
- &read_connection_id, QUIC_ARRAYSIZE(big_endian), Perspective::IS_CLIENT));
- EXPECT_EQ(connection_id, read_connection_id);
-
- QuicConnectionId read_connection_id2;
- QuicDataReader reader2(buffer, connection_id.length(), GetParam().endianness);
- EXPECT_TRUE(reader2.ReadConnectionId(&read_connection_id2,
- QUIC_ARRAYSIZE(big_endian),
- Perspective::IS_SERVER));
- EXPECT_EQ(connection_id, read_connection_id2);
-}
-
-// TODO(dschinazi) b/120240679 - remove this test once these flags are
-// deprecated: quic_variable_length_connection_ids_(client|server).
-TEST_P(QuicDataWriterTest, WriteConnectionIdClientAllowingVariableLength) {
- if (!GetQuicRestartFlag(quic_connection_ids_network_byte_order)) {
- // This test is pointless if the flag is off.
- return;
- }
- SetQuicRestartFlag(quic_variable_length_connection_ids_client, true);
- SetQuicRestartFlag(quic_variable_length_connection_ids_server, false);
- QuicConnectionId connection_id =
- TestConnectionId(UINT64_C(0x0011223344556677));
- char big_endian[] = {
- 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
- };
- EXPECT_EQ(connection_id.length(), QUIC_ARRAYSIZE(big_endian));
- ASSERT_LE(connection_id.length(), kQuicMaxConnectionIdLength);
- char buffer[kQuicMaxConnectionIdLength];
- QuicDataWriter writer(connection_id.length(), buffer, GetParam().endianness);
- EXPECT_TRUE(writer.WriteConnectionId(connection_id, Perspective::IS_SERVER));
- test::CompareCharArraysWithHexError("connection_id", buffer,
- connection_id.length(), big_endian,
- connection_id.length());
-
- QuicConnectionId read_connection_id;
- QuicDataReader reader(buffer, connection_id.length(), GetParam().endianness);
- EXPECT_TRUE(reader.ReadConnectionId(
- &read_connection_id, QUIC_ARRAYSIZE(big_endian), Perspective::IS_CLIENT));
- EXPECT_EQ(connection_id, read_connection_id);
-
- QuicConnectionId read_connection_id2;
- QuicDataReader reader2(buffer, connection_id.length(), GetParam().endianness);
- EXPECT_TRUE(reader2.ReadConnectionId(&read_connection_id2,
- QUIC_ARRAYSIZE(big_endian),
- Perspective::IS_SERVER));
- EXPECT_EQ(connection_id, read_connection_id2);
}
TEST_P(QuicDataWriterTest, WriteTag) {
@@ -991,6 +907,76 @@
EXPECT_FALSE(reader.ReadVarInt62(&test_val));
}
+// Test writing varints with a forced length.
+TEST_P(QuicDataWriterTest, VarIntFixedLength) {
+ char buffer[90];
+ memset(buffer, 0, sizeof(buffer));
+ QuicDataWriter writer(sizeof(buffer), static_cast<char*>(buffer),
+ Endianness::NETWORK_BYTE_ORDER);
+
+ writer.WriteVarInt62(1, VARIABLE_LENGTH_INTEGER_LENGTH_1);
+ writer.WriteVarInt62(1, VARIABLE_LENGTH_INTEGER_LENGTH_2);
+ writer.WriteVarInt62(1, VARIABLE_LENGTH_INTEGER_LENGTH_4);
+ writer.WriteVarInt62(1, VARIABLE_LENGTH_INTEGER_LENGTH_8);
+
+ writer.WriteVarInt62(63, VARIABLE_LENGTH_INTEGER_LENGTH_1);
+ writer.WriteVarInt62(63, VARIABLE_LENGTH_INTEGER_LENGTH_2);
+ writer.WriteVarInt62(63, VARIABLE_LENGTH_INTEGER_LENGTH_4);
+ writer.WriteVarInt62(63, VARIABLE_LENGTH_INTEGER_LENGTH_8);
+
+ writer.WriteVarInt62(64, VARIABLE_LENGTH_INTEGER_LENGTH_2);
+ writer.WriteVarInt62(64, VARIABLE_LENGTH_INTEGER_LENGTH_4);
+ writer.WriteVarInt62(64, VARIABLE_LENGTH_INTEGER_LENGTH_8);
+
+ writer.WriteVarInt62(16383, VARIABLE_LENGTH_INTEGER_LENGTH_2);
+ writer.WriteVarInt62(16383, VARIABLE_LENGTH_INTEGER_LENGTH_4);
+ writer.WriteVarInt62(16383, VARIABLE_LENGTH_INTEGER_LENGTH_8);
+
+ writer.WriteVarInt62(16384, VARIABLE_LENGTH_INTEGER_LENGTH_4);
+ writer.WriteVarInt62(16384, VARIABLE_LENGTH_INTEGER_LENGTH_8);
+
+ writer.WriteVarInt62(1073741823, VARIABLE_LENGTH_INTEGER_LENGTH_4);
+ writer.WriteVarInt62(1073741823, VARIABLE_LENGTH_INTEGER_LENGTH_8);
+
+ writer.WriteVarInt62(1073741824, VARIABLE_LENGTH_INTEGER_LENGTH_8);
+
+ QuicDataReader reader(buffer, sizeof(buffer), Endianness::NETWORK_BYTE_ORDER);
+
+ uint64_t test_val = 0;
+ for (int i = 0; i < 4; ++i) {
+ EXPECT_TRUE(reader.ReadVarInt62(&test_val));
+ EXPECT_EQ(test_val, 1);
+ }
+ for (int i = 0; i < 4; ++i) {
+ EXPECT_TRUE(reader.ReadVarInt62(&test_val));
+ EXPECT_EQ(test_val, 63);
+ }
+
+ for (int i = 0; i < 3; ++i) {
+ EXPECT_TRUE(reader.ReadVarInt62(&test_val));
+ EXPECT_EQ(test_val, 64);
+ }
+ for (int i = 0; i < 3; ++i) {
+ EXPECT_TRUE(reader.ReadVarInt62(&test_val));
+ EXPECT_EQ(test_val, 16383);
+ }
+
+ for (int i = 0; i < 2; ++i) {
+ EXPECT_TRUE(reader.ReadVarInt62(&test_val));
+ EXPECT_EQ(test_val, 16384);
+ }
+ for (int i = 0; i < 2; ++i) {
+ EXPECT_TRUE(reader.ReadVarInt62(&test_val));
+ EXPECT_EQ(test_val, 1073741823);
+ }
+
+ EXPECT_TRUE(reader.ReadVarInt62(&test_val));
+ EXPECT_EQ(test_val, 1073741824);
+
+ // We are at the end of the buffer so this should fail.
+ EXPECT_FALSE(reader.ReadVarInt62(&test_val));
+}
+
// Test encoding/decoding stream-id values.
void EncodeDecodeStreamId(uint64_t value_in, bool expected_decode_result) {
char buffer[1 * kMultiVarCount];
diff --git a/quic/core/quic_default_packet_writer.cc b/quic/core/quic_default_packet_writer.cc
index 2c162e0..3b16a74 100644
--- a/quic/core/quic_default_packet_writer.cc
+++ b/quic/core/quic_default_packet_writer.cc
@@ -30,10 +30,6 @@
return result;
}
-bool QuicDefaultPacketWriter::IsWriteBlockedDataBuffered() const {
- return false;
-}
-
bool QuicDefaultPacketWriter::IsWriteBlocked() const {
return write_blocked_;
}
diff --git a/quic/core/quic_default_packet_writer.h b/quic/core/quic_default_packet_writer.h
index 93917da..b5473eb 100644
--- a/quic/core/quic_default_packet_writer.h
+++ b/quic/core/quic_default_packet_writer.h
@@ -30,7 +30,6 @@
const QuicIpAddress& self_address,
const QuicSocketAddress& peer_address,
PerPacketOptions* options) override;
- bool IsWriteBlockedDataBuffered() const override;
bool IsWriteBlocked() const override;
void SetWritable() override;
QuicByteCount GetMaxPacketSize(
diff --git a/quic/core/quic_dispatcher.cc b/quic/core/quic_dispatcher.cc
index 0cb03aa..f17bdf2 100644
--- a/quic/core/quic_dispatcher.cc
+++ b/quic/core/quic_dispatcher.cc
@@ -96,8 +96,7 @@
QuicStreamOffset offset,
QuicByteCount data_length,
QuicDataWriter* writer) override {
- QUIC_BUG << "PacketCollector::WriteCryptoData is unimplemented.";
- return false;
+ return send_buffer_.WriteStreamData(offset, data_length, writer);
}
std::vector<std::unique_ptr<QuicEncryptedPacket>>* packets() {
@@ -143,7 +142,12 @@
frame->error_details = error_details;
// TODO(fayang): Use the right long header type for conneciton close sent by
// dispatcher.
- creator_.SetLongHeaderType(RETRY);
+ if (QuicVersionHasLongHeaderLengths(framer_->transport_version())) {
+ creator_.SetLongHeaderType(HANDSHAKE);
+ } else {
+ // TODO(b/123493765): we should probably not be sending RETRY here.
+ creator_.SetLongHeaderType(RETRY);
+ }
if (!creator_.AddSavedFrame(QuicFrame(frame), NOT_RETRANSMISSION)) {
QUIC_BUG << "Unable to add frame to an empty packet";
delete frame;
@@ -165,16 +169,31 @@
collector_.SaveStatelessRejectFrameData(reject);
while (offset < reject.length()) {
QuicFrame frame;
- creator_.SetLongHeaderType(RETRY);
- if (!creator_.ConsumeData(
- QuicUtils::GetCryptoStreamId(framer_->transport_version()),
- reject.length(), offset, offset,
- /*fin=*/false,
- /*needs_full_padding=*/true, NOT_RETRANSMISSION, &frame)) {
- QUIC_BUG << "Unable to consume data into an empty packet.";
- return;
+ if (QuicVersionHasLongHeaderLengths(framer_->transport_version())) {
+ creator_.SetLongHeaderType(HANDSHAKE);
+ } else {
+ // TODO(b/123493765): we should probably not be sending RETRY here.
+ creator_.SetLongHeaderType(RETRY);
}
- offset += frame.stream_frame.data_length;
+ if (framer_->transport_version() < QUIC_VERSION_47) {
+ if (!creator_.ConsumeData(
+ QuicUtils::GetCryptoStreamId(framer_->transport_version()),
+ reject.length(), offset, offset,
+ /*fin=*/false,
+ /*needs_full_padding=*/true, NOT_RETRANSMISSION, &frame)) {
+ QUIC_BUG << "Unable to consume data into an empty packet.";
+ return;
+ }
+ offset += frame.stream_frame.data_length;
+ } else {
+ if (!creator_.ConsumeCryptoData(ENCRYPTION_NONE,
+ reject.length() - offset, offset,
+ NOT_RETRANSMISSION, &frame)) {
+ QUIC_BUG << "Unable to consume crypto data into an empty packet.";
+ return;
+ }
+ offset += frame.crypto_frame->data_length;
+ }
if (offset < reject.length()) {
DCHECK(!creator_.HasRoomForStreamFrame(
QuicUtils::GetCryptoStreamId(framer_->transport_version()), offset,
@@ -267,7 +286,7 @@
} // namespace
QuicDispatcher::QuicDispatcher(
- const QuicConfig& config,
+ const QuicConfig* config,
const QuicCryptoServerConfig* crypto_config,
QuicVersionManager* version_manager,
std::unique_ptr<QuicConnectionHelperInterface> helper,
@@ -404,16 +423,13 @@
if (ShouldCreateSessionForUnknownVersion(framer_.last_version_label())) {
return true;
}
- if (!GetQuicReloadableFlag(quic_limit_version_negotiation) ||
- current_packet_->length() >= kMinPacketSizeForVersionNegotiation) {
+ if (current_packet_->length() >= kMinPacketSizeForVersionNegotiation) {
// Since the version is not supported, send a version negotiation
// packet and stop processing the current packet.
time_wait_list_manager()->SendVersionNegotiationPacket(
connection_id, header.form != GOOGLE_QUIC_PACKET,
GetSupportedVersions(), current_self_address_,
current_peer_address_, GetPerPacketContext());
- } else {
- QUIC_RELOADABLE_FLAG_COUNT(quic_limit_version_negotiation);
}
return false;
}
@@ -845,6 +861,10 @@
return false;
}
+void QuicDispatcher::OnCoalescedPacket(const QuicEncryptedPacket& /*packet*/) {
+ DCHECK(false);
+}
+
bool QuicDispatcher::OnStreamFrame(const QuicStreamFrame& /*frame*/) {
DCHECK(false);
return false;
@@ -1202,7 +1222,7 @@
ChloAlpnExtractor alpn_extractor;
if (FLAGS_quic_allow_chlo_buffering &&
!ChloExtractor::Extract(*current_packet_, GetSupportedVersions(),
- config_.create_session_tag_indicators(),
+ config_->create_session_tag_indicators(),
&alpn_extractor)) {
// Buffer non-CHLO packets.
ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id, form,
@@ -1224,7 +1244,7 @@
current_peer_address_, current_self_address_,
rejector.get());
if (!ChloExtractor::Extract(*current_packet_, GetSupportedVersions(),
- config_.create_session_tag_indicators(),
+ config_->create_session_tag_indicators(),
&validator)) {
ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id, form, version);
return;
@@ -1281,12 +1301,6 @@
current_packet_ = current_packet.get();
current_connection_id_ = rejector->connection_id();
framer_.set_version(first_version);
- if (GetQuicReloadableFlag(quic_fix_last_packet_is_ietf_quic)) {
- if (GetLastPacketFormat() != current_packet_format) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_fix_last_packet_is_ietf_quic);
- }
- framer_.set_last_packet_form(current_packet_format);
- }
// Stop buffering packets on this connection
const auto num_erased =
@@ -1385,8 +1399,4 @@
framer_.set_validate_flags(false);
}
-PacketHeaderFormat QuicDispatcher::GetLastPacketFormat() const {
- return framer_.GetLastPacketFormat();
-}
-
} // namespace quic
diff --git a/quic/core/quic_dispatcher.h b/quic/core/quic_dispatcher.h
index d6eb35b..b0c2509 100644
--- a/quic/core/quic_dispatcher.h
+++ b/quic/core/quic_dispatcher.h
@@ -44,7 +44,7 @@
// Ideally we'd have a linked_hash_set: the boolean is unused.
typedef QuicLinkedHashMap<QuicBlockedWriterInterface*, bool> WriteBlockedList;
- QuicDispatcher(const QuicConfig& config,
+ QuicDispatcher(const QuicConfig* config,
const QuicCryptoServerConfig* crypto_config,
QuicVersionManager* version_manager,
std::unique_ptr<QuicConnectionHelperInterface> helper,
@@ -143,6 +143,7 @@
const QuicVersionNegotiationPacket& packet) override;
void OnDecryptedPacket(EncryptionLevel level) override;
bool OnPacketHeader(const QuicPacketHeader& header) override;
+ void OnCoalescedPacket(const QuicEncryptedPacket& packet) override;
bool OnStreamFrame(const QuicStreamFrame& frame) override;
bool OnCryptoFrame(const QuicCryptoFrame& frame) override;
bool OnAckFrameStart(QuicPacketNumber largest_acked,
@@ -271,7 +272,7 @@
}
const QuicReceivedPacket& current_packet() const { return *current_packet_; }
- const QuicConfig& config() const { return config_; }
+ const QuicConfig& config() const { return *config_; }
const QuicCryptoServerConfig* crypto_config() const { return crypto_config_; }
@@ -351,11 +352,6 @@
// Skip validating that the public flags are set to legal values.
void DisableFlagValidation();
- // Please do not use this method.
- // TODO(fayang): Remove this method when deprecating
- // quic_fix_last_packet_is_ietf_quic flag.
- PacketHeaderFormat GetLastPacketFormat() const;
-
private:
friend class test::QuicDispatcherPeer;
friend class StatelessRejectorProcessDoneCallback;
@@ -410,7 +406,7 @@
new_sessions_allowed_per_event_loop_ = new_sessions_allowed_per_event_loop;
}
- const QuicConfig& config_;
+ const QuicConfig* config_;
const QuicCryptoServerConfig* crypto_config_;
diff --git a/quic/core/quic_dispatcher_test.cc b/quic/core/quic_dispatcher_test.cc
index 0381cf5..7fc1263 100644
--- a/quic/core/quic_dispatcher_test.cc
+++ b/quic/core/quic_dispatcher_test.cc
@@ -72,7 +72,7 @@
TestQuicSpdyServerSession& operator=(const TestQuicSpdyServerSession&) =
delete;
- ~TestQuicSpdyServerSession() override { delete connection(); };
+ ~TestQuicSpdyServerSession() override { delete connection(); }
MOCK_METHOD3(OnConnectionClosed,
void(QuicErrorCode error,
@@ -114,7 +114,7 @@
class TestDispatcher : public QuicDispatcher {
public:
- TestDispatcher(const QuicConfig& config,
+ TestDispatcher(const QuicConfig* config,
const QuicCryptoServerConfig* crypto_config,
QuicVersionManager* version_manager)
: QuicDispatcher(config,
@@ -157,7 +157,6 @@
using QuicDispatcher::current_client_address;
using QuicDispatcher::current_peer_address;
using QuicDispatcher::current_self_address;
- using QuicDispatcher::GetLastPacketFormat;
using QuicDispatcher::writer;
};
@@ -207,7 +206,8 @@
std::move(proof_source),
KeyExchangeSource::Default(),
TlsServerHandshaker::CreateSslCtx()),
- dispatcher_(new NiceMock<TestDispatcher>(config_,
+ server_address_(QuicIpAddress::Any4(), 5),
+ dispatcher_(new NiceMock<TestDispatcher>(&config_,
&crypto_config_,
&version_manager_)),
time_wait_list_manager_(nullptr),
@@ -370,9 +370,12 @@
};
TEST_F(QuicDispatcherTest, TlsClientHelloCreatesSession) {
+ if (CurrentSupportedVersions().front().transport_version < QUIC_VERSION_47) {
+ // TLS is only supported in versions 47 and greater.
+ return;
+ }
FLAGS_quic_supports_tls_handshake = true;
QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
- server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5);
EXPECT_CALL(*dispatcher_,
CreateQuicSession(TestConnectionId(1), client_address,
@@ -400,7 +403,6 @@
TEST_F(QuicDispatcherTest, ProcessPackets) {
QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
- server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5);
EXPECT_CALL(*dispatcher_,
CreateQuicSession(TestConnectionId(1), client_address,
@@ -448,7 +450,6 @@
// Regression test of b/93325907.
TEST_F(QuicDispatcherTest, DispatcherDoesNotRejectPacketNumberZero) {
QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
- server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5);
EXPECT_CALL(*dispatcher_,
CreateQuicSession(TestConnectionId(1), client_address,
@@ -486,9 +487,7 @@
TEST_F(QuicDispatcherTest, StatelessVersionNegotiation) {
CreateTimeWaitListManager();
- SetQuicReloadableFlag(quic_limit_version_negotiation, false);
QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
- server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5);
EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0);
EXPECT_CALL(*time_wait_list_manager_,
@@ -497,16 +496,17 @@
QuicTransportVersion version =
static_cast<QuicTransportVersion>(QuicTransportVersionMin() - 1);
ParsedQuicVersion parsed_version(PROTOCOL_QUIC_CRYPTO, version);
- ProcessPacket(client_address, TestConnectionId(1), true, parsed_version,
- SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID,
- PACKET_4BYTE_PACKET_NUMBER, 1);
+ // Pad the CHLO message with enough data to make the packet large enough
+ // to trigger version negotiation.
+ QuicString chlo = SerializeCHLO() + QuicString(1200, 'a');
+ DCHECK_LE(1200u, chlo.length());
+ ProcessPacket(client_address, TestConnectionId(1), true, parsed_version, chlo,
+ PACKET_8BYTE_CONNECTION_ID, PACKET_4BYTE_PACKET_NUMBER, 1);
}
TEST_F(QuicDispatcherTest, NoVersionNegotiationWithSmallPacket) {
CreateTimeWaitListManager();
- SetQuicReloadableFlag(quic_limit_version_negotiation, true);
QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
- server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5);
EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0);
EXPECT_CALL(*time_wait_list_manager_,
@@ -515,10 +515,12 @@
QuicTransportVersion version =
static_cast<QuicTransportVersion>(QuicTransportVersionMin() - 1);
ParsedQuicVersion parsed_version(PROTOCOL_QUIC_CRYPTO, version);
- QuicString chlo = SerializeCHLO();
+ QuicString chlo = SerializeCHLO() + QuicString(1200, 'a');
// Truncate to 1100 bytes of payload which results in a packet just
// under 1200 bytes after framing, packet, and encryption overhead.
+ DCHECK_LE(1200u, chlo.length());
QuicString truncated_chlo = chlo.substr(0, 1100);
+ DCHECK_EQ(1100u, truncated_chlo.length());
ProcessPacket(client_address, TestConnectionId(1), true, parsed_version,
truncated_chlo, PACKET_8BYTE_CONNECTION_ID,
PACKET_4BYTE_PACKET_NUMBER, 1);
@@ -607,7 +609,6 @@
CreateTimeWaitListManager();
QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 0);
- server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5);
// dispatcher_ should drop this packet.
EXPECT_CALL(*dispatcher_,
@@ -623,7 +624,6 @@
TEST_F(QuicDispatcherTest, OKSeqNoPacketProcessed) {
QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
QuicConnectionId connection_id = TestConnectionId(1);
- server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5);
EXPECT_CALL(*dispatcher_,
CreateQuicSession(TestConnectionId(1), client_address,
@@ -681,17 +681,15 @@
}
TEST_F(QuicDispatcherTest, SupportedTransportVersionsChangeInFlight) {
- static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u,
+ static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u,
"Supported versions out of sync");
- SetQuicReloadableFlag(quic_disable_version_35, false);
+ SetQuicReloadableFlag(quic_disable_version_39, false);
SetQuicReloadableFlag(quic_enable_version_43, true);
SetQuicReloadableFlag(quic_enable_version_44, true);
- SetQuicReloadableFlag(quic_enable_version_45, true);
SetQuicReloadableFlag(quic_enable_version_46, true);
SetQuicReloadableFlag(quic_enable_version_47, true);
SetQuicReloadableFlag(quic_enable_version_99, true);
QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
- server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5);
uint64_t conn_id = 1;
QuicConnectionId connection_id = TestConnectionId(conn_id);
@@ -808,39 +806,6 @@
SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID,
PACKET_4BYTE_PACKET_NUMBER, 1);
- // Turn off version 45.
- SetQuicReloadableFlag(quic_enable_version_45, false);
- connection_id = TestConnectionId(++conn_id);
- EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address,
- QuicStringPiece("hq"), _))
- .Times(0);
- ProcessPacket(client_address, connection_id, true,
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_45),
- SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID,
- PACKET_4BYTE_PACKET_NUMBER, 1);
-
- // Turn on version 45.
- SetQuicReloadableFlag(quic_enable_version_45, true);
- connection_id = TestConnectionId(++conn_id);
- EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address,
- QuicStringPiece("hq"), _))
- .WillOnce(testing::Return(CreateSession(
- dispatcher_.get(), config_, connection_id, client_address,
- &mock_helper_, &mock_alarm_factory_, &crypto_config_,
- QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
- EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
- ProcessUdpPacket(_, _, _))
- .WillOnce(WithArg<2>(
- Invoke([this, connection_id](const QuicEncryptedPacket& packet) {
- ValidatePacket(connection_id, packet);
- })));
- EXPECT_CALL(*dispatcher_,
- ShouldCreateOrBufferPacketForConnection(connection_id, _));
- ProcessPacket(client_address, connection_id, true,
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_45),
- SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID,
- PACKET_4BYTE_PACKET_NUMBER, 1);
-
// Turn off version 44.
SetQuicReloadableFlag(quic_enable_version_44, false);
connection_id = TestConnectionId(++conn_id);
@@ -907,19 +872,19 @@
SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID,
PACKET_4BYTE_PACKET_NUMBER, 1);
- // Turn off version 35.
- SetQuicReloadableFlag(quic_disable_version_35, true);
+ // Turn off version 39.
+ SetQuicReloadableFlag(quic_disable_version_39, true);
connection_id = TestConnectionId(++conn_id);
EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address,
QuicStringPiece("hq"), _))
.Times(0);
ProcessPacket(client_address, connection_id, true,
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_35),
+ ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_39),
SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID,
PACKET_4BYTE_PACKET_NUMBER, 1);
- // Turn on version 35.
- SetQuicReloadableFlag(quic_disable_version_35, false);
+ // Turn on version 39.
+ SetQuicReloadableFlag(quic_disable_version_39, false);
connection_id = TestConnectionId(++conn_id);
EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address,
QuicStringPiece("hq"), _))
@@ -936,7 +901,7 @@
EXPECT_CALL(*dispatcher_,
ShouldCreateOrBufferPacketForConnection(connection_id, _));
ProcessPacket(client_address, connection_id, true,
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_35),
+ ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_39),
SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID,
PACKET_4BYTE_PACKET_NUMBER, 1);
}
@@ -1067,9 +1032,9 @@
// Parameterized test for stateless rejects. Should test all
// combinations of enabling/disabling, reject/no-reject for stateless
// rejects.
-INSTANTIATE_TEST_CASE_P(QuicDispatcherStatelessRejectTests,
- QuicDispatcherStatelessRejectTest,
- ::testing::ValuesIn(GetStatelessRejectTestParams()));
+INSTANTIATE_TEST_SUITE_P(QuicDispatcherStatelessRejectTests,
+ QuicDispatcherStatelessRejectTest,
+ ::testing::ValuesIn(GetStatelessRejectTestParams()));
TEST_P(QuicDispatcherStatelessRejectTest, ParameterizedBasicTest) {
CreateTimeWaitListManager();
@@ -1624,6 +1589,7 @@
public:
BufferedPacketStoreTest()
: QuicDispatcherTest(),
+ server_addr_(QuicSocketAddress(QuicIpAddress::Any4(), 5)),
client_addr_(QuicIpAddress::Loopback4(), 1234),
signed_config_(new QuicSignedServerConfig) {
SetQuicReloadableFlag(quic_use_cheap_stateless_rejects,
@@ -1660,7 +1626,7 @@
CryptoHandshakeMessage full_chlo_;
};
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
BufferedPacketStoreTests,
BufferedPacketStoreTest,
::testing::ValuesIn(GetBufferedPacketStoreTestParams()));
@@ -1668,7 +1634,6 @@
TEST_P(BufferedPacketStoreTest, ProcessNonChloPacketsUptoLimitAndProcessChlo) {
InSequence s;
QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
- server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5);
QuicConnectionId conn_id = TestConnectionId(1);
// A bunch of non-CHLO should be buffered upon arrival, and the first one
// should trigger ShouldCreateOrBufferPacketForConnection().
@@ -1708,7 +1673,6 @@
TEST_P(BufferedPacketStoreTest,
ProcessNonChloPacketsForDifferentConnectionsUptoLimit) {
InSequence s;
- server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5);
// A bunch of non-CHLO should be buffered upon arrival.
size_t kNumConnections = kMaxConnectionsWithoutCHLO + 1;
for (size_t i = 1; i <= kNumConnections; ++i) {
@@ -1781,7 +1745,6 @@
TEST_P(BufferedPacketStoreTest, ReceiveRetransmittedCHLO) {
InSequence s;
QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
- server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5);
QuicConnectionId conn_id = TestConnectionId(1);
ProcessPacket(client_address, conn_id, true, QuicStrCat("data packet ", 2),
PACKET_8BYTE_CONNECTION_ID, PACKET_4BYTE_PACKET_NUMBER,
@@ -1817,7 +1780,6 @@
QuicBufferedPacketStorePeer::set_clock(store, mock_helper_.GetClock());
QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
- server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5);
QuicConnectionId conn_id = TestConnectionId(1);
ProcessPacket(client_address, conn_id, true, QuicStrCat("data packet ", 2),
PACKET_8BYTE_CONNECTION_ID, PACKET_4BYTE_PACKET_NUMBER,
@@ -2125,6 +2087,7 @@
client_addr_(QuicIpAddress::Loopback4(), 1234),
client_addr_2_(QuicIpAddress::Loopback4(), 1357),
crypto_config_peer_(&crypto_config_),
+ server_addr_(QuicIpAddress::Any4(), 5),
signed_config_(new QuicSignedServerConfig) {
SetQuicReloadableFlag(enable_quic_stateless_reject_support, true);
SetQuicReloadableFlag(quic_use_cheap_stateless_rejects, true);
@@ -2722,16 +2685,17 @@
// different endianness which causes the client to close the connection
// because of QUIC_INVALID_STREAM_DATA.
- SetQuicReloadableFlag(quic_disable_version_35, false);
- ParsedQuicVersion chlo_version(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_39);
+ SetQuicReloadableFlag(quic_disable_version_39, false);
+ SetQuicReloadableFlag(quic_enable_version_43, true);
+ ParsedQuicVersion chlo_version(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43);
chlo_.SetVersion(kVER, chlo_version);
- // Send a CHLO with v39. Dispatcher framer's version is set to v39.
+ // Send a CHLO with v43. Dispatcher framer's version is set to v43.
ProcessPacket(client_addr_, TestConnectionId(1), true, chlo_version,
SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID,
PACKET_4BYTE_PACKET_NUMBER, 1);
- // Send another CHLO with v35. Dispatcher framer's version is set to v35.
- chlo_version.transport_version = QUIC_VERSION_35;
+ // Send another CHLO with v39. Dispatcher framer's version is set to v39.
+ chlo_version.transport_version = QUIC_VERSION_39;
chlo_.SetVersion(kVER, chlo_version);
// Invalidate the cached serialized form.
chlo_.MarkDirty();
@@ -2740,7 +2704,7 @@
PACKET_4BYTE_PACKET_NUMBER, 1);
ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 2);
- // Complete the ProofSource::GetProof call for v39. This would cause the
+ // Complete the ProofSource::GetProof call for v43. This would cause the
// version mismatch between the CHLO packet and the dispatcher.
GetFakeProofSource()->InvokePendingCallback(0);
ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1);
@@ -2748,15 +2712,12 @@
// Regression test for b/116200989.
TEST_F(AsyncGetProofTest, DispatcherHasWrongLastPacketIsIetfQuic) {
- SetQuicReloadableFlag(quic_fix_last_packet_is_ietf_quic, true);
-
// Process a packet of v44.
ParsedQuicVersion chlo_version(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_44);
chlo_.SetVersion(kVER, chlo_version);
ProcessPacket(client_addr_, TestConnectionId(1), true, chlo_version,
SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID,
PACKET_4BYTE_PACKET_NUMBER, 1);
- EXPECT_NE(GOOGLE_QUIC_PACKET, dispatcher_->GetLastPacketFormat());
// Process another packet of v43.
chlo_version.transport_version = QUIC_VERSION_43;
@@ -2766,18 +2727,14 @@
ProcessPacket(client_addr_, TestConnectionId(2), true, chlo_version,
SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID,
PACKET_4BYTE_PACKET_NUMBER, 1);
- EXPECT_EQ(GOOGLE_QUIC_PACKET, dispatcher_->GetLastPacketFormat());
ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 2);
// Complete the ProofSource::GetProof call for v44.
GetFakeProofSource()->InvokePendingCallback(0);
- // Verify the last_packet_is_ietf_quic gets reset properly.
- EXPECT_NE(GOOGLE_QUIC_PACKET, dispatcher_->GetLastPacketFormat());
ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1);
// Complete the ProofSource::GetProof call for v43.
GetFakeProofSource()->InvokePendingCallback(0);
- EXPECT_EQ(GOOGLE_QUIC_PACKET, dispatcher_->GetLastPacketFormat());
ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 0);
}
diff --git a/quic/core/quic_epoll_alarm_factory.cc b/quic/core/quic_epoll_alarm_factory.cc
index 2ec2f6f..2d6efdf 100644
--- a/quic/core/quic_epoll_alarm_factory.cc
+++ b/quic/core/quic_epoll_alarm_factory.cc
@@ -69,7 +69,7 @@
QuicEpollAlarmFactory::QuicEpollAlarmFactory(QuicEpollServer* epoll_server)
: epoll_server_(epoll_server) {}
-QuicEpollAlarmFactory::~QuicEpollAlarmFactory() {}
+QuicEpollAlarmFactory::~QuicEpollAlarmFactory() = default;
QuicAlarm* QuicEpollAlarmFactory::CreateAlarm(QuicAlarm::Delegate* delegate) {
return new QuicEpollAlarm(epoll_server_,
diff --git a/quic/core/quic_epoll_alarm_factory_test.cc b/quic/core/quic_epoll_alarm_factory_test.cc
index b8d4caf..08a7cfe 100644
--- a/quic/core/quic_epoll_alarm_factory_test.cc
+++ b/quic/core/quic_epoll_alarm_factory_test.cc
@@ -40,9 +40,8 @@
QuicConnectionArena arena_;
};
-INSTANTIATE_TEST_CASE_P(UseArena,
- QuicEpollAlarmFactoryTest,
- ::testing::ValuesIn({true, false}));
+INSTANTIATE_TEST_SUITE_P(UseArena, QuicEpollAlarmFactoryTest,
+ ::testing::ValuesIn({true, false}));
TEST_P(QuicEpollAlarmFactoryTest, CreateAlarm) {
QuicArenaScopedPtr<TestDelegate> delegate =
diff --git a/quic/core/quic_epoll_connection_helper.cc b/quic/core/quic_epoll_connection_helper.cc
index 49002f6..e05139f 100644
--- a/quic/core/quic_epoll_connection_helper.cc
+++ b/quic/core/quic_epoll_connection_helper.cc
@@ -22,7 +22,7 @@
random_generator_(QuicRandom::GetInstance()),
allocator_type_(type) {}
-QuicEpollConnectionHelper::~QuicEpollConnectionHelper() {}
+QuicEpollConnectionHelper::~QuicEpollConnectionHelper() = default;
const QuicClock* QuicEpollConnectionHelper::GetClock() const {
return &clock_;
diff --git a/quic/core/quic_epoll_connection_helper.h b/quic/core/quic_epoll_connection_helper.h
index 62e030c..8b2a469 100644
--- a/quic/core/quic_epoll_connection_helper.h
+++ b/quic/core/quic_epoll_connection_helper.h
@@ -56,8 +56,6 @@
QuicBufferAllocator* GetStreamSendBufferAllocator() override;
private:
- friend class QuicEpollConnectionHelperPeer;
-
const QuicEpollClock clock_;
QuicRandom* random_generator_;
// Set up allocators. They take up minimal memory before use.
diff --git a/quic/core/quic_error_codes.cc b/quic/core/quic_error_codes.cc
index a6259e9..215f527 100644
--- a/quic/core/quic_error_codes.cc
+++ b/quic/core/quic_error_codes.cc
@@ -155,6 +155,7 @@
RETURN_STRING_LITERAL(QUIC_STREAM_ID_BLOCKED_ERROR);
RETURN_STRING_LITERAL(QUIC_MAX_STREAM_ID_ERROR);
RETURN_STRING_LITERAL(QUIC_HTTP_DECODER_ERROR);
+ RETURN_STRING_LITERAL(QUIC_STALE_CONNECTION_CANCELLED);
RETURN_STRING_LITERAL(QUIC_LAST_ERROR);
// Intentionally have no default case, so we'll break the build
diff --git a/quic/core/quic_error_codes.h b/quic/core/quic_error_codes.h
index ebf15f5..d3446a8 100644
--- a/quic/core/quic_error_codes.h
+++ b/quic/core/quic_error_codes.h
@@ -325,9 +325,11 @@
QUIC_MAX_STREAM_ID_ERROR = 119,
// Error in Http decoder
QUIC_HTTP_DECODER_ERROR = 120,
+ // Connection from stale host needs to be cancelled.
+ QUIC_STALE_CONNECTION_CANCELLED = 121,
// No error. Used as bound while iterating.
- QUIC_LAST_ERROR = 121,
+ QUIC_LAST_ERROR = 122,
};
// QuicErrorCodes is encoded as a single octet on-the-wire.
static_assert(static_cast<int>(QUIC_LAST_ERROR) <=
diff --git a/quic/core/quic_framer.cc b/quic/core/quic_framer.cc
index 1b93074..854b8c7 100644
--- a/quic/core/quic_framer.cc
+++ b/quic/core/quic_framer.cc
@@ -4,6 +4,7 @@
#include "net/third_party/quiche/src/quic/core/quic_framer.h"
+#include <cstddef>
#include <cstdint>
#include <memory>
@@ -23,12 +24,14 @@
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_aligned.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_fallthrough.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_stack_trace.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
@@ -186,7 +189,7 @@
uint8_t PacketNumberLengthToOnWireValue(
QuicTransportVersion version,
QuicPacketNumberLength packet_number_length) {
- if (version > QUIC_VERSION_46) {
+ if (version > QUIC_VERSION_44) {
return packet_number_length - 1;
}
switch (packet_number_length) {
@@ -209,7 +212,7 @@
QuicPacketNumberLength* packet_number_length) {
DCHECK(!(type & FLAGS_LONG_HEADER));
const bool two_bits_packet_number_length =
- infer_packet_header_type_from_version ? version > QUIC_VERSION_46
+ infer_packet_header_type_from_version ? version > QUIC_VERSION_44
: (type & FLAGS_FIXED_BIT);
if (two_bits_packet_number_length) {
*packet_number_length =
@@ -237,13 +240,13 @@
QuicLongHeaderType type) {
switch (type) {
case INITIAL:
- return version > QUIC_VERSION_46 ? 0 : 0x7F;
+ return version > QUIC_VERSION_44 ? 0 : 0x7F;
case ZERO_RTT_PROTECTED:
- return version > QUIC_VERSION_46 ? 1 << 4 : 0x7C;
+ return version > QUIC_VERSION_44 ? 1 << 4 : 0x7C;
case HANDSHAKE:
- return version > QUIC_VERSION_46 ? 2 << 4 : 0x7D;
+ return version > QUIC_VERSION_44 ? 2 << 4 : 0x7D;
case RETRY:
- return version > QUIC_VERSION_46 ? 3 << 4 : 0x7E;
+ return version > QUIC_VERSION_44 ? 3 << 4 : 0x7E;
case VERSION_NEGOTIATION:
return 0xF0; // Value does not matter
default:
@@ -256,7 +259,7 @@
uint8_t type,
QuicLongHeaderType* long_header_type) {
DCHECK((type & FLAGS_LONG_HEADER) && version != QUIC_VERSION_UNSUPPORTED);
- if (version > QUIC_VERSION_46) {
+ if (version > QUIC_VERSION_44) {
switch ((type & 0x30) >> 4) {
case 0:
*long_header_type = INITIAL;
@@ -303,7 +306,7 @@
QuicPacketNumberLength GetLongHeaderPacketNumberLength(
QuicTransportVersion version,
uint8_t type) {
- if (version > QUIC_VERSION_46) {
+ if (version > QUIC_VERSION_44) {
return static_cast<QuicPacketNumberLength>((type & 0x03) + 1);
}
return PACKET_4BYTE_PACKET_NUMBER;
@@ -343,6 +346,63 @@
version == QUIC_VERSION_99);
}
+// Convert a stream ID to a count of streams, for IETF QUIC/Version 99 only.
+// There is no need to take into account whether the ID is for uni- or
+// bi-directional streams, or whether it's server- or client- initiated. It
+// always returns a valid count.
+QuicStreamId StreamIdToCount(QuicTransportVersion version,
+ QuicStreamId stream_id) {
+ DCHECK_EQ(QUIC_VERSION_99, version);
+ if ((stream_id & 0x3) == 0) {
+ return (stream_id / QuicUtils::StreamIdDelta(version));
+ }
+ return (stream_id / QuicUtils::StreamIdDelta(version)) + 1;
+}
+
+// Returns the maximum value that a stream count may have, taking into account
+// the fact that bidirectional, client initiated, streams have one fewer stream
+// available than the others. This is because the old crypto streams, with ID ==
+// 0 are not included in the count.
+// The version is not included in the call, nor does the method take the version
+// into account, because this is called only from code used for IETF QUIC.
+// TODO(fkastenholz): Remove this method and replace calls to it with direct
+// references to kMaxQuicStreamIdCount when streamid 0 becomes a normal stream
+// id.
+QuicStreamId GetMaxStreamCount(bool unidirectional, Perspective perspective) {
+ if (!unidirectional && perspective == Perspective::IS_CLIENT) {
+ return kMaxQuicStreamId >> 2;
+ }
+ return (kMaxQuicStreamId >> 2) + 1;
+}
+
+// Convert a stream count to the maximum stream ID for that count.
+// Needs to know whether the resulting stream ID should be uni-directional,
+// bi-directional, server-initiated, or client-initiated.
+// Returns true if it works, false if not. The only error condition is that
+// the stream_count is too big and it would generate a stream id that is larger
+// than the implementation's maximum stream id value.
+bool StreamCountToId(QuicStreamId stream_count,
+ bool unidirectional,
+ Perspective perspective,
+ QuicTransportVersion version,
+ QuicStreamId* generated_stream_id) {
+ DCHECK_EQ(QUIC_VERSION_99, version);
+ // TODO(fkastenholz): when the MAX_STREAMS and STREAMS_BLOCKED frames
+ // are connected all the way up to the stream_id_manager, handle count==0
+ // properly (interpret it as "can open 0 streams") and the count being too
+ // large (close the connection).
+ if ((stream_count == 0) ||
+ (stream_count > GetMaxStreamCount(unidirectional, perspective))) {
+ return false;
+ }
+ *generated_stream_id =
+ ((unidirectional)
+ ? QuicUtils::GetFirstUnidirectionalStreamId(version, perspective)
+ : QuicUtils::GetFirstBidirectionalStreamId(version, perspective)) +
+ ((stream_count - 1) * QuicUtils::StreamIdDelta(version));
+ return true;
+}
+
} // namespace
QuicFramer::QuicFramer(const ParsedQuicVersionVector& supported_versions,
@@ -352,7 +412,6 @@
error_(QUIC_NO_ERROR),
last_serialized_connection_id_(EmptyQuicConnectionId()),
last_version_label_(0),
- last_header_form_(GOOGLE_QUIC_PACKET),
version_(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
supported_versions_(supported_versions),
decrypter_level_(ENCRYPTION_NONE),
@@ -485,7 +544,7 @@
if (version != QUIC_VERSION_99) {
return kQuicFrameTypeSize + kQuicMaxStreamIdSize + kQuicMaxStreamOffsetSize;
}
- if (frame.stream_id == 0) {
+ if (frame.stream_id == QuicUtils::GetInvalidStreamId(version)) {
// Frame would be a MAX DATA frame, which has only a Maximum Data field.
return kQuicFrameTypeSize +
QuicDataWriter::GetVarInt62Len(frame.byte_offset);
@@ -498,24 +557,32 @@
}
// static
-size_t QuicFramer::GetMaxStreamIdFrameSize(QuicTransportVersion version,
- const QuicMaxStreamIdFrame& frame) {
+size_t QuicFramer::GetMaxStreamsFrameSize(QuicTransportVersion version,
+ const QuicMaxStreamIdFrame& frame) {
if (version != QUIC_VERSION_99) {
QUIC_BUG << "In version " << version
<< " - not 99 - and tried to serialize MaxStreamId Frame.";
}
- return kQuicFrameTypeSize +
- QuicDataWriter::GetVarInt62Len(frame.max_stream_id);
+
+ // Convert from the stream id on which the connection is blocked to a count
+ QuicStreamId stream_count = StreamIdToCount(version, frame.max_stream_id);
+
+ return kQuicFrameTypeSize + QuicDataWriter::GetVarInt62Len(stream_count);
}
+
// static
-size_t QuicFramer::GetStreamIdBlockedFrameSize(
+size_t QuicFramer::GetStreamsBlockedFrameSize(
QuicTransportVersion version,
const QuicStreamIdBlockedFrame& frame) {
if (version != QUIC_VERSION_99) {
QUIC_BUG << "In version " << version
<< " - not 99 - and tried to serialize StreamIdBlocked Frame.";
}
- return kQuicFrameTypeSize + QuicDataWriter::GetVarInt62Len(frame.stream_id);
+
+ // Convert from the stream id on which the connection is blocked to a count
+ QuicStreamId stream_count = StreamIdToCount(version, frame.stream_id);
+
+ return kQuicFrameTypeSize + QuicDataWriter::GetVarInt62Len(stream_count);
}
// static
@@ -524,10 +591,7 @@
if (version != QUIC_VERSION_99) {
return kQuicFrameTypeSize + kQuicMaxStreamIdSize;
}
- // TODO(fkastenholz): This should be converted to use
- // QuicUtils::GetInvalidStreamId to get the correct invalid stream id value
- // and not rely on 0.
- if (frame.stream_id == 0) {
+ if (frame.stream_id == QuicUtils::GetInvalidStreamId(version)) {
// return size of IETF QUIC Blocked frame
return kQuicFrameTypeSize + QuicDataWriter::GetVarInt62Len(frame.offset);
}
@@ -591,10 +655,9 @@
case NEW_TOKEN_FRAME:
return GetNewTokenFrameSize(*frame.new_token_frame);
case MAX_STREAM_ID_FRAME:
- return GetMaxStreamIdFrameSize(version, frame.max_stream_id_frame);
+ return GetMaxStreamsFrameSize(version, frame.max_stream_id_frame);
case STREAM_ID_BLOCKED_FRAME:
- return GetStreamIdBlockedFrameSize(version,
- frame.stream_id_blocked_frame);
+ return GetStreamsBlockedFrameSize(version, frame.stream_id_blocked_frame);
case PATH_RESPONSE_FRAME:
return GetPathResponseFrameSize(*frame.path_response_frame);
case PATH_CHALLENGE_FRAME:
@@ -761,19 +824,63 @@
QuicFramer::AckFrameInfo::~AckFrameInfo() {}
+bool QuicFramer::WriteIetfLongHeaderLength(const QuicPacketHeader& header,
+ QuicDataWriter* writer,
+ size_t length_field_offset,
+ EncryptionLevel level) {
+ if (!QuicVersionHasLongHeaderLengths(transport_version()) ||
+ !header.version_flag || length_field_offset == 0) {
+ return true;
+ }
+ if (writer->length() < length_field_offset ||
+ writer->length() - length_field_offset <
+ kQuicDefaultLongHeaderLengthLength) {
+ set_detailed_error("Invalid length_field_offset.");
+ QUIC_BUG << "Invalid length_field_offset.";
+ return false;
+ }
+ size_t length_to_write = writer->length() - length_field_offset -
+ kQuicDefaultLongHeaderLengthLength;
+ // Add length of auth tag.
+ length_to_write = GetCiphertextSize(level, length_to_write);
+
+ QuicDataWriter length_writer(writer->length() - length_field_offset,
+ writer->data() + length_field_offset);
+ if (!length_writer.WriteVarInt62(length_to_write,
+ kQuicDefaultLongHeaderLengthLength)) {
+ set_detailed_error("Failed to overwrite long header length.");
+ QUIC_BUG << "Failed to overwrite long header length.";
+ return false;
+ }
+ return true;
+}
+
size_t QuicFramer::BuildDataPacket(const QuicPacketHeader& header,
const QuicFrames& frames,
char* buffer,
- size_t packet_length) {
- if (version_.transport_version == QUIC_VERSION_99) {
- return BuildIetfDataPacket(header, frames, buffer, packet_length);
- }
- QuicDataWriter writer(packet_length, buffer, endianness());
- if (!AppendPacketHeader(header, &writer)) {
+ size_t packet_length,
+ EncryptionLevel level) {
+ QuicDataWriter writer(packet_length, buffer);
+ size_t length_field_offset = 0;
+ if (!AppendPacketHeader(header, &writer, &length_field_offset)) {
QUIC_BUG << "AppendPacketHeader failed";
return 0;
}
+ if (transport_version() == QUIC_VERSION_99) {
+ if (AppendIetfFrames(frames, &writer) == 0) {
+ return 0;
+ }
+ if (!WriteIetfLongHeaderLength(header, &writer, length_field_offset,
+ level)) {
+ return 0;
+ }
+ return writer.length();
+ }
+ // TODO(dschinazi) if we enable long header lengths before v99, we need to
+ // add support for fixing up lengths in QuicFramer::BuildDataPacket.
+ DCHECK(!QuicVersionHasLongHeaderLengths(transport_version()));
+
size_t i = 0;
for (const QuicFrame& frame : frames) {
// Determine if we should write stream frame length in header.
@@ -893,173 +1000,11 @@
}
break;
case CRYPTO_FRAME:
- set_detailed_error(
- "Attempt to append CRYPTO frame and not in version 99.");
- return RaiseError(QUIC_INTERNAL_ERROR);
- default:
- RaiseError(QUIC_INVALID_FRAME_DATA);
- QUIC_BUG << "QUIC_INVALID_FRAME_DATA";
- return 0;
- }
- ++i;
- }
-
- return writer.length();
-}
-
-size_t QuicFramer::BuildIetfDataPacket(const QuicPacketHeader& header,
- const QuicFrames& frames,
- char* buffer,
- size_t packet_length) {
- QuicDataWriter writer(packet_length, buffer, endianness());
- if (!AppendIetfPacketHeader(header, &writer)) {
- QUIC_BUG << "AppendPacketHeader failed";
- return 0;
- }
-
- size_t i = 0;
- for (const QuicFrame& frame : frames) {
- // Determine if we should write stream frame length in header.
- const bool last_frame_in_packet = i == frames.size() - 1;
- if (!AppendIetfTypeByte(frame, last_frame_in_packet, &writer)) {
- QUIC_BUG << "AppendIetfTypeByte failed";
- return 0;
- }
-
- switch (frame.type) {
- case PADDING_FRAME:
- if (!AppendPaddingFrame(frame.padding_frame, &writer)) {
- QUIC_BUG << "AppendPaddingFrame of "
- << frame.padding_frame.num_padding_bytes << " failed";
- return 0;
+ if (version_.transport_version < QUIC_VERSION_47) {
+ set_detailed_error(
+ "Attempt to append CRYPTO frame in version prior to 47.");
+ return RaiseError(QUIC_INTERNAL_ERROR);
}
- break;
- case STREAM_FRAME:
- if (!AppendStreamFrame(frame.stream_frame, last_frame_in_packet,
- &writer)) {
- QUIC_BUG << "AppendStreamFrame failed";
- return 0;
- }
- break;
- case ACK_FRAME:
- if (!AppendIetfAckFrameAndTypeByte(*frame.ack_frame, &writer)) {
- QUIC_BUG << "AppendAckFrameAndTypeByte failed";
- return 0;
- }
- break;
- case STOP_WAITING_FRAME:
- set_detailed_error(
- "Attempt to append STOP WAITING frame in version 99.");
- return RaiseError(QUIC_INTERNAL_ERROR);
- case MTU_DISCOVERY_FRAME:
- // MTU discovery frames are serialized as ping frames.
- QUIC_FALLTHROUGH_INTENDED;
- case PING_FRAME:
- // Ping has no payload.
- break;
- case RST_STREAM_FRAME:
- if (!AppendRstStreamFrame(*frame.rst_stream_frame, &writer)) {
- QUIC_BUG << "AppendRstStreamFrame failed";
- return 0;
- }
- break;
- case CONNECTION_CLOSE_FRAME:
- if (!AppendConnectionCloseFrame(*frame.connection_close_frame,
- &writer)) {
- QUIC_BUG << "AppendConnectionCloseFrame failed";
- return 0;
- }
- break;
- case GOAWAY_FRAME:
- set_detailed_error("Attempt to append GOAWAY frame in version 99.");
- return RaiseError(QUIC_INTERNAL_ERROR);
- case WINDOW_UPDATE_FRAME:
- // Depending on whether there is a stream ID or not, will be either a
- // MAX STREAM DATA frame or a MAX DATA frame.
- if (frame.window_update_frame->stream_id == 0) {
- if (!AppendMaxDataFrame(*frame.window_update_frame, &writer)) {
- QUIC_BUG << "AppendMaxDataFrame failed";
- return 0;
- }
- } else {
- if (!AppendMaxStreamDataFrame(*frame.window_update_frame, &writer)) {
- QUIC_BUG << "AppendMaxStreamDataFrame failed";
- return 0;
- }
- }
- break;
- case BLOCKED_FRAME:
- if (!AppendBlockedFrame(*frame.blocked_frame, &writer)) {
- QUIC_BUG << "AppendBlockedFrame failed";
- return 0;
- }
- break;
- case APPLICATION_CLOSE_FRAME:
- if (!AppendApplicationCloseFrame(*frame.application_close_frame,
- &writer)) {
- QUIC_BUG << "AppendApplicationCloseFrame failed";
- return 0;
- }
- break;
- case MAX_STREAM_ID_FRAME:
- if (!AppendMaxStreamIdFrame(frame.max_stream_id_frame, &writer)) {
- QUIC_BUG << "AppendMaxStreamIdFrame failed";
- return 0;
- }
- break;
- case STREAM_ID_BLOCKED_FRAME:
- if (!AppendStreamIdBlockedFrame(frame.stream_id_blocked_frame,
- &writer)) {
- QUIC_BUG << "AppendMaxStreamIdFrame failed";
- return 0;
- }
- break;
- case NEW_CONNECTION_ID_FRAME:
- if (!AppendNewConnectionIdFrame(*frame.new_connection_id_frame,
- &writer)) {
- QUIC_BUG << "AppendNewConnectionIdFrame failed";
- return 0;
- }
- break;
- case RETIRE_CONNECTION_ID_FRAME:
- if (!AppendRetireConnectionIdFrame(*frame.retire_connection_id_frame,
- &writer)) {
- QUIC_BUG << "AppendRetireConnectionIdFrame failed";
- return 0;
- }
- break;
- case NEW_TOKEN_FRAME:
- if (!AppendNewTokenFrame(*frame.new_token_frame, &writer)) {
- QUIC_BUG << "AppendNewTokenFrame failed";
- return 0;
- }
- break;
- case STOP_SENDING_FRAME:
- if (!AppendStopSendingFrame(*frame.stop_sending_frame, &writer)) {
- QUIC_BUG << "AppendStopSendingFrame failed";
- return 0;
- }
- break;
- case PATH_CHALLENGE_FRAME:
- if (!AppendPathChallengeFrame(*frame.path_challenge_frame, &writer)) {
- QUIC_BUG << "AppendPathChallengeFrame failed";
- return 0;
- }
- break;
- case PATH_RESPONSE_FRAME:
- if (!AppendPathResponseFrame(*frame.path_response_frame, &writer)) {
- QUIC_BUG << "AppendPathResponseFrame failed";
- return 0;
- }
- break;
- case MESSAGE_FRAME:
- if (!AppendMessageFrameAndTypeByte(*frame.message_frame,
- last_frame_in_packet, &writer)) {
- QUIC_BUG << "AppendMessageFrame failed";
- return 0;
- }
- break;
- case CRYPTO_FRAME:
if (!AppendCryptoFrame(*frame.crypto_frame, &writer)) {
QUIC_BUG << "AppendCryptoFrame failed";
return 0;
@@ -1076,10 +1021,176 @@
return writer.length();
}
-size_t QuicFramer::BuildIetfConnectivityProbingPacket(
+size_t QuicFramer::AppendIetfFrames(const QuicFrames& frames,
+ QuicDataWriter* writer) {
+ size_t i = 0;
+ for (const QuicFrame& frame : frames) {
+ // Determine if we should write stream frame length in header.
+ const bool last_frame_in_packet = i == frames.size() - 1;
+ if (!AppendIetfTypeByte(frame, last_frame_in_packet, writer)) {
+ QUIC_BUG << "AppendIetfTypeByte failed: " << detailed_error();
+ return 0;
+ }
+
+ switch (frame.type) {
+ case PADDING_FRAME:
+ if (!AppendPaddingFrame(frame.padding_frame, writer)) {
+ QUIC_BUG << "AppendPaddingFrame of "
+ << frame.padding_frame.num_padding_bytes
+ << " failed: " << detailed_error();
+ return 0;
+ }
+ break;
+ case STREAM_FRAME:
+ if (!AppendStreamFrame(frame.stream_frame, last_frame_in_packet,
+ writer)) {
+ QUIC_BUG << "AppendStreamFrame failed: " << detailed_error();
+ return 0;
+ }
+ break;
+ case ACK_FRAME:
+ if (!AppendIetfAckFrameAndTypeByte(*frame.ack_frame, writer)) {
+ QUIC_BUG << "AppendAckFrameAndTypeByte failed: " << detailed_error();
+ return 0;
+ }
+ break;
+ case STOP_WAITING_FRAME:
+ set_detailed_error(
+ "Attempt to append STOP WAITING frame in version 99.");
+ return RaiseError(QUIC_INTERNAL_ERROR);
+ case MTU_DISCOVERY_FRAME:
+ // MTU discovery frames are serialized as ping frames.
+ QUIC_FALLTHROUGH_INTENDED;
+ case PING_FRAME:
+ // Ping has no payload.
+ break;
+ case RST_STREAM_FRAME:
+ if (!AppendRstStreamFrame(*frame.rst_stream_frame, writer)) {
+ QUIC_BUG << "AppendRstStreamFrame failed: " << detailed_error();
+ return 0;
+ }
+ break;
+ case CONNECTION_CLOSE_FRAME:
+ if (!AppendConnectionCloseFrame(*frame.connection_close_frame,
+ writer)) {
+ QUIC_BUG << "AppendConnectionCloseFrame failed: " << detailed_error();
+ return 0;
+ }
+ break;
+ case GOAWAY_FRAME:
+ set_detailed_error("Attempt to append GOAWAY frame in version 99.");
+ return RaiseError(QUIC_INTERNAL_ERROR);
+ case WINDOW_UPDATE_FRAME:
+ // Depending on whether there is a stream ID or not, will be either a
+ // MAX STREAM DATA frame or a MAX DATA frame.
+ if (frame.window_update_frame->stream_id ==
+ QuicUtils::GetInvalidStreamId(transport_version())) {
+ if (!AppendMaxDataFrame(*frame.window_update_frame, writer)) {
+ QUIC_BUG << "AppendMaxDataFrame failed: " << detailed_error();
+ return 0;
+ }
+ } else {
+ if (!AppendMaxStreamDataFrame(*frame.window_update_frame, writer)) {
+ QUIC_BUG << "AppendMaxStreamDataFrame failed: " << detailed_error();
+ return 0;
+ }
+ }
+ break;
+ case BLOCKED_FRAME:
+ if (!AppendBlockedFrame(*frame.blocked_frame, writer)) {
+ QUIC_BUG << "AppendBlockedFrame failed: " << detailed_error();
+ return 0;
+ }
+ break;
+ case APPLICATION_CLOSE_FRAME:
+ if (!AppendApplicationCloseFrame(*frame.application_close_frame,
+ writer)) {
+ QUIC_BUG << "AppendApplicationCloseFrame failed: "
+ << detailed_error();
+ return 0;
+ }
+ break;
+ case MAX_STREAM_ID_FRAME:
+ if (!AppendMaxStreamsFrame(frame.max_stream_id_frame, writer)) {
+ QUIC_BUG << "AppendMaxStreamsFrame failed" << detailed_error();
+ return 0;
+ }
+ break;
+ case STREAM_ID_BLOCKED_FRAME:
+ if (!AppendStreamsBlockedFrame(frame.stream_id_blocked_frame, writer)) {
+ QUIC_BUG << "AppendStreamsBlockedFrame failed" << detailed_error();
+ return 0;
+ }
+ break;
+ case NEW_CONNECTION_ID_FRAME:
+ if (!AppendNewConnectionIdFrame(*frame.new_connection_id_frame,
+ writer)) {
+ QUIC_BUG << "AppendNewConnectionIdFrame failed: " << detailed_error();
+ return 0;
+ }
+ break;
+ case RETIRE_CONNECTION_ID_FRAME:
+ if (!AppendRetireConnectionIdFrame(*frame.retire_connection_id_frame,
+ writer)) {
+ QUIC_BUG << "AppendRetireConnectionIdFrame failed: "
+ << detailed_error();
+ return 0;
+ }
+ break;
+ case NEW_TOKEN_FRAME:
+ if (!AppendNewTokenFrame(*frame.new_token_frame, writer)) {
+ QUIC_BUG << "AppendNewTokenFrame failed: " << detailed_error();
+ return 0;
+ }
+ break;
+ case STOP_SENDING_FRAME:
+ if (!AppendStopSendingFrame(*frame.stop_sending_frame, writer)) {
+ QUIC_BUG << "AppendStopSendingFrame failed: " << detailed_error();
+ return 0;
+ }
+ break;
+ case PATH_CHALLENGE_FRAME:
+ if (!AppendPathChallengeFrame(*frame.path_challenge_frame, writer)) {
+ QUIC_BUG << "AppendPathChallengeFrame failed: " << detailed_error();
+ return 0;
+ }
+ break;
+ case PATH_RESPONSE_FRAME:
+ if (!AppendPathResponseFrame(*frame.path_response_frame, writer)) {
+ QUIC_BUG << "AppendPathResponseFrame failed: " << detailed_error();
+ return 0;
+ }
+ break;
+ case MESSAGE_FRAME:
+ if (!AppendMessageFrameAndTypeByte(*frame.message_frame,
+ last_frame_in_packet, writer)) {
+ QUIC_BUG << "AppendMessageFrame failed: " << detailed_error();
+ return 0;
+ }
+ break;
+ case CRYPTO_FRAME:
+ if (!AppendCryptoFrame(*frame.crypto_frame, writer)) {
+ QUIC_BUG << "AppendCryptoFrame failed: " << detailed_error();
+ return 0;
+ }
+ break;
+ default:
+ RaiseError(QUIC_INVALID_FRAME_DATA);
+ set_detailed_error("Tried to append unknown frame type.");
+ QUIC_BUG << "QUIC_INVALID_FRAME_DATA";
+ return 0;
+ }
+ ++i;
+ }
+
+ return writer->length();
+}
+
+size_t QuicFramer::BuildConnectivityProbingPacketNew(
const QuicPacketHeader& header,
char* buffer,
- size_t packet_length) {
+ size_t packet_length,
+ EncryptionLevel level) {
QuicFrames frames;
// Write a PING frame, which has no data payload.
@@ -1090,19 +1201,26 @@
QuicPaddingFrame padding_frame;
frames.push_back(QuicFrame(padding_frame));
- return BuildIetfDataPacket(header, frames, buffer, packet_length);
+ return BuildDataPacket(header, frames, buffer, packet_length, level);
}
size_t QuicFramer::BuildConnectivityProbingPacket(
const QuicPacketHeader& header,
char* buffer,
- size_t packet_length) {
- if (version_.transport_version == QUIC_VERSION_99) {
- return BuildIetfConnectivityProbingPacket(header, buffer, packet_length);
+ size_t packet_length,
+ EncryptionLevel level) {
+ if (transport_version() == QUIC_VERSION_99 ||
+ QuicVersionHasLongHeaderLengths(transport_version()) ||
+ GetQuicReloadableFlag(quic_simplify_build_connectivity_probing_packet)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_simplify_build_connectivity_probing_packet);
+ // TODO(rch): Remove this method when the flag is deprecated.
+ return BuildConnectivityProbingPacketNew(header, buffer, packet_length,
+ level);
}
- QuicDataWriter writer(packet_length, buffer, endianness());
- if (!AppendPacketHeader(header, &writer)) {
+ QuicDataWriter writer(packet_length, buffer);
+
+ if (!AppendPacketHeader(header, &writer, nullptr)) {
QUIC_BUG << "AppendPacketHeader failed";
return 0;
}
@@ -1133,7 +1251,8 @@
char* buffer,
size_t packet_length,
QuicPathFrameBuffer* payload,
- QuicRandom* randomizer) {
+ QuicRandom* randomizer,
+ EncryptionLevel level) {
if (version_.transport_version != QUIC_VERSION_99) {
QUIC_BUG << "Attempt to build a PATH_CHALLENGE Connectivity Probing "
"packet and not doing IETF QUIC";
@@ -1152,7 +1271,7 @@
QuicPaddingFrame padding_frame;
frames.push_back(QuicFrame(padding_frame));
- return BuildIetfDataPacket(header, frames, buffer, packet_length);
+ return BuildDataPacket(header, frames, buffer, packet_length, level);
}
size_t QuicFramer::BuildPathResponsePacket(
@@ -1160,7 +1279,8 @@
char* buffer,
size_t packet_length,
const QuicDeque<QuicPathFrameBuffer>& payloads,
- const bool is_padded) {
+ const bool is_padded,
+ EncryptionLevel level) {
if (payloads.empty()) {
QUIC_BUG
<< "Attempt to generate connectivity response with no request payloads";
@@ -1192,7 +1312,7 @@
frames.push_back(QuicFrame(padding_frame));
}
- return BuildIetfDataPacket(header, frames, buffer, packet_length);
+ return BuildDataPacket(header, frames, buffer, packet_length, level);
}
// static
@@ -1221,7 +1341,7 @@
std::unique_ptr<char[]> buffer(new char[len]);
// Endianness is not a concern here, as writer is not going to write integers
// or floating numbers.
- QuicDataWriter writer(len, buffer.get(), NETWORK_BYTE_ORDER);
+ QuicDataWriter writer(len, buffer.get());
uint8_t flags = static_cast<uint8_t>(PACKET_PUBLIC_FLAGS_RST |
PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID);
@@ -1231,7 +1351,7 @@
return nullptr;
}
- if (!writer.WriteConnectionId(packet.connection_id, Perspective::IS_SERVER)) {
+ if (!writer.WriteConnectionId(packet.connection_id)) {
return nullptr;
}
@@ -1255,7 +1375,7 @@
size_t len = kPacketHeaderTypeSize + random_bytes_length +
sizeof(stateless_reset_token);
std::unique_ptr<char[]> buffer(new char[len]);
- QuicDataWriter writer(len, buffer.get(), NETWORK_BYTE_ORDER);
+ QuicDataWriter writer(len, buffer.get());
uint8_t type = 0;
type |= FLAGS_FIXED_BIT;
@@ -1306,7 +1426,7 @@
std::unique_ptr<char[]> buffer(new char[len]);
// Endianness is not a concern here, version negotiation packet does not have
// integers or floating numbers.
- QuicDataWriter writer(len, buffer.get(), NETWORK_BYTE_ORDER);
+ QuicDataWriter writer(len, buffer.get());
uint8_t flags = static_cast<uint8_t>(
PACKET_PUBLIC_FLAGS_VERSION | PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID |
@@ -1316,7 +1436,7 @@
return nullptr;
}
- if (!writer.WriteConnectionId(connection_id, Perspective::IS_SERVER)) {
+ if (!writer.WriteConnectionId(connection_id)) {
return nullptr;
}
@@ -1342,7 +1462,7 @@
PACKET_8BYTE_CONNECTION_ID +
(versions.size() + 1) * kQuicVersionSize;
std::unique_ptr<char[]> buffer(new char[len]);
- QuicDataWriter writer(len, buffer.get(), NETWORK_BYTE_ORDER);
+ QuicDataWriter writer(len, buffer.get());
// TODO(fayang): Randomly select a value for the type.
uint8_t type = static_cast<uint8_t>(FLAGS_LONG_HEADER | VERSION_NEGOTIATION);
@@ -1356,8 +1476,7 @@
if (!AppendIetfConnectionId(true, EmptyQuicConnectionId(),
PACKET_0BYTE_CONNECTION_ID, connection_id,
- PACKET_8BYTE_CONNECTION_ID, &writer,
- Perspective::IS_SERVER)) {
+ PACKET_8BYTE_CONNECTION_ID, &writer)) {
return nullptr;
}
@@ -1373,7 +1492,7 @@
}
bool QuicFramer::ProcessPacket(const QuicEncryptedPacket& packet) {
- QuicDataReader reader(packet.data(), packet.length(), endianness());
+ QuicDataReader reader(packet.data(), packet.length());
bool last_packet_is_ietf_quic = false;
if (infer_packet_header_type_from_version_) {
@@ -1384,7 +1503,6 @@
}
if (last_packet_is_ietf_quic) {
QUIC_DVLOG(1) << ENDPOINT << "Processing IETF QUIC packet.";
- reader.set_endianness(NETWORK_BYTE_ORDER);
}
visitor_->OnPacket();
@@ -1397,7 +1515,6 @@
DCHECK_NE("", detailed_error_);
return RaiseError(QUIC_INVALID_PACKET_HEADER);
}
- last_header_form_ = header.form;
if (!visitor_->OnUnauthenticatedPublicHeader(header)) {
// The visitor suppresses further processing of the packet.
@@ -1411,9 +1528,6 @@
}
}
- // framer's version may change, reset reader's endianness.
- reader.set_endianness(endianness());
-
bool rv;
if (IsVersionNegotiation(header, last_packet_is_ietf_quic)) {
QUIC_DVLOG(1) << ENDPOINT << "Received version negotiation packet";
@@ -1467,6 +1581,119 @@
return true;
}
+bool QuicFramer::MaybeProcessIetfInitialRetryToken(
+ QuicDataReader* encrypted_reader,
+ QuicPacketHeader* header) {
+ if (!QuicVersionHasLongHeaderLengths(header->version.transport_version) ||
+ header->form != IETF_QUIC_LONG_HEADER_PACKET ||
+ header->long_packet_type != INITIAL) {
+ return true;
+ }
+ uint64_t retry_token_length = 0;
+ header->retry_token_length_length = encrypted_reader->PeekVarInt62Length();
+ if (!encrypted_reader->ReadVarInt62(&retry_token_length)) {
+ set_detailed_error("Unable to read INITIAL retry token length.");
+ return RaiseError(QUIC_INVALID_PACKET_HEADER);
+ }
+ header->retry_token = encrypted_reader->PeekRemainingPayload();
+ // Safety check to avoid spending ressources if malformed.
+ // At this point header->retry_token contains the rest of the packet
+ // so its length() is the amount of data remaining in the packet.
+ if (retry_token_length > header->retry_token.length()) {
+ set_detailed_error("INITIAL token length longer than packet.");
+ return RaiseError(QUIC_INVALID_PACKET_HEADER);
+ }
+ // Resize retry_token to make it only contain the retry token.
+ header->retry_token.remove_suffix(header->retry_token.length() -
+ retry_token_length);
+ // Advance encrypted_reader by retry_token_length.
+ uint8_t wasted_byte;
+ for (uint64_t i = 0; i < retry_token_length; ++i) {
+ if (!encrypted_reader->ReadUInt8(&wasted_byte)) {
+ set_detailed_error("Unable to read INITIAL retry token.");
+ return RaiseError(QUIC_INVALID_PACKET_HEADER);
+ }
+ }
+ return true;
+}
+
+// Seeks the current packet to check for a coalesced packet at the end.
+// If the IETF length field only spans part of the outer packet,
+// then there is a coalesced packet after this one.
+void QuicFramer::MaybeProcessCoalescedPacket(
+ const QuicDataReader& encrypted_reader,
+ uint64_t remaining_bytes_length,
+ const QuicPacketHeader& header) {
+ if (header.remaining_packet_length >= remaining_bytes_length) {
+ // There is no coalesced packet.
+ return;
+ }
+
+ QuicStringPiece remaining_data = encrypted_reader.PeekRemainingPayload();
+ DCHECK_EQ(remaining_data.length(), remaining_bytes_length);
+
+ const char* coalesced_data =
+ remaining_data.data() + header.remaining_packet_length;
+ uint64_t coalesced_data_length =
+ remaining_bytes_length - header.remaining_packet_length;
+ QuicDataReader coalesced_reader(coalesced_data, coalesced_data_length);
+
+ QuicPacketHeader coalesced_header;
+ if (!ProcessIetfPacketHeader(&coalesced_reader, &coalesced_header)) {
+ QUIC_PEER_BUG << ENDPOINT
+ << "Failed to parse received coalesced header of length "
+ << coalesced_data_length << ": "
+ << QuicTextUtils::HexEncode(coalesced_data,
+ coalesced_data_length)
+ << " previous header was " << header;
+ return;
+ }
+
+ 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 "
+ << coalesced_header << " previous header was " << header;
+ return;
+ }
+
+ QuicEncryptedPacket coalesced_packet(coalesced_data, coalesced_data_length,
+ /*owns_buffer=*/false);
+ visitor_->OnCoalescedPacket(coalesced_packet);
+}
+
+bool QuicFramer::MaybeProcessIetfLength(QuicDataReader* encrypted_reader,
+ QuicPacketHeader* header) {
+ if (!QuicVersionHasLongHeaderLengths(header->version.transport_version) ||
+ header->form != IETF_QUIC_LONG_HEADER_PACKET ||
+ (header->long_packet_type != INITIAL &&
+ header->long_packet_type != HANDSHAKE &&
+ header->long_packet_type != ZERO_RTT_PROTECTED)) {
+ return true;
+ }
+ header->length_length = encrypted_reader->PeekVarInt62Length();
+ if (!encrypted_reader->ReadVarInt62(&header->remaining_packet_length)) {
+ set_detailed_error("Unable to read long header payload length.");
+ return RaiseError(QUIC_INVALID_PACKET_HEADER);
+ }
+ uint64_t remaining_bytes_length = encrypted_reader->BytesRemaining();
+ if (header->remaining_packet_length > remaining_bytes_length) {
+ set_detailed_error("Long header payload length longer than packet.");
+ return RaiseError(QUIC_INVALID_PACKET_HEADER);
+ }
+
+ MaybeProcessCoalescedPacket(*encrypted_reader, remaining_bytes_length,
+ *header);
+
+ if (!encrypted_reader->TruncateRemaining(header->remaining_packet_length)) {
+ set_detailed_error("Length TruncateRemaining failed.");
+ QUIC_BUG << "Length TruncateRemaining failed.";
+ return RaiseError(QUIC_INVALID_PACKET_HEADER);
+ }
+ return true;
+}
+
bool QuicFramer::ProcessIetfDataPacket(QuicDataReader* encrypted_reader,
QuicPacketHeader* header,
const QuicEncryptedPacket& packet,
@@ -1474,6 +1701,10 @@
size_t buffer_length) {
DCHECK_NE(GOOGLE_QUIC_PACKET, header->form);
DCHECK(!header->has_possible_stateless_reset_token);
+ header->retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_0;
+ header->retry_token = QuicStringPiece();
+ header->length_length = VARIABLE_LENGTH_INTEGER_LENGTH_0;
+ header->remaining_packet_length = 0;
if (header->form == IETF_QUIC_SHORT_HEADER_PACKET &&
perspective_ == Perspective::IS_CLIENT) {
// Peek possible stateless reset token. Will only be used on decryption
@@ -1488,6 +1719,14 @@
}
}
+ if (!MaybeProcessIetfInitialRetryToken(encrypted_reader, header)) {
+ return false;
+ }
+
+ if (!MaybeProcessIetfLength(encrypted_reader, header)) {
+ return false;
+ }
+
if (header->form == IETF_QUIC_SHORT_HEADER_PACKET ||
header->long_packet_type != VERSION_NEGOTIATION) {
// Process packet number.
@@ -1518,7 +1757,8 @@
// using QUIC crypto.
if (header->form == IETF_QUIC_LONG_HEADER_PACKET &&
header->long_packet_type == ZERO_RTT_PROTECTED &&
- perspective_ == Perspective::IS_CLIENT) {
+ perspective_ == Perspective::IS_CLIENT &&
+ version_.handshake_protocol == PROTOCOL_QUIC_CRYPTO) {
if (!encrypted_reader->ReadBytes(
reinterpret_cast<uint8_t*>(last_nonce_.data()),
last_nonce_.size())) {
@@ -1537,8 +1777,17 @@
return false;
}
+ QuicStringPiece encrypted = encrypted_reader->ReadRemainingPayload();
+ QuicStringPiece associated_data = GetAssociatedDataFromEncryptedPacket(
+ version_.transport_version, packet,
+ header->destination_connection_id_length,
+ header->source_connection_id_length, header->version_flag,
+ header->nonce != nullptr, header->packet_number_length,
+ header->retry_token_length_length, header->retry_token.length(),
+ header->length_length);
+
size_t decrypted_length = 0;
- if (!DecryptPayload(encrypted_reader, *header, packet, decrypted_buffer,
+ if (!DecryptPayload(encrypted, associated_data, *header, decrypted_buffer,
buffer_length, &decrypted_length)) {
if (IsIetfStatelessResetPacket(*header)) {
// This is a stateless reset packet.
@@ -1550,7 +1799,7 @@
set_detailed_error("Unable to decrypt payload.");
return RaiseError(QUIC_DECRYPTION_FAILURE);
}
- QuicDataReader reader(decrypted_buffer, decrypted_length, endianness());
+ QuicDataReader reader(decrypted_buffer, decrypted_length);
// Update the largest packet number after we have decrypted the packet
// so we are confident is not attacker controlled.
@@ -1609,14 +1858,23 @@
return false;
}
+ QuicStringPiece encrypted = encrypted_reader->ReadRemainingPayload();
+ QuicStringPiece associated_data = GetAssociatedDataFromEncryptedPacket(
+ version_.transport_version, packet,
+ header->destination_connection_id_length,
+ header->source_connection_id_length, header->version_flag,
+ header->nonce != nullptr, header->packet_number_length,
+ header->retry_token_length_length, header->retry_token.length(),
+ header->length_length);
+
size_t decrypted_length = 0;
- if (!DecryptPayload(encrypted_reader, *header, packet, decrypted_buffer,
+ if (!DecryptPayload(encrypted, associated_data, *header, decrypted_buffer,
buffer_length, &decrypted_length)) {
set_detailed_error("Unable to decrypt payload.");
return RaiseError(QUIC_DECRYPTION_FAILURE);
}
- QuicDataReader reader(decrypted_buffer, decrypted_length, endianness());
+ QuicDataReader reader(decrypted_buffer, decrypted_length);
// Update the largest packet number after we have decrypted the packet
// so we are confident is not attacker controlled.
@@ -1704,9 +1962,10 @@
}
bool QuicFramer::AppendPacketHeader(const QuicPacketHeader& header,
- QuicDataWriter* writer) {
+ QuicDataWriter* writer,
+ size_t* length_field_offset) {
if (transport_version() > QUIC_VERSION_43) {
- return AppendIetfPacketHeader(header, writer);
+ return AppendIetfPacketHeader(header, writer, length_field_offset);
}
QUIC_DVLOG(1) << ENDPOINT << "Appending header: " << header;
uint8_t public_flags = 0;
@@ -1745,8 +2004,7 @@
public_flags |= PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID_OLD;
}
if (!writer->WriteUInt8(public_flags) ||
- !writer->WriteConnectionId(header.destination_connection_id,
- perspective_)) {
+ !writer->WriteConnectionId(header.destination_connection_id)) {
return false;
}
break;
@@ -1781,7 +2039,7 @@
bool QuicFramer::AppendIetfHeaderTypeByte(const QuicPacketHeader& header,
QuicDataWriter* writer) {
uint8_t type = 0;
- if (transport_version() > QUIC_VERSION_46) {
+ if (transport_version() > QUIC_VERSION_44) {
if (header.version_flag) {
type = static_cast<uint8_t>(
FLAGS_LONG_HEADER | FLAGS_FIXED_BIT |
@@ -1814,7 +2072,8 @@
}
bool QuicFramer::AppendIetfPacketHeader(const QuicPacketHeader& header,
- QuicDataWriter* writer) {
+ QuicDataWriter* writer,
+ size_t* length_field_offset) {
QUIC_DVLOG(1) << ENDPOINT << "Appending IETF header: " << header;
QUIC_BUG_IF(!QuicUtils::IsConnectionIdValidForVersion(
header.destination_connection_id, transport_version()))
@@ -1838,11 +2097,34 @@
if (!AppendIetfConnectionId(
header.version_flag, header.destination_connection_id,
header.destination_connection_id_length, header.source_connection_id,
- header.source_connection_id_length, writer, perspective_)) {
+ header.source_connection_id_length, writer)) {
return false;
}
last_serialized_connection_id_ = header.destination_connection_id;
+ if (QuicVersionHasLongHeaderLengths(transport_version()) &&
+ header.version_flag) {
+ if (header.long_packet_type == INITIAL) {
+ // Write retry token length.
+ if (!writer->WriteVarInt62(header.retry_token.length(),
+ header.retry_token_length_length)) {
+ return false;
+ }
+ // Write retry token.
+ if (!header.retry_token.empty() &&
+ !writer->WriteStringPiece(header.retry_token)) {
+ return false;
+ }
+ }
+ if (length_field_offset != nullptr) {
+ *length_field_offset = writer->length();
+ }
+ // Add fake length to reserve two bytes to add length in later.
+ writer->WriteVarInt62(256);
+ } else if (length_field_offset != nullptr) {
+ *length_field_offset = 0;
+ }
+
// Append packet number.
if (!AppendPacketNumber(header.packet_number_length, header.packet_number,
writer)) {
@@ -1943,8 +2225,7 @@
switch (public_flags & PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID) {
case PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID:
if (!reader->ReadConnectionId(&header->destination_connection_id,
- kQuicDefaultConnectionIdLength,
- perspective_)) {
+ kQuicDefaultConnectionIdLength)) {
set_detailed_error("Unable to read ConnectionId.");
return false;
}
@@ -2133,7 +2414,7 @@
} else {
header->version = ParseQuicVersionLabel(version_label);
if (header->version.transport_version != QUIC_VERSION_UNSUPPORTED) {
- if (header->version.transport_version > QUIC_VERSION_46 &&
+ if (header->version.transport_version > QUIC_VERSION_44 &&
!(type & FLAGS_FIXED_BIT)) {
set_detailed_error("Fixed bit is 0 in long header.");
return false;
@@ -2170,7 +2451,7 @@
header->destination_connection_id = last_serialized_connection_id_;
}
if (infer_packet_header_type_from_version_ &&
- transport_version() > QUIC_VERSION_46 && !(type & FLAGS_FIXED_BIT)) {
+ transport_version() > QUIC_VERSION_44 && !(type & FLAGS_FIXED_BIT)) {
set_detailed_error("Fixed bit is 0 in short header.");
return false;
}
@@ -2218,14 +2499,14 @@
// Read connection ID.
if (header->destination_connection_id_length == PACKET_8BYTE_CONNECTION_ID &&
!reader->ReadConnectionId(&header->destination_connection_id,
- kQuicDefaultConnectionIdLength, perspective_)) {
+ kQuicDefaultConnectionIdLength)) {
set_detailed_error("Unable to read Destination ConnectionId.");
return false;
}
if (header->source_connection_id_length == PACKET_8BYTE_CONNECTION_ID &&
!reader->ReadConnectionId(&header->source_connection_id,
- kQuicDefaultConnectionIdLength, perspective_)) {
+ kQuicDefaultConnectionIdLength)) {
set_detailed_error("Unable to read Source ConnectionId.");
return false;
}
@@ -2428,6 +2709,22 @@
}
break;
}
+ case CRYPTO_FRAME: {
+ if (version_.transport_version < QUIC_VERSION_47) {
+ set_detailed_error("Illegal frame type.");
+ return RaiseError(QUIC_INVALID_FRAME_DATA);
+ }
+ QuicCryptoFrame frame;
+ if (!ProcessCryptoFrame(reader, &frame)) {
+ return RaiseError(QUIC_INVALID_FRAME_DATA);
+ }
+ if (!visitor_->OnCryptoFrame(frame)) {
+ QUIC_DVLOG(1) << "Visitor asked to stop further processing.";
+ // Returning true since there was no parsing error.
+ return true;
+ }
+ break;
+ }
default:
set_detailed_error("Illegal frame type.");
@@ -2556,9 +2853,10 @@
}
break;
}
- case IETF_MAX_STREAM_ID: {
+ case IETF_MAX_STREAMS_BIDIRECTIONAL:
+ case IETF_MAX_STREAMS_UNIDIRECTIONAL: {
QuicMaxStreamIdFrame frame;
- if (!ProcessMaxStreamIdFrame(reader, &frame)) {
+ if (!ProcessMaxStreamsFrame(reader, &frame, frame_type)) {
return RaiseError(QUIC_MAX_STREAM_ID_DATA);
}
QUIC_CODE_COUNT_N(max_stream_id_received, 1, 2);
@@ -2603,9 +2901,10 @@
}
break;
}
- case IETF_STREAM_ID_BLOCKED: {
+ case IETF_STREAMS_BLOCKED_UNIDIRECTIONAL:
+ case IETF_STREAMS_BLOCKED_BIDIRECTIONAL: {
QuicStreamIdBlockedFrame frame;
- if (!ProcessStreamIdBlockedFrame(reader, &frame)) {
+ if (!ProcessStreamsBlockedFrame(reader, &frame, frame_type)) {
return RaiseError(QUIC_STREAM_ID_BLOCKED_DATA);
}
QUIC_CODE_COUNT_N(stream_id_blocked_received, 1, 2);
@@ -2927,9 +3226,7 @@
return false;
}
- if (GetQuicReloadableFlag(quic_disallow_peer_ack_0) &&
- largest_acked < first_sending_packet_number_.ToUint64()) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_disallow_peer_ack_0, 1, 3);
+ if (largest_acked < first_sending_packet_number_.ToUint64()) {
// Connection always sends packet starting from kFirstSendingPacketNumber >
// 0, peer has observed an unsent packet.
set_detailed_error("Largest acked is 0.");
@@ -2966,25 +3263,12 @@
}
if (first_block_length == 0) {
- // For non-empty ACKs, the first block length must be non-zero.
- // TODO(fayang): remove this if and return false directly when deprecating
- // gfe2_reloadable_flag_quic_disallow_peer_ack_0.
- if (largest_acked != 0 || num_ack_blocks != 0) {
- set_detailed_error(
- QuicStrCat("First block length is zero but ACK is "
- "not empty. largest acked is ",
- largest_acked, ", num ack blocks is ",
- QuicTextUtils::Uint64ToString(num_ack_blocks), ".")
- .c_str());
- return false;
- }
- DCHECK(!GetQuicReloadableFlag(quic_disallow_peer_ack_0));
+ set_detailed_error("First block length is zero.");
+ return false;
}
bool first_ack_block_underflow = first_block_length > largest_acked + 1;
- if (GetQuicReloadableFlag(quic_disallow_peer_ack_0) &&
- first_block_length + first_sending_packet_number_.ToUint64() >
- largest_acked + 1) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_disallow_peer_ack_0, 2, 3);
+ if (first_block_length + first_sending_packet_number_.ToUint64() >
+ largest_acked + 1) {
first_ack_block_underflow = true;
}
if (first_ack_block_underflow) {
@@ -3018,10 +3302,8 @@
return false;
}
bool ack_block_underflow = first_received < gap + current_block_length;
- if (GetQuicReloadableFlag(quic_disallow_peer_ack_0) &&
- first_received < gap + current_block_length +
+ if (first_received < gap + current_block_length +
first_sending_packet_number_.ToUint64()) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_disallow_peer_ack_0, 3, 3);
ack_block_underflow = true;
}
if (ack_block_underflow) {
@@ -3074,6 +3356,14 @@
return false;
}
+ if (largest_acked.ToUint64() <= delta_from_largest_observed) {
+ set_detailed_error(QuicStrCat("delta_from_largest_observed too high: ",
+ delta_from_largest_observed,
+ ", largest_acked: ", largest_acked.ToUint64())
+ .c_str());
+ return false;
+ }
+
// Time delta from the framer creation.
uint32_t time_delta_us;
if (!reader->ReadUInt32(&time_delta_us)) {
@@ -3093,6 +3383,14 @@
set_detailed_error("Unable to read sequence delta in received packets.");
return false;
}
+ if (largest_acked.ToUint64() <= delta_from_largest_observed) {
+ set_detailed_error(
+ QuicStrCat("delta_from_largest_observed too high: ",
+ delta_from_largest_observed,
+ ", largest_acked: ", largest_acked.ToUint64())
+ .c_str());
+ return false;
+ }
seq_num = largest_acked - delta_from_largest_observed;
// Time delta from the previous timestamp.
@@ -3410,11 +3708,6 @@
void QuicFramer::ProcessPaddingFrame(QuicDataReader* reader,
QuicPaddingFrame* frame) {
- if (version_.transport_version == QUIC_VERSION_35) {
- frame->num_padding_bytes = reader->BytesRemaining() + 1;
- reader->ReadRemainingPayload();
- return;
- }
// Type byte has been read.
frame->num_padding_bytes = 1;
uint8_t next_byte;
@@ -3429,7 +3722,9 @@
bool no_message_length,
QuicMessageFrame* frame) {
if (no_message_length) {
- frame->message_data = QuicString(reader->ReadRemainingPayload());
+ QuicStringPiece remaining(reader->ReadRemainingPayload());
+ frame->data = remaining.data();
+ frame->message_length = remaining.length();
return true;
}
@@ -3445,7 +3740,8 @@
return false;
}
- frame->message_data = QuicString(message_piece);
+ frame->data = message_piece.data();
+ frame->message_length = message_length;
return true;
}
@@ -3458,14 +3754,18 @@
QuicConnectionIdLength source_connection_id_length,
bool includes_version,
bool includes_diversification_nonce,
- QuicPacketNumberLength packet_number_length) {
+ QuicPacketNumberLength packet_number_length,
+ QuicVariableLengthIntegerLength retry_token_length_length,
+ uint64_t retry_token_length,
+ QuicVariableLengthIntegerLength length_length) {
// TODO(ianswett): This is identical to QuicData::AssociatedData.
return QuicStringPiece(
encrypted.data(),
GetStartOfEncryptedData(version, destination_connection_id_length,
source_connection_id_length, includes_version,
includes_diversification_nonce,
- packet_number_length));
+ packet_number_length, retry_token_length_length,
+ retry_token_length, length_length));
}
void QuicFramer::SetDecrypter(EncryptionLevel level,
@@ -3509,7 +3809,7 @@
DCHECK(packet_number.IsInitialized());
size_t output_length = 0;
if (!encrypter_[level]->EncryptPacket(
- version_.transport_version, packet_number.ToUint64(),
+ packet_number.ToUint64(),
QuicStringPiece(buffer, ad_len), // Associated data
QuicStringPiece(buffer + ad_len, total_len - ad_len), // Plaintext
buffer + ad_len, // Destination buffer
@@ -3538,7 +3838,7 @@
// Encrypt the plaintext into the buffer.
size_t output_length = 0;
if (!encrypter_[level]->EncryptPacket(
- version_.transport_version, packet_number.ToUint64(), associated_data,
+ packet_number.ToUint64(), associated_data,
packet.Plaintext(version_.transport_version), buffer + ad_len,
&output_length, buffer_len - ad_len)) {
RaiseError(QUIC_ENCRYPTION_FAILURE);
@@ -3548,6 +3848,11 @@
return ad_len + output_length;
}
+size_t QuicFramer::GetCiphertextSize(EncryptionLevel level,
+ size_t plaintext_size) const {
+ return encrypter_[level]->GetCiphertextSize(plaintext_size);
+}
+
size_t QuicFramer::GetMaxPlaintextSize(size_t ciphertext_size) {
// In order to keep the code simple, we don't have the current encryption
// level to hand. Both the NullEncrypter and AES-GCM have a tag length of 12.
@@ -3565,24 +3870,17 @@
return min_plaintext_size;
}
-bool QuicFramer::DecryptPayload(QuicDataReader* encrypted_reader,
+bool QuicFramer::DecryptPayload(QuicStringPiece encrypted,
+ QuicStringPiece associated_data,
const QuicPacketHeader& header,
- const QuicEncryptedPacket& packet,
char* decrypted_buffer,
size_t buffer_length,
size_t* decrypted_length) {
- QuicStringPiece encrypted = encrypted_reader->ReadRemainingPayload();
DCHECK(decrypter_ != nullptr);
- QuicStringPiece associated_data = GetAssociatedDataFromEncryptedPacket(
- version_.transport_version, packet,
- header.destination_connection_id_length,
- header.source_connection_id_length, header.version_flag,
- header.nonce != nullptr, header.packet_number_length);
bool success = decrypter_->DecryptPacket(
- version_.transport_version, header.packet_number.ToUint64(),
- associated_data, encrypted, decrypted_buffer, decrypted_length,
- buffer_length);
+ header.packet_number.ToUint64(), associated_data, encrypted,
+ decrypted_buffer, decrypted_length, buffer_length);
if (success) {
visitor_->OnDecryptedPacket(decrypter_level_);
} else if (alternative_decrypter_ != nullptr) {
@@ -3591,7 +3889,7 @@
alternative_decrypter_->SetDiversificationNonce(*header.nonce);
}
bool try_alternative_decryption = true;
- if (alternative_decrypter_level_ == ENCRYPTION_INITIAL) {
+ if (alternative_decrypter_level_ == ENCRYPTION_ZERO_RTT) {
if (perspective_ == Perspective::IS_CLIENT) {
if (header.nonce == nullptr) {
// Can not use INITIAL decryption without a diversification nonce.
@@ -3604,9 +3902,8 @@
if (try_alternative_decryption) {
success = alternative_decrypter_->DecryptPacket(
- version_.transport_version, header.packet_number.ToUint64(),
- associated_data, encrypted, decrypted_buffer, decrypted_length,
- buffer_length);
+ header.packet_number.ToUint64(), associated_data, encrypted,
+ decrypted_buffer, decrypted_length, buffer_length);
}
if (success) {
visitor_->OnDecryptedPacket(alternative_decrypter_level_);
@@ -3793,7 +4090,7 @@
case MESSAGE_FRAME:
return GetMessageFrameSize(version_.transport_version,
last_frame_in_packet,
- frame.message_frame->message_data.length());
+ frame.message_frame->message_length);
case PADDING_FRAME:
DCHECK(false);
return 0;
@@ -3890,14 +4187,16 @@
case WINDOW_UPDATE_FRAME:
// Depending on whether there is a stream ID or not, will be either a
// MAX_STREAM_DATA frame or a MAX_DATA frame.
- if (frame.window_update_frame->stream_id == 0) {
+ if (frame.window_update_frame->stream_id ==
+ QuicUtils::GetInvalidStreamId(transport_version())) {
type_byte = IETF_MAX_DATA;
} else {
type_byte = IETF_MAX_STREAM_DATA;
}
break;
case BLOCKED_FRAME:
- if (frame.blocked_frame->stream_id == 0) {
+ if (frame.blocked_frame->stream_id ==
+ QuicUtils::GetInvalidStreamId(transport_version())) {
type_byte = IETF_BLOCKED;
} else {
type_byte = IETF_STREAM_BLOCKED;
@@ -3935,10 +4234,20 @@
type_byte = IETF_NEW_TOKEN;
break;
case MAX_STREAM_ID_FRAME:
- type_byte = IETF_MAX_STREAM_ID;
+ if (QuicUtils::IsBidirectionalStreamId(
+ frame.max_stream_id_frame.max_stream_id)) {
+ type_byte = IETF_MAX_STREAMS_BIDIRECTIONAL;
+ } else {
+ type_byte = IETF_MAX_STREAMS_UNIDIRECTIONAL;
+ }
break;
case STREAM_ID_BLOCKED_FRAME:
- type_byte = IETF_STREAM_ID_BLOCKED;
+ if (QuicUtils::IsBidirectionalStreamId(
+ frame.max_stream_id_frame.max_stream_id)) {
+ type_byte = IETF_STREAMS_BLOCKED_BIDIRECTIONAL;
+ } else {
+ type_byte = IETF_STREAMS_BLOCKED_UNIDIRECTIONAL;
+ }
break;
case PATH_RESPONSE_FRAME:
type_byte = IETF_PATH_RESPONSE;
@@ -4061,8 +4370,6 @@
return true;
}
-// TODO(dschinazi) b/120240679 - remove perspective once these flags are
-// deprecated: quic_variable_length_connection_ids_(client|server).
// static
bool QuicFramer::AppendIetfConnectionId(
bool version_flag,
@@ -4070,8 +4377,7 @@
QuicConnectionIdLength destination_connection_id_length,
QuicConnectionId source_connection_id,
QuicConnectionIdLength source_connection_id_length,
- QuicDataWriter* writer,
- Perspective perspective) {
+ QuicDataWriter* writer) {
if (version_flag) {
// Append connection ID length byte.
uint8_t dcil = GetConnectionIdLengthValue(destination_connection_id_length);
@@ -4082,11 +4388,11 @@
}
}
if (destination_connection_id_length == PACKET_8BYTE_CONNECTION_ID &&
- !writer->WriteConnectionId(destination_connection_id, perspective)) {
+ !writer->WriteConnectionId(destination_connection_id)) {
return false;
}
if (source_connection_id_length == PACKET_8BYTE_CONNECTION_ID &&
- !writer->WriteConnectionId(source_connection_id, perspective)) {
+ !writer->WriteConnectionId(source_connection_id)) {
return false;
}
return true;
@@ -4688,10 +4994,7 @@
bool QuicFramer::AppendBlockedFrame(const QuicBlockedFrame& frame,
QuicDataWriter* writer) {
if (version_.transport_version == QUIC_VERSION_99) {
- // TODO(fkastenholz): This should be converted to use
- // QuicUtils::GetInvalidStreamId to get the correct invalid stream id value
- // and not rely on 0.
- if (frame.stream_id == 0) {
+ if (frame.stream_id == QuicUtils::GetInvalidStreamId(transport_version())) {
return AppendIetfBlockedFrame(frame, writer);
}
return AppendStreamBlockedFrame(frame, writer);
@@ -4705,11 +5008,6 @@
bool QuicFramer::AppendPaddingFrame(const QuicPaddingFrame& frame,
QuicDataWriter* writer) {
- if (version_.transport_version == QUIC_VERSION_35) {
- writer->WritePadding();
- return true;
- }
-
if (frame.num_padding_bytes == 0) {
return false;
}
@@ -4730,12 +5028,15 @@
if (!writer->WriteUInt8(type_byte)) {
return false;
}
- if (!last_frame_in_packet &&
- !writer->WriteVarInt62(frame.message_data.length())) {
+ if (!last_frame_in_packet && !writer->WriteVarInt62(frame.message_length)) {
return false;
}
- return writer->WriteBytes(frame.message_data.data(),
- frame.message_data.length());
+ for (const auto& slice : frame.message_data) {
+ if (!writer->WriteBytes(slice.data(), slice.length())) {
+ return false;
+ }
+ }
+ return true;
}
bool QuicFramer::RaiseError(QuicErrorCode error) {
@@ -4760,11 +5061,6 @@
return header.long_packet_type == VERSION_NEGOTIATION;
}
-Endianness QuicFramer::endianness() const {
- return version_.transport_version != QUIC_VERSION_35 ? NETWORK_BYTE_ORDER
- : HOST_BYTE_ORDER;
-}
-
bool QuicFramer::StartsWithChlo(QuicStreamId id,
QuicStreamOffset offset) const {
if (data_producer_ == nullptr) {
@@ -4772,7 +5068,7 @@
return false;
}
char buf[sizeof(kCHLO)];
- QuicDataWriter writer(sizeof(kCHLO), buf, endianness());
+ QuicDataWriter writer(sizeof(kCHLO), buf);
if (data_producer_->WriteStreamData(id, offset, sizeof(kCHLO), &writer) !=
WRITE_SUCCESS) {
QUIC_BUG << "Failed to write data for stream " << id << " with offset "
@@ -4784,10 +5080,6 @@
0;
}
-PacketHeaderFormat QuicFramer::GetLastPacketFormat() const {
- return last_header_form_;
-}
-
bool QuicFramer::AppendIetfConnectionCloseFrame(
const QuicConnectionCloseFrame& frame,
QuicDataWriter* writer) {
@@ -5003,7 +5295,7 @@
bool QuicFramer::ProcessMaxDataFrame(QuicDataReader* reader,
QuicWindowUpdateFrame* frame) {
- frame->stream_id = 0;
+ frame->stream_id = QuicUtils::GetInvalidStreamId(transport_version());
if (!reader->ReadVarInt62(&frame->byte_offset)) {
set_detailed_error("Can not read MAX_DATA byte-offset");
return false;
@@ -5038,22 +5330,47 @@
return true;
}
-bool QuicFramer::AppendMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame,
- QuicDataWriter* writer) {
- if (!writer->WriteVarInt62(frame.max_stream_id)) {
- set_detailed_error("Can not write MAX_STREAM_ID stream id");
+bool QuicFramer::AppendMaxStreamsFrame(const QuicMaxStreamIdFrame& frame,
+ QuicDataWriter* writer) {
+ // Convert from the stream id on which the connection is blocked to a count
+ QuicStreamId stream_count =
+ StreamIdToCount(version_.transport_version, frame.max_stream_id);
+
+ if (!writer->WriteVarInt62(stream_count)) {
+ set_detailed_error("Can not write MAX_STREAMS stream count");
return false;
}
return true;
}
-bool QuicFramer::ProcessMaxStreamIdFrame(QuicDataReader* reader,
- QuicMaxStreamIdFrame* frame) {
- if (!reader->ReadVarIntStreamId(&frame->max_stream_id)) {
- set_detailed_error("Can not read MAX_STREAM_ID stream id.");
+bool QuicFramer::ProcessMaxStreamsFrame(QuicDataReader* reader,
+ QuicMaxStreamIdFrame* frame,
+ uint64_t frame_type) {
+ QuicStreamId received_stream_count;
+ if (!reader->ReadVarIntStreamId(&received_stream_count)) {
+ set_detailed_error("Can not read MAX_STREAMS stream count.");
return false;
}
- return true;
+ // TODO(fkastenholz): handle properly when the STREAMS_BLOCKED
+ // frame is implemented and passed up to the stream ID manager.
+ if (received_stream_count == 0) {
+ set_detailed_error("MAX_STREAMS stream count of 0 not supported.");
+ return false;
+ }
+ // Note that this code assumes that the only possible error that
+ // StreamCountToId can detect is that the stream count is too big or is 0.
+ // Too big is prevented by passing in the minimum of the received count
+ // and the maximum supported count, ensuring that the stream ID is
+ // pegged at the maximum allowed ID.
+ // count==0 is handled above, so that detailed_error_ may be set
+ // properly.
+ return StreamCountToId(
+ std::min(
+ received_stream_count,
+ GetMaxStreamCount((frame_type == IETF_MAX_STREAMS_UNIDIRECTIONAL),
+ perspective_)),
+ /*unidirectional=*/(frame_type == IETF_MAX_STREAMS_UNIDIRECTIONAL),
+ perspective_, version_.transport_version, &frame->max_stream_id);
}
bool QuicFramer::AppendIetfBlockedFrame(const QuicBlockedFrame& frame,
@@ -5068,10 +5385,7 @@
bool QuicFramer::ProcessIetfBlockedFrame(QuicDataReader* reader,
QuicBlockedFrame* frame) {
// Indicates that it is a BLOCKED frame (as opposed to STREAM_BLOCKED).
- // TODO(fkastenholz): This should be converted to use
- // QuicUtils::GetInvalidStreamId to get the correct invalid stream id value
- // and not rely on 0.
- frame->stream_id = 0;
+ frame->stream_id = QuicUtils::GetInvalidStreamId(transport_version());
if (!reader->ReadVarInt62(&frame->offset)) {
set_detailed_error("Can not read blocked offset.");
return false;
@@ -5105,23 +5419,58 @@
return true;
}
-bool QuicFramer::AppendStreamIdBlockedFrame(
+bool QuicFramer::AppendStreamsBlockedFrame(
const QuicStreamIdBlockedFrame& frame,
QuicDataWriter* writer) {
- if (!writer->WriteVarInt62(frame.stream_id)) {
- set_detailed_error("Can not write STREAM_ID_BLOCKED stream id");
+ // Convert from the stream id on which the connection is blocked to a count
+ QuicStreamId stream_count =
+ StreamIdToCount(version_.transport_version, frame.stream_id);
+
+ if (!writer->WriteVarInt62(stream_count)) {
+ set_detailed_error("Can not write STREAMS_BLOCKED stream count");
return false;
}
return true;
}
-bool QuicFramer::ProcessStreamIdBlockedFrame(QuicDataReader* reader,
- QuicStreamIdBlockedFrame* frame) {
- if (!reader->ReadVarIntStreamId(&frame->stream_id)) {
- set_detailed_error("Can not read STREAM_ID_BLOCKED stream id.");
+bool QuicFramer::ProcessStreamsBlockedFrame(QuicDataReader* reader,
+ QuicStreamIdBlockedFrame* frame,
+ uint64_t frame_type) {
+ QuicStreamId received_stream_count;
+ if (!reader->ReadVarIntStreamId(&received_stream_count)) {
+ set_detailed_error("Can not read STREAMS_BLOCKED stream id.");
return false;
}
- return true;
+ // TODO(fkastenholz): handle properly when the STREAMS_BLOCKED
+ // frame is implemented and passed up to the stream ID manager.
+ if (received_stream_count == 0) {
+ set_detailed_error("STREAMS_BLOCKED stream count 0 not supported.");
+ return false;
+ }
+ // TODO(fkastenholz): handle properly when the STREAMS_BLOCKED
+ // frame is implemented and passed up to the stream ID manager.
+ if (received_stream_count >
+ GetMaxStreamCount((frame_type == IETF_MAX_STREAMS_UNIDIRECTIONAL),
+ ((perspective_ == Perspective::IS_CLIENT)
+ ? Perspective::IS_SERVER
+ : Perspective::IS_CLIENT))) {
+ // If stream count is such that the resulting stream ID would exceed our
+ // implementation limit, generate an error.
+ set_detailed_error(
+ "STREAMS_BLOCKED stream count exceeds implementation limit.");
+ return false;
+ }
+ // Convert the stream count to an ID that can be used.
+ // The STREAMS_BLOCKED frame is a request for more streams
+ // that the peer will initiate. If this node is a client, it
+ // means that the peer is a server, and wants server-initiated
+ // stream IDs.
+ return StreamCountToId(
+ received_stream_count,
+ /*unidirectional=*/(frame_type == IETF_STREAMS_BLOCKED_UNIDIRECTIONAL),
+ (perspective_ == Perspective::IS_CLIENT) ? Perspective::IS_SERVER
+ : Perspective::IS_CLIENT,
+ version_.transport_version, &frame->stream_id);
}
bool QuicFramer::AppendNewConnectionIdFrame(
@@ -5136,7 +5485,7 @@
"Can not write New Connection ID frame connection ID Length");
return false;
}
- if (!writer->WriteConnectionId(frame.connection_id, perspective_)) {
+ if (!writer->WriteConnectionId(frame.connection_id)) {
set_detailed_error("Can not write New Connection ID frame connection ID");
return false;
}
@@ -5171,8 +5520,7 @@
return false;
}
- if (!reader->ReadConnectionId(&frame->connection_id, connection_id_length,
- perspective_)) {
+ if (!reader->ReadConnectionId(&frame->connection_id, connection_id_length)) {
set_detailed_error("Unable to read new connection ID frame connection id.");
return false;
}
diff --git a/quic/core/quic_framer.h b/quic/core/quic_framer.h
index 46280c5..76d86b8 100644
--- a/quic/core/quic_framer.h
+++ b/quic/core/quic_framer.h
@@ -112,6 +112,16 @@
// If OnPacketHeader returns false, framing for this packet will cease.
virtual bool OnPacketHeader(const QuicPacketHeader& header) = 0;
+ // Called when the packet being processed contains multiple IETF QUIC packets,
+ // which is due to there being more data after what is covered by the length
+ // field. |packet| contains the remaining data which can be processed.
+ // Note that this is called when the framer parses the length field, before
+ // it attempts to decrypt the first payload. It is the visitor's
+ // responsibility to buffer the packet and call ProcessPacket on it
+ // after the framer is done parsing the current payload. |packet| does not
+ // own its internal buffer, the visitor should make a copy of it.
+ virtual void OnCoalescedPacket(const QuicEncryptedPacket& packet) = 0;
+
// Called when a StreamFrame has been parsed.
virtual bool OnStreamFrame(const QuicStreamFrame& frame) = 0;
@@ -304,11 +314,11 @@
// be generated and calculates the appropriate size.
static size_t GetWindowUpdateFrameSize(QuicTransportVersion version,
const QuicWindowUpdateFrame& frame);
- // Size in bytes of all MaxStreamId frame fields.
- static size_t GetMaxStreamIdFrameSize(QuicTransportVersion version,
- const QuicMaxStreamIdFrame& frame);
- // Size in bytes of all StreamIdBlocked frame fields.
- static size_t GetStreamIdBlockedFrameSize(
+ // Size in bytes of all MaxStreams frame fields.
+ static size_t GetMaxStreamsFrameSize(QuicTransportVersion version,
+ const QuicMaxStreamIdFrame& frame);
+ // Size in bytes of all StreamsBlocked frame fields.
+ static size_t GetStreamsBlockedFrameSize(
QuicTransportVersion version,
const QuicStreamIdBlockedFrame& frame);
// Size in bytes of all Blocked frame fields.
@@ -362,7 +372,10 @@
QuicConnectionIdLength source_connection_id_length,
bool includes_version,
bool includes_diversification_nonce,
- QuicPacketNumberLength packet_number_length);
+ QuicPacketNumberLength packet_number_length,
+ QuicVariableLengthIntegerLength retry_token_length_length,
+ uint64_t retry_token_length,
+ QuicVariableLengthIntegerLength length_length);
// Serializes a packet containing |frames| into |buffer|.
// Returns the length of the packet, which must not be longer than
@@ -370,19 +383,22 @@
size_t BuildDataPacket(const QuicPacketHeader& header,
const QuicFrames& frames,
char* buffer,
- size_t packet_length);
+ size_t packet_length,
+ EncryptionLevel level);
// Serializes a probing packet, which is a padded PING packet. Returns the
// length of the packet. Returns 0 if it fails to serialize.
size_t BuildConnectivityProbingPacket(const QuicPacketHeader& header,
char* buffer,
- size_t packet_length);
+ size_t packet_length,
+ EncryptionLevel level);
- // Serializes an IETF probing packet, which is a padded PING packet.
- // Returns the length of the packet. Returns 0 if it fails to serialize.
- size_t BuildIetfConnectivityProbingPacket(const QuicPacketHeader& header,
- char* buffer,
- size_t packet_length);
+ // Serializes a probing packet, which is a padded PING packet. Returns the
+ // length of the packet. Returns 0 if it fails to serialize.
+ size_t BuildConnectivityProbingPacketNew(const QuicPacketHeader& header,
+ char* buffer,
+ size_t packet_length,
+ EncryptionLevel level);
// Serialize a probing packet that uses IETF QUIC's PATH CHALLENGE frame. Also
// fills the packet with padding.
@@ -390,7 +406,8 @@
char* buffer,
size_t packet_length,
QuicPathFrameBuffer* payload,
- QuicRandom* randomizer);
+ QuicRandom* randomizer,
+ EncryptionLevel level);
// Serialize a probing response packet that uses IETF QUIC's PATH RESPONSE
// frame. Also fills the packet with padding if |is_padded| is
@@ -400,7 +417,8 @@
char* buffer,
size_t packet_length,
const QuicDeque<QuicPathFrameBuffer>& payloads,
- const bool is_padded);
+ const bool is_padded,
+ EncryptionLevel level);
// Returns a new public reset packet.
static std::unique_ptr<QuicEncryptedPacket> BuildPublicResetPacket(
@@ -426,17 +444,24 @@
// packet will be set -- but it will be set from version_ not
// header.versions.
bool AppendPacketHeader(const QuicPacketHeader& header,
- QuicDataWriter* writer);
+ QuicDataWriter* writer,
+ size_t* length_field_offset);
bool AppendIetfHeaderTypeByte(const QuicPacketHeader& header,
QuicDataWriter* writer);
bool AppendIetfPacketHeader(const QuicPacketHeader& header,
- QuicDataWriter* writer);
+ QuicDataWriter* writer,
+ size_t* length_field_offset);
+ bool WriteIetfLongHeaderLength(const QuicPacketHeader& header,
+ QuicDataWriter* writer,
+ size_t length_field_offset,
+ EncryptionLevel level);
bool AppendTypeByte(const QuicFrame& frame,
bool last_frame_in_packet,
QuicDataWriter* writer);
bool AppendIetfTypeByte(const QuicFrame& frame,
bool last_frame_in_packet,
QuicDataWriter* writer);
+ size_t AppendIetfFrames(const QuicFrames& frames, QuicDataWriter* writer);
bool AppendStreamFrame(const QuicStreamFrame& frame,
bool last_frame_in_packet,
QuicDataWriter* writer);
@@ -485,6 +510,10 @@
char* buffer,
size_t buffer_len);
+ // Returns the length of the ciphertext that would be generated by encrypting
+ // to plaintext of size |plaintext_size| at the given level.
+ size_t GetCiphertextSize(EncryptionLevel level, size_t plaintext_size) const;
+
// Returns the maximum length of plaintext that can be encrypted
// to ciphertext no larger than |ciphertext_size|.
size_t GetMaxPlaintextSize(size_t ciphertext_size);
@@ -507,28 +536,15 @@
// Returns true if data with |offset| of stream |id| starts with 'CHLO'.
bool StartsWithChlo(QuicStreamId id, QuicStreamOffset offset) const;
- // Returns byte order to read/write integers and floating numbers.
- Endianness endianness() const;
-
// Returns true if |header| is considered as an stateless reset packet.
bool IsIetfStatelessResetPacket(const QuicPacketHeader& header) const;
- // Returns header wire format of last received packet.
- // Please do not use this method.
- // TODO(fayang): Remove last_header_form_ when deprecating
- // quic_fix_last_packet_is_ietf_quic flag.
- PacketHeaderFormat GetLastPacketFormat() const;
-
void set_validate_flags(bool value) { validate_flags_ = value; }
Perspective perspective() const { return perspective_; }
QuicVersionLabel last_version_label() const { return last_version_label_; }
- void set_last_packet_form(PacketHeaderFormat form) {
- last_header_form_ = form;
- }
-
void set_data_producer(QuicStreamFrameDataProducer* data_producer) {
data_producer_ = data_producer;
}
@@ -566,12 +582,6 @@
size_t num_ack_blocks;
};
- // The same as BuildDataPacket, but it only builds IETF-format packets.
- size_t BuildIetfDataPacket(const QuicPacketHeader& header,
- const QuicFrames& frames,
- char* buffer,
- size_t packet_length);
-
bool ProcessDataPacket(QuicDataReader* reader,
QuicPacketHeader* header,
const QuicEncryptedPacket& packet,
@@ -590,6 +600,16 @@
bool ProcessVersionNegotiationPacket(QuicDataReader* reader,
const QuicPacketHeader& header);
+ bool MaybeProcessIetfInitialRetryToken(QuicDataReader* encrypted_reader,
+ QuicPacketHeader* header);
+
+ void MaybeProcessCoalescedPacket(const QuicDataReader& encrypted_reader,
+ uint64_t remaining_bytes_length,
+ const QuicPacketHeader& header);
+
+ bool MaybeProcessIetfLength(QuicDataReader* encrypted_reader,
+ QuicPacketHeader* header);
+
bool ProcessPublicHeader(QuicDataReader* reader,
bool last_packet_is_ietf_quic,
QuicPacketHeader* header);
@@ -640,9 +660,9 @@
bool no_message_length,
QuicMessageFrame* frame);
- bool DecryptPayload(QuicDataReader* encrypted_reader,
+ bool DecryptPayload(QuicStringPiece encrypted,
+ QuicStringPiece associated_data,
const QuicPacketHeader& header,
- const QuicEncryptedPacket& packet,
char* decrypted_buffer,
size_t buffer_length,
size_t* decrypted_length);
@@ -703,8 +723,7 @@
QuicConnectionIdLength destination_connection_id_length,
QuicConnectionId source_connection_id,
QuicConnectionIdLength source_connection_id_length,
- QuicDataWriter* writer,
- Perspective perspective);
+ QuicDataWriter* writer);
// The Append* methods attempt to write the provided header or frame using the
// |writer|, and return true if successful.
@@ -789,10 +808,11 @@
bool ProcessMaxStreamDataFrame(QuicDataReader* reader,
QuicWindowUpdateFrame* frame);
- bool AppendMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame,
- QuicDataWriter* writer);
- bool ProcessMaxStreamIdFrame(QuicDataReader* reader,
- QuicMaxStreamIdFrame* frame);
+ bool AppendMaxStreamsFrame(const QuicMaxStreamIdFrame& frame,
+ QuicDataWriter* writer);
+ bool ProcessMaxStreamsFrame(QuicDataReader* reader,
+ QuicMaxStreamIdFrame* frame,
+ uint64_t frame_type);
bool AppendIetfBlockedFrame(const QuicBlockedFrame& frame,
QuicDataWriter* writer);
@@ -803,10 +823,12 @@
bool ProcessStreamBlockedFrame(QuicDataReader* reader,
QuicBlockedFrame* frame);
- bool AppendStreamIdBlockedFrame(const QuicStreamIdBlockedFrame& frame,
- QuicDataWriter* writer);
- bool ProcessStreamIdBlockedFrame(QuicDataReader* reader,
- QuicStreamIdBlockedFrame* frame);
+ bool AppendStreamsBlockedFrame(const QuicStreamIdBlockedFrame& frame,
+ QuicDataWriter* writer);
+ bool ProcessStreamsBlockedFrame(QuicDataReader* reader,
+ QuicStreamIdBlockedFrame* frame,
+ uint64_t frame_type);
+
bool AppendNewConnectionIdFrame(const QuicNewConnectionIdFrame& frame,
QuicDataWriter* writer);
bool ProcessNewConnectionIdFrame(QuicDataReader* reader,
@@ -845,9 +867,6 @@
QuicConnectionId last_serialized_connection_id_;
// The last QUIC version label received.
QuicVersionLabel last_version_label_;
- // Format of last received packet header, whether it is Google QUIC, IETF long
- // header packet or IETF short header packet.
- PacketHeaderFormat last_header_form_;
// Version of the protocol being used.
ParsedQuicVersion version_;
// This vector contains QUIC versions which we currently support.
diff --git a/quic/core/quic_framer_test.cc b/quic/core/quic_framer_test.cc
index 888c87e..c674896 100644
--- a/quic/core/quic_framer_test.cc
+++ b/quic/core/quic_framer_test.cc
@@ -24,6 +24,7 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_framer_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_data_producer.h"
@@ -83,14 +84,12 @@
bool SetKey(QuicStringPiece key) override { return true; }
bool SetNoncePrefix(QuicStringPiece nonce_prefix) override { return true; }
bool SetIV(QuicStringPiece iv) override { return true; }
- bool EncryptPacket(QuicTransportVersion version,
- uint64_t packet_number,
+ bool EncryptPacket(uint64_t packet_number,
QuicStringPiece associated_data,
QuicStringPiece plaintext,
char* output,
size_t* output_length,
size_t max_output_length) override {
- version_ = version;
packet_number_ = QuicPacketNumber(packet_number);
associated_data_ = QuicString(associated_data);
plaintext_ = QuicString(plaintext);
@@ -110,7 +109,6 @@
QuicStringPiece GetKey() const override { return QuicStringPiece(); }
QuicStringPiece GetNoncePrefix() const override { return QuicStringPiece(); }
- QuicTransportVersion version_;
QuicPacketNumber packet_number_;
QuicString associated_data_;
QuicString plaintext_;
@@ -129,14 +127,12 @@
bool SetDiversificationNonce(const DiversificationNonce& key) override {
return true;
}
- bool DecryptPacket(QuicTransportVersion version,
- uint64_t packet_number,
+ bool DecryptPacket(uint64_t packet_number,
QuicStringPiece associated_data,
QuicStringPiece ciphertext,
char* output,
size_t* output_length,
size_t max_output_length) override {
- version_ = version;
packet_number_ = QuicPacketNumber(packet_number);
associated_data_ = QuicString(associated_data);
ciphertext_ = QuicString(ciphertext);
@@ -150,7 +146,6 @@
QuicStringPiece GetNoncePrefix() const override { return QuicStringPiece(); }
// Use a distinct value starting with 0xFFFFFF, which is never used by TLS.
uint32_t cipher_id() const override { return 0xFFFFFFF2; }
- QuicTransportVersion version_;
QuicPacketNumber packet_number_;
QuicString associated_data_;
QuicString ciphertext_;
@@ -212,6 +207,15 @@
return accept_packet_;
}
+ void OnCoalescedPacket(const QuicEncryptedPacket& packet) override {
+ size_t coalesced_data_length = packet.length();
+ char* coalesced_data = new char[coalesced_data_length];
+ memcpy(coalesced_data, packet.data(), coalesced_data_length);
+ coalesced_packets_.push_back(QuicMakeUnique<QuicEncryptedPacket>(
+ coalesced_data, coalesced_data_length,
+ /*owns_buffer=*/true));
+ }
+
bool OnStreamFrame(const QuicStreamFrame& frame) override {
++frame_count_;
// Save a copy of the data so it is valid after the packet is processed.
@@ -278,7 +282,8 @@
bool OnMessageFrame(const QuicMessageFrame& frame) override {
++frame_count_;
- message_frames_.push_back(QuicMakeUnique<QuicMessageFrame>(frame));
+ message_frames_.push_back(
+ QuicMakeUnique<QuicMessageFrame>(frame.data, frame.message_length));
return true;
}
@@ -386,6 +391,7 @@
std::vector<std::unique_ptr<QuicPaddingFrame>> padding_frames_;
std::vector<std::unique_ptr<QuicPingFrame>> ping_frames_;
std::vector<std::unique_ptr<QuicMessageFrame>> message_frames_;
+ std::vector<std::unique_ptr<QuicEncryptedPacket>> coalesced_packets_;
QuicRstStreamFrame rst_stream_frame_;
QuicConnectionCloseFrame connection_close_frame_;
QuicApplicationCloseFrame application_close_frame_;
@@ -459,7 +465,6 @@
}
bool CheckEncryption(QuicPacketNumber packet_number, QuicPacket* packet) {
- EXPECT_EQ(version_.transport_version, encrypter_->version_);
if (packet_number != encrypter_->packet_number_) {
QUIC_LOG(ERROR) << "Encrypted incorrect packet number. expected "
<< packet_number
@@ -488,36 +493,53 @@
bool includes_diversification_nonce,
QuicConnectionIdLength destination_connection_id_length,
QuicConnectionIdLength source_connection_id_length) {
- EXPECT_EQ(version_.transport_version, decrypter_->version_);
+ return CheckDecryption(
+ encrypted, includes_version, includes_diversification_nonce,
+ destination_connection_id_length, source_connection_id_length,
+ VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0);
+ }
+
+ bool CheckDecryption(
+ const QuicEncryptedPacket& encrypted,
+ bool includes_version,
+ bool includes_diversification_nonce,
+ QuicConnectionIdLength destination_connection_id_length,
+ QuicConnectionIdLength source_connection_id_length,
+ QuicVariableLengthIntegerLength retry_token_length_length,
+ size_t retry_token_length,
+ QuicVariableLengthIntegerLength length_length) {
if (visitor_.header_->packet_number != decrypter_->packet_number_) {
QUIC_LOG(ERROR) << "Decrypted incorrect packet number. expected "
<< visitor_.header_->packet_number
<< " actual: " << decrypter_->packet_number_;
return false;
}
- if (QuicFramer::GetAssociatedDataFromEncryptedPacket(
+ QuicStringPiece associated_data =
+ QuicFramer::GetAssociatedDataFromEncryptedPacket(
framer_.transport_version(), encrypted,
destination_connection_id_length, source_connection_id_length,
includes_version, includes_diversification_nonce,
- PACKET_4BYTE_PACKET_NUMBER) != decrypter_->associated_data_) {
+ PACKET_4BYTE_PACKET_NUMBER, retry_token_length_length,
+ retry_token_length, length_length);
+ if (associated_data != decrypter_->associated_data_) {
QUIC_LOG(ERROR) << "Decrypted incorrect associated data. expected "
- << QuicFramer::GetAssociatedDataFromEncryptedPacket(
- framer_.transport_version(), encrypted,
- destination_connection_id_length,
- source_connection_id_length, includes_version,
- includes_diversification_nonce,
- PACKET_4BYTE_PACKET_NUMBER)
- << " actual: " << decrypter_->associated_data_;
+ << QuicTextUtils::HexEncode(associated_data)
+ << " actual: "
+ << QuicTextUtils::HexEncode(decrypter_->associated_data_);
return false;
}
QuicStringPiece ciphertext(
encrypted.AsStringPiece().substr(GetStartOfEncryptedData(
framer_.transport_version(), destination_connection_id_length,
source_connection_id_length, includes_version,
- includes_diversification_nonce, PACKET_4BYTE_PACKET_NUMBER)));
+ includes_diversification_nonce, PACKET_4BYTE_PACKET_NUMBER,
+ retry_token_length_length, retry_token_length, length_length)));
if (ciphertext != decrypter_->ciphertext_) {
QUIC_LOG(ERROR) << "Decrypted incorrect ciphertext data. expected "
- << ciphertext << " actual: " << decrypter_->ciphertext_;
+ << QuicTextUtils::HexEncode(ciphertext) << " actual: "
+ << QuicTextUtils::HexEncode(decrypter_->ciphertext_)
+ << " associated data: "
+ << QuicTextUtils::HexEncode(associated_data);
return false;
}
return true;
@@ -609,12 +631,29 @@
return BuildUnsizedDataPacket(&framer_, header, frames, packet_size);
}
+ // N starts at 1.
+ QuicStreamId GetNthStreamid(QuicTransportVersion transport_version,
+ Perspective perspective,
+ bool bidirectional,
+ int n) {
+ if (bidirectional) {
+ return QuicUtils::GetFirstBidirectionalStreamId(transport_version,
+ perspective) +
+ ((n - 1) * QuicUtils::StreamIdDelta(transport_version));
+ }
+ // Unidirectional
+ return QuicUtils::GetFirstUnidirectionalStreamId(transport_version,
+ perspective) +
+ ((n - 1) * QuicUtils::StreamIdDelta(transport_version));
+ }
+
test::TestEncrypter* encrypter_;
test::TestDecrypter* decrypter_;
ParsedQuicVersion version_;
QuicTime start_;
QuicFramer framer_;
test::TestQuicVisitor visitor_;
+ SimpleBufferAllocator allocator_;
};
// Multiple test cases of QuicFramerTest use byte arrays to define packets for
@@ -626,7 +665,7 @@
GetQuicVersionDigitOnes()
// Run all framer tests with all supported versions of QUIC.
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
QuicFramerTests,
QuicFramerTest,
::testing::ValuesIn(AllSupportedVersionsIncludingTls()));
@@ -764,7 +803,7 @@
// packet number
0x78, 0x56, 0x34, 0x12,
};
- unsigned char packet47[kMaxPacketSize + 1] = {
+ unsigned char packet46[kMaxPacketSize + 1] = {
// type (short header 4 byte packet number)
0x43,
// connection_id
@@ -775,9 +814,9 @@
// clang-format on
unsigned char* p = packet;
size_t p_size = QUIC_ARRAYSIZE(packet);
- if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
- p_size = QUIC_ARRAYSIZE(packet47);
+ if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
+ p_size = QUIC_ARRAYSIZE(packet46);
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
p_size = QUIC_ARRAYSIZE(packet44);
@@ -786,7 +825,8 @@
const size_t header_size = GetPacketHeaderSize(
framer_.transport_version(), PACKET_8BYTE_CONNECTION_ID,
PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion,
- !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER);
+ !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER,
+ VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0);
memset(p + header_size, 0, kMaxPacketSize - header_size);
@@ -802,20 +842,12 @@
}
TEST_P(QuicFramerTest, PacketHeader) {
- // clang-format off
- PacketFragments packet38 = {
- // public flags (8 byte connection_id)
- {"Unable to read public flags.",
- {0x28}},
- // connection_id
- {"Unable to read ConnectionId.",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"Unable to read packet number.",
- {0x78, 0x56, 0x34, 0x12}},
- };
+ if (framer_.transport_version() > QUIC_VERSION_43) {
+ return;
+ }
- PacketFragments packet39 = {
+ // clang-format off
+ PacketFragments packet = {
// public flags (8 byte connection_id)
{"Unable to read public flags.",
{0x28}},
@@ -828,12 +860,7 @@
};
// clang-format on
- if (framer_.transport_version() > QUIC_VERSION_43) {
- return;
- }
-
- PacketFragments& fragments =
- framer_.transport_version() == QUIC_VERSION_35 ? packet38 : packet39;
+ PacketFragments& fragments = packet;
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
@@ -869,7 +896,7 @@
{"Unable to read packet number.",
{0x12, 0x34, 0x56, 0x78}},
};
- PacketFragments packet47 = {
+ PacketFragments packet46 = {
// type (long header with packet type INITIAL)
{"Unable to read type.",
{0xC3}},
@@ -888,12 +915,13 @@
};
// clang-format on
- if (framer_.transport_version() <= QUIC_VERSION_43) {
+ if (framer_.transport_version() <= QUIC_VERSION_43 ||
+ QuicVersionHasLongHeaderLengths(framer_.transport_version())) {
return;
}
PacketFragments& fragments =
- framer_.transport_version() > QUIC_VERSION_46 ? packet47 : packet44;
+ framer_.transport_version() > QUIC_VERSION_44 ? packet46 : packet44;
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
@@ -907,7 +935,7 @@
EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
CheckFramingBoundaries(
- framer_.transport_version() > QUIC_VERSION_46 ? packet47 : packet44,
+ framer_.transport_version() > QUIC_VERSION_44 ? packet46 : packet44,
QUIC_INVALID_PACKET_HEADER);
}
@@ -924,16 +952,6 @@
// connection_id
// packet number
{"Unable to read packet number.",
- {0x78, 0x56, 0x34, 0x12}}
- };
-
- PacketFragments packet39 = {
- // public flags (0 byte connection_id)
- {"Unable to read public flags.",
- {0x20}},
- // connection_id
- // packet number
- {"Unable to read packet number.",
{0x12, 0x34, 0x56, 0x78}},
};
@@ -947,7 +965,7 @@
{0x12, 0x34, 0x56, 0x78}},
};
- PacketFragments packet47 = {
+ PacketFragments packet46 = {
// type (short header, 4 byte packet number)
{"Unable to read type.",
{0x43}},
@@ -959,12 +977,9 @@
// clang-format on
PacketFragments& fragments =
- framer_.transport_version() > QUIC_VERSION_46
- ? packet47
- : (framer_.transport_version() > QUIC_VERSION_43
- ? packet44
- : (framer_.transport_version() == QUIC_VERSION_35 ? packet
- : packet39));
+ framer_.transport_version() > QUIC_VERSION_44
+ ? packet46
+ : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
@@ -993,21 +1008,6 @@
{QUIC_VERSION_BYTES}},
// packet number
{"Unable to read packet number.",
- {0x78, 0x56, 0x34, 0x12}},
- };
-
- PacketFragments packet39 = {
- // public flags (0 byte connection_id)
- {"Unable to read public flags.",
- {0x29}},
- // connection_id
- {"Unable to read ConnectionId.",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // version tag
- {"Unable to read protocol version.",
- {QUIC_VERSION_BYTES}},
- // packet number
- {"Unable to read packet number.",
{0x12, 0x34, 0x56, 0x78}},
};
@@ -1029,7 +1029,7 @@
{0x12, 0x34, 0x56, 0x78}},
};
- PacketFragments packet47 = {
+ PacketFragments packet46 = {
// type (long header with packet type ZERO_RTT_PROTECTED and 4 bytes
// packet number)
{"Unable to read type.",
@@ -1047,15 +1047,37 @@
{"Unable to read packet number.",
{0x12, 0x34, 0x56, 0x78}},
};
+
+ PacketFragments packet99 = {
+ // type (long header with packet type ZERO_RTT_PROTECTED and 4 bytes
+ // packet number)
+ {"Unable to read type.",
+ {0xD3}},
+ // version tag
+ {"Unable to read protocol version.",
+ {QUIC_VERSION_BYTES}},
+ // connection_id length
+ {"Unable to read ConnectionId length.",
+ {0x50}},
+ // connection_id
+ {"Unable to read Destination ConnectionId.",
+ {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+ // long header packet length
+ {"Unable to read long header payload length.",
+ {0x04}},
+ // packet number
+ {"Long header payload length longer than packet.",
+ {0x12, 0x34, 0x56, 0x78}},
+ };
// clang-format on
PacketFragments& fragments =
- framer_.transport_version() > QUIC_VERSION_46
- ? packet47
- : (framer_.transport_version() > QUIC_VERSION_43
- ? packet44
- : (framer_.transport_version() == QUIC_VERSION_35 ? packet
- : packet39));
+ framer_.transport_version() == QUIC_VERSION_99
+ ? packet99
+ : framer_.transport_version() > QUIC_VERSION_44
+ ? packet46
+ : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
+ : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
@@ -1084,18 +1106,6 @@
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
// packet number
{"Unable to read packet number.",
- {0x78, 0x56, 0x34, 0x12}},
- };
-
- PacketFragments packet39 = {
- // public flags (8 byte connection_id and 4 byte packet number)
- {"Unable to read public flags.",
- {0x28}},
- // connection_id
- {"Unable to read ConnectionId.",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"Unable to read packet number.",
{0x12, 0x34, 0x56, 0x78}},
};
@@ -1111,7 +1121,7 @@
{0x12, 0x34, 0x56, 0x78}},
};
- PacketFragments packet47 = {
+ PacketFragments packet46 = {
// type (short header, 4 byte packet number)
{"Unable to read type.",
{0x43}},
@@ -1125,12 +1135,9 @@
// clang-format on
PacketFragments& fragments =
- framer_.transport_version() > QUIC_VERSION_46
- ? packet47
- : (framer_.transport_version() > QUIC_VERSION_43
- ? packet44
- : (framer_.transport_version() == QUIC_VERSION_35 ? packet
- : packet39));
+ framer_.transport_version() > QUIC_VERSION_44
+ ? packet46
+ : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
@@ -1158,18 +1165,6 @@
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
// packet number
{"Unable to read packet number.",
- {0x78, 0x56}},
- };
-
- PacketFragments packet39 = {
- // public flags (8 byte connection_id and 2 byte packet number)
- {"Unable to read public flags.",
- {0x18}},
- // connection_id
- {"Unable to read ConnectionId.",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"Unable to read packet number.",
{0x56, 0x78}},
};
@@ -1185,7 +1180,7 @@
{0x56, 0x78}},
};
- PacketFragments packet47 = {
+ PacketFragments packet46 = {
// type (short header, 2 byte packet number)
{"Unable to read type.",
{0x41}},
@@ -1199,12 +1194,9 @@
// clang-format on
PacketFragments& fragments =
- framer_.transport_version() > QUIC_VERSION_46
- ? packet47
- : (framer_.transport_version() > QUIC_VERSION_43
- ? packet44
- : (framer_.transport_version() == QUIC_VERSION_35 ? packet
- : packet39));
+ framer_.transport_version() > QUIC_VERSION_44
+ ? packet46
+ : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
@@ -1248,7 +1240,7 @@
{0x78}},
};
- PacketFragments packet47 = {
+ PacketFragments packet46 = {
// type (8 byte connection_id and 1 byte packet number)
{"Unable to read type.",
{0x40}},
@@ -1263,8 +1255,8 @@
// clang-format on
PacketFragments& fragments =
- framer_.transport_version() > QUIC_VERSION_46
- ? packet47
+ framer_.transport_version() > QUIC_VERSION_44
+ ? packet46
: (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
@@ -1360,24 +1352,6 @@
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
// packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // frame type (padding)
- 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
-
- unsigned char packet39[] = {
- // public flags: includes nonce flag
- 0x2C,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // nonce
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- // packet number
0x12, 0x34, 0x56, 0x78,
// frame type (padding)
@@ -1407,7 +1381,7 @@
0x00, 0x00, 0x00, 0x00
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type: Long header with packet type ZERO_RTT_PROTECTED and 1 byte packet
// number.
0xD0,
@@ -1429,18 +1403,48 @@
0x00,
0x00, 0x00, 0x00, 0x00
};
+
+ unsigned char packet99[] = {
+ // type: Long header with packet type ZERO_RTT_PROTECTED and 1 byte packet
+ // number.
+ 0xD0,
+ // version tag
+ QUIC_VERSION_BYTES,
+ // connection_id length
+ 0x05,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // long header packet length
+ 0x26,
+ // packet number
+ 0x78,
+ // nonce
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+
+ // frame type (padding)
+ 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
// clang-format on
+ if (framer_.version().handshake_protocol != PROTOCOL_QUIC_CRYPTO) {
+ return;
+ }
+
unsigned char* p = packet;
size_t p_size = QUIC_ARRAYSIZE(packet);
- if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
- p_size = QUIC_ARRAYSIZE(packet47);
+ if (framer_.transport_version() == QUIC_VERSION_99) {
+ p = packet99;
+ p_size = QUIC_ARRAYSIZE(packet99);
+ } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
+ p_size = QUIC_ARRAYSIZE(packet46);
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
p_size = QUIC_ARRAYSIZE(packet44);
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
}
QuicEncryptedPacket encrypted(AsChars(p), p_size, false);
@@ -1452,7 +1456,7 @@
}
EXPECT_EQ(1u, visitor_.padding_frames_.size());
EXPECT_EQ(5, visitor_.padding_frames_[0]->num_padding_bytes);
-};
+}
TEST_P(QuicFramerTest, LargePublicFlagWithMismatchedVersions) {
// clang-format off
@@ -1464,21 +1468,6 @@
// version tag
'Q', '0', '0', '0',
// packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // frame type (padding frame)
- 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
-
- unsigned char packet39[] = {
- // public flags (8 byte connection_id, version flag and an unknown flag)
- 0x29,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // version tag
- 'Q', '0', '0', '0',
- // packet number
0x12, 0x34, 0x56, 0x78,
// frame type (padding frame)
@@ -1505,11 +1494,8 @@
// clang-format on
QuicEncryptedPacket encrypted(
- AsChars(framer_.transport_version() > QUIC_VERSION_43
- ? packet44
- : (framer_.transport_version() == QUIC_VERSION_35
- ? packet
- : packet39)),
+ AsChars(framer_.transport_version() > QUIC_VERSION_43 ? packet44
+ : packet),
framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet44)
: QUIC_ARRAYSIZE(packet),
false);
@@ -1520,7 +1506,7 @@
EXPECT_EQ(1, visitor_.version_mismatch_);
EXPECT_EQ(1u, visitor_.padding_frames_.size());
EXPECT_EQ(5, visitor_.padding_frames_[0]->num_padding_bytes);
-};
+}
TEST_P(QuicFramerTest, PaddingFrame) {
// clang-format off
@@ -1530,88 +1516,6 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // frame type (padding frame)
- 0x00,
- // Ignored data (which in this case is a stream frame)
- // frame type (stream frame with fin)
- 0xFF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0x3A,
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
- // clang-format on
-
- if (framer_.transport_version() != QUIC_VERSION_35) {
- return;
- }
-
- QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(CheckDecryption(
- encrypted, !kIncludeVersion, !kIncludeDiversificationNonce,
- PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID));
-
- ASSERT_EQ(0u, visitor_.stream_frames_.size());
- EXPECT_EQ(0u, visitor_.ack_frames_.size());
- EXPECT_EQ(1u, visitor_.padding_frames_.size());
- EXPECT_EQ(28, visitor_.padding_frames_[0]->num_padding_bytes);
- // A packet with no frames is not acceptable.
- CheckProcessingFails(
- packet,
- GetPacketHeaderSize(
- framer_.transport_version(), PACKET_8BYTE_CONNECTION_ID,
- PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion,
- !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER),
- "Packet has no frames.", QUIC_MISSING_PAYLOAD);
-}
-
-TEST_P(QuicFramerTest, NewPaddingFrame) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x28,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // paddings
- 0x00, 0x00,
- // frame type (stream frame with fin)
- 0xFF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0x3A,
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- // paddings
- 0x00, 0x00,
- };
-
- unsigned char packet39[] = {
- // public flags (8 byte connection_id)
- 0x28,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
0x12, 0x34, 0x56, 0x78,
// paddings
@@ -1660,7 +1564,7 @@
0x00, 0x00,
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -1716,22 +1620,17 @@
};
// clang-format on
- if (framer_.transport_version() == QUIC_VERSION_35) {
- return;
- }
unsigned char* p = packet;
size_t p_size = QUIC_ARRAYSIZE(packet);
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
- p_size = QUIC_ARRAYSIZE(packet47);
+ } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
+ p_size = QUIC_ARRAYSIZE(packet46);
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
p_size = QUIC_ARRAYSIZE(packet44);
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
}
QuicEncryptedPacket encrypted(AsChars(p), p_size, false);
@@ -1764,36 +1663,6 @@
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
// packet number
{"",
- {0x78, 0x56, 0x34, 0x12}},
- // frame type (stream frame with fin)
- {"",
- {0xFF}},
- // stream id
- {"Unable to read stream_id.",
- {0x04, 0x03, 0x02, 0x01}},
- // offset
- {"Unable to read offset.",
- {0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0x3A}},
- {"Unable to read frame data.",
- {
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!'}},
- };
-
- PacketFragments packet39 = {
- // public flags (8 byte connection_id)
- {"",
- {0x28}},
- // connection_id
- {"",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"",
{0x12, 0x34, 0x56, 0x78}},
// frame type (stream frame with fin)
{"",
@@ -1845,7 +1714,7 @@
'r', 'l', 'd', '!'}},
};
- PacketFragments packet47 = {
+ PacketFragments packet46 = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -1909,13 +1778,10 @@
PacketFragments& fragments =
framer_.transport_version() == QUIC_VERSION_99
? packet99
- : (framer_.transport_version() > QUIC_VERSION_46
- ? packet47
- : (framer_.transport_version() > QUIC_VERSION_43
- ? packet44
- : (framer_.transport_version() != QUIC_VERSION_35
- ? packet39
- : packet)));
+ : (framer_.transport_version() > QUIC_VERSION_44
+ ? packet46
+ : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
+ : packet));
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -1996,33 +1862,10 @@
QuicMakeUnique<NullDecrypter>(Perspective::IS_CLIENT));
decrypter_ = new test::TestDecrypter();
framer_.SetAlternativeDecrypter(
- ENCRYPTION_INITIAL, std::unique_ptr<QuicDecrypter>(decrypter_), false);
+ ENCRYPTION_ZERO_RTT, std::unique_ptr<QuicDecrypter>(decrypter_), false);
// clang-format off
unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x28,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // frame type (stream frame with fin)
- 0xFF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0x3A,
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
-
- unsigned char packet39[] = {
// public flags (8 byte connection_id)
0x28,
// connection_id
@@ -2076,8 +1919,6 @@
unsigned char* p = packet;
if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
}
QuicEncryptedPacket encrypted(AsChars(p),
framer_.transport_version() > QUIC_VERSION_43
@@ -2108,36 +1949,6 @@
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
// packet number
{"",
- {0x78, 0x56, 0x34, 0x12}},
- // frame type (stream frame with fin)
- {"",
- {0xFE}},
- // stream id
- {"Unable to read stream_id.",
- {0x04, 0x03, 0x02}},
- // offset
- {"Unable to read offset.",
- {0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0x3A}},
- {"Unable to read frame data.",
- {
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!'}},
- };
-
- PacketFragments packet39 = {
- // public flags (8 byte connection_id)
- {"",
- {0x28}},
- // connection_id
- {"",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"",
{0x12, 0x34, 0x56, 0x78}},
// frame type (stream frame with fin)
{"",
@@ -2160,8 +1971,7 @@
};
// clang-format on
- PacketFragments& fragments =
- framer_.transport_version() != QUIC_VERSION_35 ? packet39 : packet;
+ PacketFragments& fragments = packet;
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -2194,36 +2004,6 @@
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
// packet number
{"",
- {0x78, 0x56, 0x34, 0x12}},
- // frame type (stream frame with fin)
- {"",
- {0xFD}},
- // stream id
- {"Unable to read stream_id.",
- {0x04, 0x03}},
- // offset
- {"Unable to read offset.",
- {0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0x3A}},
- {"Unable to read frame data.",
- {
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!'}},
- };
-
- PacketFragments packet39 = {
- // public flags (8 byte connection_id)
- {"",
- {0x28}},
- // connection_id
- {"",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"",
{0x12, 0x34, 0x56, 0x78}},
// frame type (stream frame with fin)
{"",
@@ -2275,7 +2055,7 @@
'r', 'l', 'd', '!'}},
};
- PacketFragments packet47 = {
+ PacketFragments packet46 = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -2339,13 +2119,10 @@
PacketFragments& fragments =
framer_.transport_version() == QUIC_VERSION_99
? packet99
- : (framer_.transport_version() > QUIC_VERSION_46
- ? packet47
- : (framer_.transport_version() > QUIC_VERSION_43
- ? packet44
- : (framer_.transport_version() != QUIC_VERSION_35
- ? packet39
- : packet)));
+ : (framer_.transport_version() > QUIC_VERSION_44
+ ? packet46
+ : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
+ : packet));
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -2378,36 +2155,6 @@
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
// packet number
{"",
- {0x78, 0x56, 0x34, 0x12}},
- // frame type (stream frame with fin)
- {"",
- {0xFC}},
- // stream id
- {"Unable to read stream_id.",
- {0x04}},
- // offset
- {"Unable to read offset.",
- {0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0x3A}},
- {"Unable to read frame data.",
- {
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!'}},
- };
-
- PacketFragments packet39 = {
- // public flags (8 byte connection_id)
- {"",
- {0x28}},
- // connection_id
- {"",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"",
{0x12, 0x34, 0x56, 0x78}},
// frame type (stream frame with fin)
{"",
@@ -2459,7 +2206,7 @@
'r', 'l', 'd', '!'}},
};
- PacketFragments packet47 = {
+ PacketFragments packet46 = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -2523,13 +2270,10 @@
PacketFragments& fragments =
framer_.transport_version() == QUIC_VERSION_99
? packet99
- : (framer_.transport_version() > QUIC_VERSION_46
- ? packet47
- : (framer_.transport_version() > QUIC_VERSION_43
- ? packet44
- : (framer_.transport_version() != QUIC_VERSION_35
- ? packet39
- : packet)));
+ : (framer_.transport_version() > QUIC_VERSION_44
+ ? packet46
+ : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
+ : packet));
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -2565,39 +2309,6 @@
{QUIC_VERSION_BYTES}},
// packet number
{"",
- {0x78, 0x56, 0x34, 0x12}},
- // frame type (stream frame with fin)
- {"",
- {0xFE}},
- // stream id
- {"Unable to read stream_id.",
- {0x04, 0x03, 0x02}},
- // offset
- {"Unable to read offset.",
- {0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0x3A}},
- {"Unable to read frame data.",
- {
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!'}},
- };
-
- PacketFragments packet39 = {
- // public flags (version, 8 byte connection_id)
- {"",
- {0x29}},
- // connection_id
- {"",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // version tag
- {"",
- {QUIC_VERSION_BYTES}},
- // packet number
- {"",
{0x12, 0x34, 0x56, 0x78}},
// frame type (stream frame with fin)
{"",
@@ -2655,7 +2366,7 @@
'r', 'l', 'd', '!'}},
};
- PacketFragments packet47 = {
+ PacketFragments packet46 = {
// public flags (long header with packet type ZERO_RTT_PROTECTED and
// 4-byte packet number)
{"",
@@ -2706,6 +2417,9 @@
// connection_id
{"",
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+ // long header packet length
+ {"",
+ {0x1E}},
// packet number
{"",
{0x12, 0x34, 0x56, 0x78}},
@@ -2713,33 +2427,38 @@
{"",
{0x08 | 0x01 | 0x02 | 0x04}},
// stream id
- {"Unable to read stream_id.",
+ {"Long header payload length longer than packet.",
{kVarInt62FourBytes + 0x00, 0x02, 0x03, 0x04}},
// offset
- {"Unable to read stream data offset.",
+ {"Long header payload length longer than packet.",
{kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC,
0x32, 0x10, 0x76, 0x54}},
// data length
- {"Unable to read stream data length.",
+ {"Long header payload length longer than packet.",
{kVarInt62OneByte + 0x0c}},
// data
- {"Unable to read frame data.",
+ {"Long header payload length longer than packet.",
{ 'h', 'e', 'l', 'l',
'o', ' ', 'w', 'o',
'r', 'l', 'd', '!'}},
};
// clang-format on
+ QuicVariableLengthIntegerLength retry_token_length_length =
+ VARIABLE_LENGTH_INTEGER_LENGTH_0;
+ size_t retry_token_length = 0;
+ QuicVariableLengthIntegerLength length_length =
+ QuicVersionHasLongHeaderLengths(framer_.transport_version())
+ ? VARIABLE_LENGTH_INTEGER_LENGTH_1
+ : VARIABLE_LENGTH_INTEGER_LENGTH_0;
+
PacketFragments& fragments =
framer_.transport_version() == QUIC_VERSION_99
? packet99
- : (framer_.transport_version() > QUIC_VERSION_46
- ? packet47
- : (framer_.transport_version() > QUIC_VERSION_43
- ? packet44
- : (framer_.transport_version() != QUIC_VERSION_35
- ? packet39
- : packet)));
+ : (framer_.transport_version() > QUIC_VERSION_44
+ ? packet46
+ : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
+ : packet));
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -2748,7 +2467,8 @@
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(CheckDecryption(
*encrypted, kIncludeVersion, !kIncludeDiversificationNonce,
- PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID));
+ PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID,
+ retry_token_length_length, retry_token_length, length_length));
ASSERT_EQ(1u, visitor_.stream_frames_.size());
EXPECT_EQ(0u, visitor_.ack_frames_.size());
@@ -2758,7 +2478,10 @@
EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset);
CheckStreamFrameData("hello world!", visitor_.stream_frames_[0].get());
- CheckFramingBoundaries(fragments, QUIC_INVALID_STREAM_DATA);
+ CheckFramingBoundaries(fragments,
+ framer_.transport_version() == QUIC_VERSION_99
+ ? QUIC_INVALID_PACKET_HEADER
+ : QUIC_INVALID_STREAM_DATA);
}
TEST_P(QuicFramerTest, RejectPacket) {
@@ -2771,29 +2494,6 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // frame type (stream frame with fin)
- 0xFF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0x3A,
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
-
- unsigned char packet39[] = {
- // public flags (8 byte connection_id)
- 0x28,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
0x12, 0x34, 0x56, 0x78,
// frame type (stream frame with fin)
@@ -2834,7 +2534,7 @@
'r', 'l', 'd', '!',
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -2859,12 +2559,10 @@
// clang-format on
unsigned char* p = packet;
- if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
+ if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
}
QuicEncryptedPacket encrypted(AsChars(p),
framer_.transport_version() > QUIC_VERSION_43
@@ -2903,7 +2601,7 @@
0x01,
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type (short header, 1 byte packet number)
0x40,
// connection_id
@@ -2914,12 +2612,12 @@
// clang-format on
QuicEncryptedPacket encrypted(
- framer_.transport_version() > QUIC_VERSION_46
- ? AsChars(packet47)
+ framer_.transport_version() > QUIC_VERSION_44
+ ? AsChars(packet46)
: (framer_.transport_version() > QUIC_VERSION_43 ? AsChars(packet44)
: AsChars(packet)),
- framer_.transport_version() > QUIC_VERSION_46
- ? QUIC_ARRAYSIZE(packet47)
+ framer_.transport_version() > QUIC_VERSION_44
+ ? QUIC_ARRAYSIZE(packet46)
: (framer_.transport_version() > QUIC_VERSION_43
? QUIC_ARRAYSIZE(packet44)
: QUIC_ARRAYSIZE(packet)),
@@ -2942,34 +2640,6 @@
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
// packet number
{"",
- {0x78, 0x56, 0x34, 0x12}},
- // frame type (ack frame)
- // (one ack block, 2 byte largest observed, 2 byte block length)
- {"",
- {0x45}},
- // largest acked
- {"Unable to read largest acked.",
- {0x34, 0x12}},
- // Zero delta time.
- {"Unable to read ack delay time.",
- {0x00, 0x00}},
- // first ack block length.
- {"Unable to read first ack block length.",
- {0x34, 0x12}},
- // num timestamps.
- {"Unable to read num received packets.",
- {0x00}}
- };
-
- PacketFragments packet39 = {
- // public flags (8 byte connection_id)
- {"",
- {0x2C}},
- // connection_id
- {"",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"",
{0x12, 0x34, 0x56, 0x78}},
// frame type (ack frame)
// (one ack block, 2 byte largest observed, 2 byte block length)
@@ -3017,7 +2687,7 @@
{0x00}}
};
- PacketFragments packet47 = {
+ PacketFragments packet46 = {
// type (short packet, 4 byte packet number)
{"",
{0x43}},
@@ -3084,13 +2754,10 @@
PacketFragments& fragments =
framer_.transport_version() == QUIC_VERSION_99
? packet99
- : (framer_.transport_version() > QUIC_VERSION_46
- ? packet47
- : (framer_.transport_version() > QUIC_VERSION_43
- ? packet44
- : (framer_.transport_version() != QUIC_VERSION_35
- ? packet39
- : packet)));
+ : (framer_.transport_version() > QUIC_VERSION_44
+ ? packet46
+ : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
+ : packet));
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -3124,34 +2791,6 @@
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
// packet number
{"",
- {0x78, 0x56, 0x34, 0x12}},
- // frame type (ack frame)
- // (one ack block, 2 byte largest observed, 2 byte block length)
- {"",
- {0x45}},
- // largest acked
- {"Unable to read largest acked.",
- {0x34, 0x12}},
- // Zero delta time.
- {"Unable to read ack delay time.",
- {0x00, 0x00}},
- // first ack block length.
- {"Unable to read first ack block length.",
- {0x88, 0x88}},
- // num timestamps.
- {"Underflow with first ack block length 34952 largest acked is 4660.",
- {0x00}}
- };
-
- PacketFragments packet39 = {
- // public flags (8 byte connection_id)
- {"",
- {0x2C}},
- // connection_id
- {"",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"",
{0x12, 0x34, 0x56, 0x78}},
// frame type (ack frame)
// (one ack block, 2 byte largest observed, 2 byte block length)
@@ -3199,7 +2838,7 @@
{0x00}}
};
- PacketFragments packet47 = {
+ PacketFragments packet46 = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -3258,13 +2897,10 @@
PacketFragments& fragments =
framer_.transport_version() == QUIC_VERSION_99
? packet99
- : (framer_.transport_version() > QUIC_VERSION_46
- ? packet47
- : (framer_.transport_version() > QUIC_VERSION_43
- ? packet44
- : (framer_.transport_version() != QUIC_VERSION_35
- ? packet39
- : packet)));
+ : (framer_.transport_version() > QUIC_VERSION_44
+ ? packet46
+ : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
+ : packet));
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
@@ -3557,47 +3193,6 @@
{ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }},
// packet number
{"",
- { 0x78, 0x56, 0x34, 0x12 }},
-
- // frame type (ack frame)
- // (more than one ack block, 2 byte largest observed, 2 byte block length)
- {"",
- { 0x65 }},
- // largest acked
- {"Unable to read largest acked.",
- { 0x34, 0x12 }},
- // Zero delta time.
- {"Unable to read ack delay time.",
- { 0x00, 0x00 }},
- // num ack blocks ranges.
- {"Unable to read num of ack blocks.",
- { 0x01 }},
- // first ack block length.
- {"Unable to read first ack block length.",
- { 0x00, 0x00 }},
- // gap to next block.
- { "First block length is zero but ACK is not empty. "
- "largest acked is 4660, num ack blocks is 1.",
- { 0x01 }},
- // ack block length.
- { "First block length is zero but ACK is not empty. "
- "largest acked is 4660, num ack blocks is 1.",
- { 0xaf, 0x0e }},
- // Number of timestamps.
- { "First block length is zero but ACK is not empty. "
- "largest acked is 4660, num ack blocks is 1.",
- { 0x00 }},
- };
-
- PacketFragments packet39 = {
- // public flags (8 byte connection_id)
- {"",
- { 0x2C }},
- // connection_id
- {"",
- { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }},
- // packet number
- {"",
{ 0x12, 0x34, 0x56, 0x78 }},
// frame type (ack frame)
@@ -3617,16 +3212,13 @@
{"Unable to read first ack block length.",
{ 0x00, 0x00 }},
// gap to next block.
- { "First block length is zero but ACK is not empty. "
- "largest acked is 4660, num ack blocks is 1.",
+ { "First block length is zero.",
{ 0x01 }},
// ack block length.
- { "First block length is zero but ACK is not empty. "
- "largest acked is 4660, num ack blocks is 1.",
+ { "First block length is zero.",
{ 0x0e, 0xaf }},
// Number of timestamps.
- { "First block length is zero but ACK is not empty. "
- "largest acked is 4660, num ack blocks is 1.",
+ { "First block length is zero.",
{ 0x00 }},
};
@@ -3658,20 +3250,17 @@
{"Unable to read first ack block length.",
{ 0x00, 0x00 }},
// gap to next block.
- { "First block length is zero but ACK is not empty. "
- "largest acked is 4660, num ack blocks is 1.",
+ { "First block length is zero.",
{ 0x01 }},
// ack block length.
- { "First block length is zero but ACK is not empty. "
- "largest acked is 4660, num ack blocks is 1.",
+ { "First block length is zero.",
{ 0x0e, 0xaf }},
// Number of timestamps.
- { "First block length is zero but ACK is not empty. "
- "largest acked is 4660, num ack blocks is 1.",
+ { "First block length is zero.",
{ 0x00 }},
};
- PacketFragments packet47 = {
+ PacketFragments packet46 = {
// type (short header, 4 byte packet number)
{"",
{ 0x43 }},
@@ -3699,27 +3288,21 @@
{"Unable to read first ack block length.",
{ 0x00, 0x00 }},
// gap to next block.
- { "First block length is zero but ACK is not empty. "
- "largest acked is 4660, num ack blocks is 1.",
+ { "First block length is zero.",
{ 0x01 }},
// ack block length.
- { "First block length is zero but ACK is not empty. "
- "largest acked is 4660, num ack blocks is 1.",
+ { "First block length is zero.",
{ 0x0e, 0xaf }},
// Number of timestamps.
- { "First block length is zero but ACK is not empty. "
- "largest acked is 4660, num ack blocks is 1.",
+ { "First block length is zero.",
{ 0x00 }},
};
// clang-format on
PacketFragments& fragments =
- framer_.transport_version() > QUIC_VERSION_46
- ? packet47
- : (framer_.transport_version() > QUIC_VERSION_43
- ? packet44
- : (framer_.transport_version() != QUIC_VERSION_35 ? packet39
- : packet));
+ framer_.transport_version() > QUIC_VERSION_44
+ ? packet46
+ : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
@@ -3749,34 +3332,6 @@
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
// packet number
{"",
- {0x78, 0x56, 0x34, 0x12}},
- // frame type (ack frame)
- // (one ack block, 4 byte largest observed, 2 byte block length)
- {"",
- {0x49}},
- // largest acked
- {"Unable to read largest acked.",
- {0x78, 0x56, 0x34, 0x12}},
- // Zero delta time.
- {"Unable to read ack delay time.",
- {0x00, 0x00}},
- // first ack block length.
- {"Unable to read first ack block length.",
- {0x34, 0x12}},
- // num timestamps.
- {"Unable to read num received packets.",
- {0x00}}
- };
-
- PacketFragments packet39 = {
- // public flags (8 byte connection_id)
- {"",
- {0x2C}},
- // connection_id
- {"",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"",
{0x12, 0x34, 0x56, 0x78}},
// frame type (ack frame)
// (one ack block, 4 byte largest observed, 2 byte block length)
@@ -3824,7 +3379,7 @@
{0x00}}
};
- PacketFragments packet47 = {
+ PacketFragments packet46 = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -3883,13 +3438,10 @@
PacketFragments& fragments =
framer_.transport_version() == QUIC_VERSION_99
? packet99
- : (framer_.transport_version() > QUIC_VERSION_46
- ? packet47
- : (framer_.transport_version() > QUIC_VERSION_43
- ? packet44
- : (framer_.transport_version() != QUIC_VERSION_35
- ? packet39
- : packet)));
+ : (framer_.transport_version() > QUIC_VERSION_44
+ ? packet46
+ : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
+ : packet));
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -3922,74 +3474,6 @@
{ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }},
// packet number
{"",
- { 0x78, 0x56, 0x34, 0x12 }},
-
- // frame type (ack frame)
- // (more than one ack block, 2 byte largest observed, 2 byte block length)
- {"",
- { 0x65 }},
- // largest acked
- {"Unable to read largest acked.",
- { 0x34, 0x12 }},
- // Zero delta time.
- {"Unable to read ack delay time.",
- { 0x00, 0x00 }},
- // num ack blocks ranges.
- {"Unable to read num of ack blocks.",
- { 0x04 }},
- // first ack block length.
- {"Unable to read first ack block length.",
- { 0x01, 0x00 }},
- // gap to next block.
- { "Unable to read gap to next ack block.",
- { 0x01 }},
- // ack block length.
- { "Unable to ack block length.",
- { 0xaf, 0x0e }},
- // gap to next block.
- { "Unable to read gap to next ack block.",
- { 0xff }},
- // ack block length.
- { "Unable to ack block length.",
- { 0x00, 0x00 }},
- // gap to next block.
- { "Unable to read gap to next ack block.",
- { 0x91 }},
- // ack block length.
- { "Unable to ack block length.",
- { 0xea, 0x01 }},
- // gap to next block.
- { "Unable to read gap to next ack block.",
- { 0x05 }},
- // ack block length.
- { "Unable to ack block length.",
- { 0x04, 0x00 }},
- // Number of timestamps.
- { "Unable to read num received packets.",
- { 0x02 }},
- // Delta from largest observed.
- { "Unable to read sequence delta in received packets.",
- { 0x01 }},
- // Delta time.
- { "Unable to read time delta in received packets.",
- { 0x10, 0x32, 0x54, 0x76 }},
- // Delta from largest observed.
- { "Unable to read sequence delta in received packets.",
- { 0x02 }},
- // Delta time.
- { "Unable to read incremental time delta in received packets.",
- { 0x10, 0x32 }},
- };
-
- PacketFragments packet39 = {
- // public flags (8 byte connection_id)
- {"",
- { 0x2C }},
- // connection_id
- {"",
- { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }},
- // packet number
- {"",
{ 0x12, 0x34, 0x56, 0x78 }},
// frame type (ack frame)
@@ -4117,7 +3601,7 @@
{ 0x32, 0x10 }},
};
- PacketFragments packet47 = {
+ PacketFragments packet46 = {
// type (short header, 4 byte packet number)
{"",
{ 0x43 }},
@@ -4245,13 +3729,10 @@
PacketFragments& fragments =
framer_.transport_version() == QUIC_VERSION_99
? packet99
- : (framer_.transport_version() > QUIC_VERSION_46
- ? packet47
- : (framer_.transport_version() > QUIC_VERSION_43
- ? packet44
- : (framer_.transport_version() != QUIC_VERSION_35
- ? packet39
- : packet)));
+ : (framer_.transport_version() > QUIC_VERSION_44
+ ? packet46
+ : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
+ : packet));
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
@@ -4279,6 +3760,200 @@
CheckFramingBoundaries(fragments, QUIC_INVALID_ACK_DATA);
}
+TEST_P(QuicFramerTest, AckFrameTimeStampDeltaTooHigh) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x28,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+
+ // frame type (ack frame)
+ // (no ack blocks, 1 byte largest observed, 1 byte block length)
+ 0x40,
+ // largest acked
+ 0x01,
+ // Zero delta time.
+ 0x00, 0x00,
+ // first ack block length.
+ 0x01,
+ // num timestamps.
+ 0x01,
+ // Delta from largest observed.
+ 0x01,
+ // Delta time.
+ 0x10, 0x32, 0x54, 0x76,
+ };
+
+ unsigned char packet44[] = {
+ // type (short header, 4 byte packet number)
+ 0x32,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+
+ // frame type (ack frame)
+ // (no ack blocks, 1 byte largest observed, 1 byte block length)
+ 0x40,
+ // largest acked
+ 0x01,
+ // Zero delta time.
+ 0x00, 0x00,
+ // first ack block length.
+ 0x01,
+ // num timestamps.
+ 0x01,
+ // Delta from largest observed.
+ 0x01,
+ // Delta time.
+ 0x10, 0x32, 0x54, 0x76,
+ };
+
+ unsigned char packet46[] = {
+ // type (short header, 4 byte packet number)
+ 0x43,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+
+ // frame type (ack frame)
+ // (no ack blocks, 1 byte largest observed, 1 byte block length)
+ 0x40,
+ // largest acked
+ 0x01,
+ // Zero delta time.
+ 0x00, 0x00,
+ // first ack block length.
+ 0x01,
+ // num timestamps.
+ 0x01,
+ // Delta from largest observed.
+ 0x01,
+ // Delta time.
+ 0x10, 0x32, 0x54, 0x76,
+ };
+ // clang-format on
+ if (framer_.transport_version() == QUIC_VERSION_99) {
+ return;
+ }
+ QuicEncryptedPacket encrypted(
+ AsChars(framer_.transport_version() > QUIC_VERSION_44
+ ? packet46
+ : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
+ : packet)),
+ QUIC_ARRAYSIZE(packet), false);
+ EXPECT_FALSE(framer_.ProcessPacket(encrypted));
+ EXPECT_TRUE(QuicTextUtils::StartsWith(
+ framer_.detailed_error(), "delta_from_largest_observed too high"));
+}
+
+TEST_P(QuicFramerTest, AckFrameTimeStampSecondDeltaTooHigh) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x28,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+
+ // frame type (ack frame)
+ // (no ack blocks, 1 byte largest observed, 1 byte block length)
+ 0x40,
+ // largest acked
+ 0x03,
+ // Zero delta time.
+ 0x00, 0x00,
+ // first ack block length.
+ 0x03,
+ // num timestamps.
+ 0x02,
+ // Delta from largest observed.
+ 0x01,
+ // Delta time.
+ 0x10, 0x32, 0x54, 0x76,
+ // Delta from largest observed.
+ 0x03,
+ // Delta time.
+ 0x10, 0x32,
+ };
+
+ unsigned char packet44[] = {
+ // type (short header, 4 byte packet number)
+ 0x32,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+
+ // frame type (ack frame)
+ // (no ack blocks, 1 byte largest observed, 1 byte block length)
+ 0x40,
+ // largest acked
+ 0x03,
+ // Zero delta time.
+ 0x00, 0x00,
+ // first ack block length.
+ 0x03,
+ // num timestamps.
+ 0x02,
+ // Delta from largest observed.
+ 0x01,
+ // Delta time.
+ 0x10, 0x32, 0x54, 0x76,
+ // Delta from largest observed.
+ 0x03,
+ // Delta time.
+ 0x10, 0x32,
+ };
+
+ unsigned char packet46[] = {
+ // type (short header, 4 byte packet number)
+ 0x43,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+
+ // frame type (ack frame)
+ // (no ack blocks, 1 byte largest observed, 1 byte block length)
+ 0x40,
+ // largest acked
+ 0x03,
+ // Zero delta time.
+ 0x00, 0x00,
+ // first ack block length.
+ 0x03,
+ // num timestamps.
+ 0x02,
+ // Delta from largest observed.
+ 0x01,
+ // Delta time.
+ 0x10, 0x32, 0x54, 0x76,
+ // Delta from largest observed.
+ 0x03,
+ // Delta time.
+ 0x10, 0x32,
+ };
+ // clang-format on
+ if (framer_.transport_version() == QUIC_VERSION_99) {
+ return;
+ }
+ QuicEncryptedPacket encrypted(
+ AsChars(framer_.transport_version() > QUIC_VERSION_44
+ ? packet46
+ : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
+ : packet)),
+ QUIC_ARRAYSIZE(packet), false);
+ EXPECT_FALSE(framer_.ProcessPacket(encrypted));
+ EXPECT_TRUE(QuicTextUtils::StartsWith(
+ framer_.detailed_error(), "delta_from_largest_observed too high"));
+}
+
TEST_P(QuicFramerTest, NewStopWaitingFrame) {
if (version_.transport_version == QUIC_VERSION_99) {
return;
@@ -4293,24 +3968,6 @@
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
// packet number
{"",
- {0x78, 0x56, 0x34, 0x12}},
- // frame type (stop waiting frame)
- {"",
- {0x06}},
- // least packet number awaiting an ack, delta from packet number.
- {"Unable to read least unacked delta.",
- {0x08, 0x00, 0x00, 0x00}}
- };
-
- PacketFragments packet39 = {
- // public flags (8 byte connection_id)
- {"",
- {0x2C}},
- // connection_id
- {"",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"",
{0x12, 0x34, 0x56, 0x78}},
// frame type (stop waiting frame)
{"",
@@ -4338,7 +3995,7 @@
{0x00, 0x00, 0x00, 0x08}}
};
- PacketFragments packet47 = {
+ PacketFragments packet46 = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -4358,12 +4015,10 @@
// clang-format on
PacketFragments& fragments =
- framer_.transport_version() > QUIC_VERSION_46
- ? packet47
- : (framer_.transport_version() > QUIC_VERSION_43
- ? packet44
- : (framer_.transport_version() != QUIC_VERSION_35 ? packet39
- : packet));
+ framer_.transport_version() > QUIC_VERSION_44
+ ? packet46
+ : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet);
+
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -4393,20 +4048,6 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x78, 0x56, 0x34, 0x12,
- // frame type (stop waiting frame)
- 0x06,
- // least packet number awaiting an ack, delta from packet number.
- 0xA8, 0x9A, 0x78, 0x56,
- 0x34, 0x13,
- };
-
- unsigned char packet39[] = {
- // public flags (8 byte connection_id)
- 0x2C,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
0x12, 0x34, 0x56, 0x78,
// frame type (stop waiting frame)
0x06,
@@ -4428,7 +4069,7 @@
0x57, 0x78, 0x9A, 0xA8,
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -4443,13 +4084,10 @@
// clang-format on
QuicEncryptedPacket encrypted(
- AsChars(framer_.transport_version() > QUIC_VERSION_46
- ? packet47
- : (framer_.transport_version() > QUIC_VERSION_43
- ? packet44
- : (framer_.transport_version() == QUIC_VERSION_35
- ? packet
- : packet39))),
+ AsChars(framer_.transport_version() > QUIC_VERSION_44
+ ? packet46
+ : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
+ : packet)),
framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet44)
: QUIC_ARRAYSIZE(packet),
false);
@@ -4469,31 +4107,6 @@
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
// packet number
{"",
- {0x78, 0x56, 0x34, 0x12}},
- // frame type (rst stream frame)
- {"",
- {0x01}},
- // stream id
- {"Unable to read stream_id.",
- {0x04, 0x03, 0x02, 0x01}},
- // sent byte offset
- {"Unable to read rst stream sent byte offset.",
- {0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0x3A}},
- // error code
- {"Unable to read rst stream error code.",
- {0x01, 0x00, 0x00, 0x00}}
- };
-
- PacketFragments packet39 = {
- // public flags (8 byte connection_id)
- {"",
- {0x28}},
- // connection_id
- {"",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"",
{0x12, 0x34, 0x56, 0x78}},
// frame type (rst stream frame)
{"",
@@ -4535,7 +4148,7 @@
{0x00, 0x00, 0x00, 0x01}}
};
- PacketFragments packet47 = {
+ PacketFragments packet46 = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -4588,13 +4201,10 @@
PacketFragments& fragments =
framer_.transport_version() == QUIC_VERSION_99
? packet99
- : (framer_.transport_version() > QUIC_VERSION_46
- ? packet47
- : (framer_.transport_version() > QUIC_VERSION_43
- ? packet44
- : (framer_.transport_version() != QUIC_VERSION_35
- ? packet39
- : packet)));
+ : (framer_.transport_version() > QUIC_VERSION_44
+ ? packet46
+ : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
+ : packet));
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -4622,34 +4232,6 @@
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
// packet number
{"",
- {0x78, 0x56, 0x34, 0x12}},
- // frame type (connection close frame)
- {"",
- {0x02}},
- // error code
- {"Unable to read connection close error code.",
- {0x11, 0x00, 0x00, 0x00}},
- {"Unable to read connection close error details.",
- {
- // error details length
- 0x0d, 0x00,
- // error details
- 'b', 'e', 'c', 'a',
- 'u', 's', 'e', ' ',
- 'I', ' ', 'c', 'a',
- 'n'}
- }
- };
-
- PacketFragments packet39 = {
- // public flags (8 byte connection_id)
- {"",
- {0x28}},
- // connection_id
- {"",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"",
{0x12, 0x34, 0x56, 0x78}},
// frame type (connection close frame)
{"",
@@ -4697,7 +4279,7 @@
}
};
- PacketFragments packet47 = {
+ PacketFragments packet46 = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -4759,13 +4341,10 @@
PacketFragments& fragments =
framer_.transport_version() == QUIC_VERSION_99
? packet99
- : (framer_.transport_version() > QUIC_VERSION_46
- ? packet47
- : (framer_.transport_version() > QUIC_VERSION_43
- ? packet44
- : (framer_.transport_version() != QUIC_VERSION_35
- ? packet39
- : packet)));
+ : (framer_.transport_version() > QUIC_VERSION_44
+ ? packet46
+ : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
+ : packet));
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -4860,37 +4439,6 @@
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
// packet number
{"",
- {0x78, 0x56, 0x34, 0x12}},
- // frame type (go away frame)
- {"",
- {0x03}},
- // error code
- {"Unable to read go away error code.",
- {0x09, 0x00, 0x00, 0x00}},
- // stream id
- {"Unable to read last good stream id.",
- {0x04, 0x03, 0x02, 0x01}},
- {"Unable to read goaway reason.",
- {
- // error details length
- 0x0d, 0x00,
- // error details
- 'b', 'e', 'c', 'a',
- 'u', 's', 'e', ' ',
- 'I', ' ', 'c', 'a',
- 'n'}
- }
- };
-
- PacketFragments packet39 = {
- // public flags (8 byte connection_id)
- {"",
- {0x28}},
- // connection_id
- {"",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"",
{0x12, 0x34, 0x56, 0x78}},
// frame type (go away frame)
{"",
@@ -4946,7 +4494,7 @@
}
};
- PacketFragments packet47 = {
+ PacketFragments packet46 = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -4980,12 +4528,9 @@
// clang-format on
PacketFragments& fragments =
- framer_.transport_version() > QUIC_VERSION_46
- ? packet47
- : (framer_.transport_version() > QUIC_VERSION_43
- ? packet44
- : (framer_.transport_version() != QUIC_VERSION_35 ? packet39
- : packet));
+ framer_.transport_version() > QUIC_VERSION_44
+ ? packet46
+ : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -5019,28 +4564,6 @@
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
// packet number
{"",
- {0x78, 0x56, 0x34, 0x12}},
- // frame type (window update frame)
- {"",
- {0x04}},
- // stream id
- {"Unable to read stream_id.",
- {0x04, 0x03, 0x02, 0x01}},
- // byte offset
- {"Unable to read window byte_offset.",
- {0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0x3A}},
- };
-
- PacketFragments packet39 = {
- // public flags (8 byte connection_id)
- {"",
- {0x28}},
- // connection_id
- {"",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"",
{0x12, 0x34, 0x56, 0x78}},
// frame type (window update frame)
{"",
@@ -5076,7 +4599,7 @@
0x32, 0x10, 0x76, 0x54}},
};
- PacketFragments packet47 = {
+ PacketFragments packet46 = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -5101,12 +4624,9 @@
// clang-format on
PacketFragments& fragments =
- framer_.transport_version() > QUIC_VERSION_46
- ? packet47
- : (framer_.transport_version() > QUIC_VERSION_43
- ? packet44
- : (framer_.transport_version() != QUIC_VERSION_35 ? packet39
- : packet));
+ framer_.transport_version() > QUIC_VERSION_44
+ ? packet46
+ : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet);
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -5159,7 +4679,8 @@
*encrypted, !kIncludeVersion, !kIncludeDiversificationNonce,
PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID));
- EXPECT_EQ(0u, visitor_.window_update_frame_.stream_id);
+ EXPECT_EQ(QuicUtils::GetInvalidStreamId(framer_.transport_version()),
+ visitor_.window_update_frame_.stream_id);
EXPECT_EQ(kStreamOffset, visitor_.window_update_frame_.byte_offset);
CheckFramingBoundaries(packet99, QUIC_INVALID_MAX_DATA_FRAME_DATA);
@@ -5221,24 +4742,6 @@
{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
// packet number
{"",
- {0x78, 0x56, 0x34, 0x12}},
- // frame type (blocked frame)
- {"",
- {0x05}},
- // stream id
- {"Unable to read stream_id.",
- {0x04, 0x03, 0x02, 0x01}},
- };
-
- PacketFragments packet39 = {
- // public flags (8 byte connection_id)
- {"",
- {0x28}},
- // connection_id
- {"",
- {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
- // packet number
- {"",
{0x12, 0x34, 0x56, 0x78}},
// frame type (blocked frame)
{"",
@@ -5266,7 +4769,7 @@
{0x01, 0x02, 0x03, 0x04}},
};
- PacketFragments packet47 = {
+ PacketFragments packet46 = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -5309,13 +4812,10 @@
PacketFragments& fragments =
framer_.transport_version() == QUIC_VERSION_99
? packet99
- : (framer_.transport_version() > QUIC_VERSION_46
- ? packet47
- : (framer_.transport_version() > QUIC_VERSION_43
- ? packet44
- : (framer_.transport_version() != QUIC_VERSION_35
- ? packet39
- : packet)));
+ : (framer_.transport_version() > QUIC_VERSION_44
+ ? packet46
+ : (framer_.transport_version() > QUIC_VERSION_43 ? packet44
+ : packet));
std::unique_ptr<QuicEncryptedPacket> encrypted(
AssemblePacketFromFragments(fragments));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -5348,18 +4848,6 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // frame type (ping frame)
- 0x07,
- };
-
- unsigned char packet39[] = {
- // public flags (8 byte connection_id)
- 0x28,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
0x12, 0x34, 0x56, 0x78,
// frame type (ping frame)
@@ -5378,7 +4866,7 @@
0x07,
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -5406,17 +4894,15 @@
QuicEncryptedPacket encrypted(
AsChars(framer_.transport_version() == QUIC_VERSION_99
? packet99
- : (framer_.transport_version() > QUIC_VERSION_46
- ? packet47
+ : (framer_.transport_version() > QUIC_VERSION_44
+ ? packet46
: framer_.transport_version() > QUIC_VERSION_43
? packet44
- : (framer_.transport_version() == QUIC_VERSION_35
- ? packet
- : packet39))),
+ : packet)),
framer_.transport_version() == QUIC_VERSION_99
? QUIC_ARRAYSIZE(packet99)
- : (framer_.transport_version() > QUIC_VERSION_46
- ? QUIC_ARRAYSIZE(packet47)
+ : (framer_.transport_version() > QUIC_VERSION_44
+ ? QUIC_ARRAYSIZE(packet46)
: framer_.transport_version() > QUIC_VERSION_43
? QUIC_ARRAYSIZE(packet44)
: QUIC_ARRAYSIZE(packet)),
@@ -5466,7 +4952,7 @@
{'m', 'e', 's', 's', 'a', 'g', 'e', '2'}},
};
- PacketFragments packet47 = {
+ PacketFragments packet46 = {
// type (short header, 4 byte packet number)
{"",
{0x43}},
@@ -5495,7 +4981,7 @@
// clang-format on
std::unique_ptr<QuicEncryptedPacket> encrypted(AssemblePacketFromFragments(
- framer_.transport_version() > QUIC_VERSION_46 ? packet47 : packet45));
+ framer_.transport_version() > QUIC_VERSION_44 ? packet46 : packet45));
EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
@@ -5505,11 +4991,11 @@
PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID));
ASSERT_EQ(2u, visitor_.message_frames_.size());
- EXPECT_EQ(7u, visitor_.message_frames_[0]->message_data.length());
- EXPECT_EQ(8u, visitor_.message_frames_[1]->message_data.length());
+ EXPECT_EQ(7u, visitor_.message_frames_[0]->message_length);
+ EXPECT_EQ(8u, visitor_.message_frames_[1]->message_length);
CheckFramingBoundaries(
- framer_.transport_version() > QUIC_VERSION_46 ? packet47 : packet45,
+ framer_.transport_version() > QUIC_VERSION_44 ? packet46 : packet45,
QUIC_INVALID_MESSAGE_DATA);
}
@@ -5744,7 +5230,7 @@
QuicMakeUnique<NullDecrypter>(Perspective::IS_CLIENT));
decrypter_ = new test::TestDecrypter();
framer_.SetAlternativeDecrypter(
- ENCRYPTION_INITIAL, std::unique_ptr<QuicDecrypter>(decrypter_), false);
+ ENCRYPTION_ZERO_RTT, std::unique_ptr<QuicDecrypter>(decrypter_), false);
// This packet cannot be decrypted because diversification nonce is missing.
QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
@@ -5774,7 +5260,7 @@
QuicMakeUnique<NullDecrypter>(Perspective::IS_CLIENT));
decrypter_ = new test::TestDecrypter();
framer_.SetAlternativeDecrypter(
- ENCRYPTION_INITIAL, std::unique_ptr<QuicDecrypter>(decrypter_), false);
+ ENCRYPTION_ZERO_RTT, std::unique_ptr<QuicDecrypter>(decrypter_), false);
// This packet cannot be decrypted because diversification nonce is missing.
QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false);
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
@@ -5892,19 +5378,6 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // frame type (padding frame)
- 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
-
- unsigned char packet39[kMaxPacketSize] = {
- // public flags (8 byte connection_id)
- 0x28,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
0x12, 0x34, 0x56, 0x78,
// frame type (padding frame)
@@ -5925,7 +5398,7 @@
0x00, 0x00, 0x00, 0x00
};
- unsigned char packet47[kMaxPacketSize] = {
+ unsigned char packet46[kMaxPacketSize] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -5955,18 +5428,17 @@
unsigned char* p = packet;
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
- } else if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
+ } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
}
uint64_t header_size = GetPacketHeaderSize(
framer_.transport_version(), PACKET_8BYTE_CONNECTION_ID,
PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion,
- !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER);
+ !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER,
+ VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0);
memset(p + header_size + 1, 0x00, kMaxPacketSize - header_size - 1);
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
@@ -5979,9 +5451,6 @@
}
TEST_P(QuicFramerTest, BuildStreamFramePacketWithNewPaddingFrame) {
- if (framer_.transport_version() == QUIC_VERSION_35) {
- return;
- }
QuicPacketHeader header;
header.destination_connection_id = FramerTestConnectionId();
header.reset_flag = false;
@@ -6000,33 +5469,6 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // paddings
- 0x00, 0x00,
- // frame type (stream frame with fin)
- 0xFF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0x3A,
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- // paddings
- 0x00, 0x00,
- };
-
- unsigned char packet39[] = {
- // public flags (8 byte connection_id)
- 0x28,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
0x12, 0x34, 0x56, 0x78,
// paddings
@@ -6075,7 +5517,7 @@
0x00, 0x00,
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -6138,14 +5580,12 @@
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
- p_size = QUIC_ARRAYSIZE(packet47);
+ } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
+ p_size = QUIC_ARRAYSIZE(packet46);
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
p_size = QUIC_ARRAYSIZE(packet44);
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
}
QuicEncryptedPacket encrypted(AsChars(p), p_size, false);
@@ -6170,19 +5610,6 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // frame type (padding frame)
- 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
-
- unsigned char packet39[kMaxPacketSize] = {
- // public flags (8 byte connection_id and 4 byte packet number)
- 0x28,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
0x12, 0x34, 0x56, 0x78,
// frame type (padding frame)
@@ -6203,7 +5630,7 @@
0x00, 0x00, 0x00, 0x00
};
- unsigned char packet47[kMaxPacketSize] = {
+ unsigned char packet46[kMaxPacketSize] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -6233,18 +5660,17 @@
unsigned char* p = packet;
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
- } else if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
+ } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
}
uint64_t header_size = GetPacketHeaderSize(
framer_.transport_version(), PACKET_8BYTE_CONNECTION_ID,
PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion,
- !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER);
+ !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER,
+ VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0);
memset(p + header_size + 1, 0x00, kMaxPacketSize - header_size - 1);
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
@@ -6273,19 +5699,6 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x78, 0x56,
-
- // frame type (padding frame)
- 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
-
- unsigned char packet39[kMaxPacketSize] = {
- // public flags (8 byte connection_id and 2 byte packet number)
- 0x18,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
0x56, 0x78,
// frame type (padding frame)
@@ -6306,7 +5719,7 @@
0x00, 0x00, 0x00, 0x00
};
- unsigned char packet47[kMaxPacketSize] = {
+ unsigned char packet46[kMaxPacketSize] = {
// type (short header, 2 byte packet number)
0x41,
// connection_id
@@ -6336,18 +5749,17 @@
unsigned char* p = packet;
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
- } else if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
+ } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
}
uint64_t header_size = GetPacketHeaderSize(
framer_.transport_version(), PACKET_8BYTE_CONNECTION_ID,
PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion,
- !kIncludeDiversificationNonce, PACKET_2BYTE_PACKET_NUMBER);
+ !kIncludeDiversificationNonce, PACKET_2BYTE_PACKET_NUMBER,
+ VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0);
memset(p + header_size + 1, 0x00, kMaxPacketSize - header_size - 1);
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
@@ -6396,7 +5808,7 @@
0x00, 0x00, 0x00, 0x00
};
- unsigned char packet47[kMaxPacketSize] = {
+ unsigned char packet46[kMaxPacketSize] = {
// type (short header, 1 byte packet number)
0x40,
// connection_id
@@ -6426,8 +5838,8 @@
unsigned char* p = packet;
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
- } else if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
+ } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
}
@@ -6435,7 +5847,8 @@
uint64_t header_size = GetPacketHeaderSize(
framer_.transport_version(), PACKET_8BYTE_CONNECTION_ID,
PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion,
- !kIncludeDiversificationNonce, PACKET_1BYTE_PACKET_NUMBER);
+ !kIncludeDiversificationNonce, PACKET_1BYTE_PACKET_NUMBER,
+ VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0);
memset(p + header_size + 1, 0x00, kMaxPacketSize - header_size - 1);
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
@@ -6453,6 +5866,9 @@
header.reset_flag = false;
header.version_flag = false;
header.packet_number = kPacketNumber;
+ if (QuicVersionHasLongHeaderLengths(framer_.transport_version())) {
+ header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2;
+ }
QuicStreamFrame stream_frame(kStreamId, true, kStreamOffset,
QuicStringPiece("hello world!"));
@@ -6466,27 +5882,6 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // frame type (stream frame with fin and no length)
- 0xDF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0x3A,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
-
- unsigned char packet39[] = {
- // public flags (8 byte connection_id)
- 0x28,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
0x12, 0x34, 0x56, 0x78,
// frame type (stream frame with fin and no length)
@@ -6523,7 +5918,7 @@
'r', 'l', 'd', '!',
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -6574,14 +5969,12 @@
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
- p_size = QUIC_ARRAYSIZE(packet47);
+ } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
+ p_size = QUIC_ARRAYSIZE(packet46);
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
p_size = QUIC_ARRAYSIZE(packet44);
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
}
test::CompareCharArraysWithHexError("constructed packet", data->data(),
data->length(), AsChars(p), p_size);
@@ -6596,6 +5989,9 @@
header.long_packet_type = ZERO_RTT_PROTECTED;
}
header.packet_number = kPacketNumber;
+ if (QuicVersionHasLongHeaderLengths(framer_.transport_version())) {
+ header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2;
+ }
QuicStreamFrame stream_frame(kStreamId, true, kStreamOffset,
QuicStringPiece("hello world!"));
@@ -6610,26 +6006,6 @@
// version tag
QUIC_VERSION_BYTES,
// packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // frame type (stream frame with fin and no length)
- 0xDF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32, 0xDC, 0xFE, 0x98, 0x3A,
- // data
- 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!',
- };
-
- unsigned char packet39[] = {
- // public flags (version, 8 byte connection_id)
- 0x2D,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // version tag
- QUIC_VERSION_BYTES,
- // packet number
0x12, 0x34, 0x56, 0x78,
// frame type (stream frame with fin and no length)
@@ -6664,7 +6040,7 @@
'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!',
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type (long header with packet type ZERO_RTT_PROTECTED)
0xD3,
// version tag
@@ -6695,6 +6071,8 @@
0x50,
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // length
+ 0x40, 0x1D,
// packet number
0x12, 0x34, 0x56, 0x78,
@@ -6718,14 +6096,12 @@
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
- p_size = QUIC_ARRAYSIZE(packet47);
+ } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
+ p_size = QUIC_ARRAYSIZE(packet46);
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
p_size = QUIC_ARRAYSIZE(packet44);
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
}
test::CompareCharArraysWithHexError("constructed packet", data->data(),
data->length(), AsChars(p), p_size);
@@ -6896,27 +6272,6 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // frame type (ack frame)
- // (no ack blocks, 2 byte largest observed, 2 byte block length)
- 0x45,
- // largest acked
- 0x34, 0x12,
- // Zero delta time.
- 0x00, 0x00,
- // first ack block length.
- 0x34, 0x12,
- // num timestamps.
- 0x00,
- };
-
- unsigned char packet39[] = {
- // public flags (8 byte connection_id)
- 0x28,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
0x12, 0x34, 0x56, 0x78,
// frame type (ack frame)
@@ -6953,7 +6308,7 @@
0x00,
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -6999,14 +6354,12 @@
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
- p_size = QUIC_ARRAYSIZE(packet47);
+ } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
+ p_size = QUIC_ARRAYSIZE(packet46);
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
p_size = QUIC_ARRAYSIZE(packet44);
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
}
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
@@ -7034,27 +6387,6 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // frame type (ack frame)
- // (no ack blocks, 4 byte largest observed, 4 byte block length)
- 0x4A,
- // largest acked
- 0x78, 0x56, 0x34, 0x12,
- // Zero delta time.
- 0x00, 0x00,
- // first ack block length.
- 0x78, 0x56, 0x34, 0x12,
- // num timestamps.
- 0x00,
- };
-
- unsigned char packet39[] = {
- // public flags (8 byte connection_id)
- 0x28,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
0x12, 0x34, 0x56, 0x78,
// frame type (ack frame)
@@ -7091,7 +6423,7 @@
0x00,
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -7138,14 +6470,12 @@
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
- p_size = QUIC_ARRAYSIZE(packet47);
+ } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
+ p_size = QUIC_ARRAYSIZE(packet46);
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
p_size = QUIC_ARRAYSIZE(packet44);
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
}
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
@@ -7178,45 +6508,6 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // frame type (ack frame)
- // (has ack blocks, 2 byte largest observed, 2 byte block length)
- 0x65,
- // largest acked
- 0x34, 0x12,
- // Zero delta time.
- 0x00, 0x00,
- // num ack blocks ranges.
- 0x04,
- // first ack block length.
- 0x01, 0x00,
- // gap to next block.
- 0x01,
- // ack block length.
- 0xaf, 0x0e,
- // gap to next block.
- 0xff,
- // ack block length.
- 0x00, 0x00,
- // gap to next block.
- 0x91,
- // ack block length.
- 0xea, 0x01,
- // gap to next block.
- 0x05,
- // ack block length.
- 0x04, 0x00,
- // num timestamps.
- 0x00,
- };
-
- unsigned char packet39[] = {
- // public flags (8 byte connection_id)
- 0x28,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
0x12, 0x34, 0x56, 0x78,
// frame type (ack frame)
@@ -7289,7 +6580,7 @@
0x00,
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -7368,14 +6659,12 @@
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
- p_size = QUIC_ARRAYSIZE(packet47);
+ } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
+ p_size = QUIC_ARRAYSIZE(packet46);
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
p_size = QUIC_ARRAYSIZE(packet44);
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
}
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
@@ -7411,99 +6700,6 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x78, 0x56, 0x34, 0x12,
- // frame type (ack frame)
- // (has ack blocks, 2 byte largest observed, 2 byte block length)
- 0x65,
- // largest acked
- 0x34, 0x12,
- // Zero delta time.
- 0x00, 0x00,
- // num ack blocks ranges.
- 0xff,
- // first ack block length.
- 0xdd, 0x0f,
- // 255 = 4 * 63 + 3
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
-
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
-
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
-
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
-
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
-
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
-
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- // num timestamps.
- 0x00,
- };
-
- unsigned char packet39[] = {
- // public flags (8 byte connection_id)
- 0x28,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
0x12, 0x34, 0x56, 0x78,
// frame type (ack frame)
// (has ack blocks, 2 byte largest observed, 2 byte block length)
@@ -7684,7 +6880,7 @@
0x00,
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -7867,14 +7063,12 @@
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
- p_size = QUIC_ARRAYSIZE(packet47);
+ } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
+ p_size = QUIC_ARRAYSIZE(packet46);
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
p_size = QUIC_ARRAYSIZE(packet44);
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
}
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
@@ -7906,20 +7100,6 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // frame type (stop waiting frame)
- 0x06,
- // least packet number awaiting an ack, delta from packet number.
- 0x08, 0x00, 0x00, 0x00,
- };
-
- unsigned char packet39[] = {
- // public flags (8 byte connection_id)
- 0x28,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
0x12, 0x34, 0x56, 0x78,
// frame type (stop waiting frame)
@@ -7930,18 +7110,12 @@
// clang-format on
- unsigned char* p = packet;
- if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
- }
-
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != nullptr);
- test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(), AsChars(p),
- framer_.transport_version() != QUIC_VERSION_35 ? QUIC_ARRAYSIZE(packet39)
- : QUIC_ARRAYSIZE(packet));
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(packet),
+ QUIC_ARRAYSIZE(packet));
}
TEST_P(QuicFramerTest, BuildRstFramePacketQuic) {
@@ -7967,25 +7141,6 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // frame type (rst stream frame)
- 0x01,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // sent byte offset
- 0x01, 0x02, 0x03, 0x04,
- 0x05, 0x06, 0x07, 0x08,
- // error code
- 0x08, 0x07, 0x06, 0x05,
- };
-
- unsigned char packet39[] = {
- // public flags (8 byte connection_id)
- 0x28,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
0x12, 0x34, 0x56, 0x78,
// frame type (rst stream frame)
@@ -8018,7 +7173,7 @@
0x05, 0x06, 0x07, 0x08,
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type (short packet, 4 byte packet number)
0x43,
// connection_id
@@ -8066,14 +7221,12 @@
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
- p_size = QUIC_ARRAYSIZE(packet47);
+ } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
+ p_size = QUIC_ARRAYSIZE(packet46);
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
p_size = QUIC_ARRAYSIZE(packet44);
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
}
QuicEncryptedPacket encrypted(AsChars(p), p_size, false);
@@ -8107,27 +7260,6 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // frame type (connection close frame)
- 0x02,
- // error code
- 0x08, 0x07, 0x06, 0x05,
- // error details length
- 0x0d, 0x00,
- // error details
- 'b', 'e', 'c', 'a',
- 'u', 's', 'e', ' ',
- 'I', ' ', 'c', 'a',
- 'n',
- };
-
- unsigned char packet39[] = {
- // public flags (8 byte connection_id)
- 0x28,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
0x12, 0x34, 0x56, 0x78,
// frame type (connection close frame)
@@ -8164,7 +7296,7 @@
'n',
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -8214,14 +7346,12 @@
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
- p_size = QUIC_ARRAYSIZE(packet47);
+ } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
+ p_size = QUIC_ARRAYSIZE(packet46);
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
p_size = QUIC_ARRAYSIZE(packet44);
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
}
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
@@ -8255,55 +7385,6 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // frame type (connection close frame)
- 0x02,
- // error code
- 0x08, 0x07, 0x06, 0x05,
- // error details length
- 0x00, 0x01,
- // error details (truncated to 256 bytes)
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- };
-
- unsigned char packet39[] = {
- // public flags (8 byte connection_id)
- 0x28,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
0x12, 0x34, 0x56, 0x78,
// frame type (connection close frame)
@@ -8396,7 +7477,7 @@
'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -8502,14 +7583,12 @@
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
- p_size = QUIC_ARRAYSIZE(packet47);
+ } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
+ p_size = QUIC_ARRAYSIZE(packet46);
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
p_size = QUIC_ARRAYSIZE(packet44);
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
}
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
@@ -8669,29 +7748,6 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // frame type (go away frame)
- 0x03,
- // error code
- 0x08, 0x07, 0x06, 0x05,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // error details length
- 0x0d, 0x00,
- // error details
- 'b', 'e', 'c', 'a',
- 'u', 's', 'e', ' ',
- 'I', ' ', 'c', 'a',
- 'n',
- };
-
- unsigned char packet39[] = {
- // public flags (8 byte connection_id)
- 0x28,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
0x12, 0x34, 0x56, 0x78,
// frame type (go away frame)
@@ -8732,7 +7788,7 @@
'n',
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -8759,14 +7815,12 @@
unsigned char* p = packet;
size_t p_size = QUIC_ARRAYSIZE(packet);
- if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
- p_size = QUIC_ARRAYSIZE(packet47);
+ if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
+ p_size = QUIC_ARRAYSIZE(packet46);
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
p_size = QUIC_ARRAYSIZE(packet44);
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
}
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
@@ -8801,57 +7855,6 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // frame type (go away frame)
- 0x03,
- // error code
- 0x08, 0x07, 0x06, 0x05,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // error details length
- 0x00, 0x01,
- // error details (truncated to 256 bytes)
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
- };
-
- unsigned char packet39[] = {
- // public flags (8 byte connection_id)
- 0x28,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
0x12, 0x34, 0x56, 0x78,
// frame type (go away frame)
@@ -8948,7 +7951,7 @@
'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -9002,14 +8005,12 @@
unsigned char* p = packet;
size_t p_size = QUIC_ARRAYSIZE(packet);
- if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
- p_size = QUIC_ARRAYSIZE(packet47);
+ if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
+ p_size = QUIC_ARRAYSIZE(packet46);
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
p_size = QUIC_ARRAYSIZE(packet44);
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
}
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
@@ -9039,23 +8040,6 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // frame type (window update frame)
- 0x04,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // byte offset
- 0x88, 0x77, 0x66, 0x55,
- 0x44, 0x33, 0x22, 0x11,
- };
-
- unsigned char packet39[] = {
- // public flags (8 byte connection_id)
- 0x28,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
0x12, 0x34, 0x56, 0x78,
// frame type (window update frame)
@@ -9084,7 +8068,7 @@
0x55, 0x66, 0x77, 0x88,
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -9127,14 +8111,12 @@
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
- p_size = QUIC_ARRAYSIZE(packet47);
+ } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
+ p_size = QUIC_ARRAYSIZE(packet46);
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
p_size = QUIC_ARRAYSIZE(packet44);
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
}
test::CompareCharArraysWithHexError("constructed packet", data->data(),
@@ -9197,7 +8179,8 @@
header.packet_number = kPacketNumber;
QuicWindowUpdateFrame window_update_frame;
- window_update_frame.stream_id = 0;
+ window_update_frame.stream_id =
+ QuicUtils::GetInvalidStreamId(framer_.transport_version());
window_update_frame.byte_offset = 0x1122334455667788;
QuicFrames frames = {QuicFrame(&window_update_frame)};
@@ -9236,12 +8219,11 @@
QuicBlockedFrame blocked_frame;
if (framer_.transport_version() == QUIC_VERSION_99) {
- // For V99, the stream ID must be 0 for the frame
- // to be a BLOCKED frame. if non-0, it will be a
+ // For V99, the stream ID must be <invalid> for the frame
+ // to be a BLOCKED frame. if it's valid, it will be a
// STREAM_BLOCKED frame.
- // TODO(fkastenholz): This should be converted to use
- // QuicUtils::GetInvalidStreamId to get the correct invalid stream id value.
- blocked_frame.stream_id = 0;
+ blocked_frame.stream_id =
+ QuicUtils::GetInvalidStreamId(framer_.transport_version());
} else {
blocked_frame.stream_id = kStreamId;
}
@@ -9256,20 +8238,6 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // frame type (blocked frame)
- 0x05,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- };
-
- unsigned char packet39[] = {
- // public flags (8 byte connection_id)
- 0x28,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
0x12, 0x34, 0x56, 0x78,
// frame type (blocked frame)
@@ -9292,7 +8260,7 @@
0x01, 0x02, 0x03, 0x04,
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type (short packet, 4 byte packet number)
0x43,
// connection_id
@@ -9314,7 +8282,7 @@
// packet number
0x12, 0x34, 0x56, 0x78,
- // frame type (IETF_BLOCKED frame) wahoo
+ // frame type (IETF_BLOCKED frame)
0x14,
// Offset
kVarInt62EightBytes + 0x3a, 0x98, 0xFE, 0xDC, 0x32, 0x10, 0x76, 0x54
@@ -9329,14 +8297,12 @@
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
- p_size = QUIC_ARRAYSIZE(packet47);
+ } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
+ p_size = QUIC_ARRAYSIZE(packet46);
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
p_size = QUIC_ARRAYSIZE(packet44);
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
}
test::CompareCharArraysWithHexError("constructed packet", data->data(),
@@ -9359,18 +8325,6 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // frame type (ping frame)
- 0x07,
- };
-
- unsigned char packet39[] = {
- // public flags (8 byte connection_id)
- 0x28,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
0x12, 0x34, 0x56, 0x78,
// frame type (ping frame)
@@ -9389,7 +8343,7 @@
0x07,
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -9417,12 +8371,10 @@
unsigned char* p = packet;
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
- } else if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
+ } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
}
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
@@ -9443,9 +8395,13 @@
header.reset_flag = false;
header.version_flag = false;
header.packet_number = kPacketNumber;
+ QuicMemSliceStorage storage(nullptr, 0, nullptr, 0);
- QuicMessageFrame frame(1, "message");
- QuicMessageFrame frame2(2, "message2");
+ QuicMessageFrame frame(1);
+ MakeSpan(&allocator_, "message", &storage).SaveMemSlicesAsMessageData(&frame);
+ QuicMessageFrame frame2(2);
+ MakeSpan(&allocator_, "message2", &storage)
+ .SaveMemSlicesAsMessageData(&frame2);
QuicFrames frames = {QuicFrame(&frame), QuicFrame(&frame2)};
// clang-format off
@@ -9469,7 +8425,7 @@
'm', 'e', 's', 's', 'a', 'g', 'e', '2'
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -9513,8 +8469,8 @@
unsigned char* p = packet45;
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
- } else if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
+ } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
}
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
@@ -9541,21 +8497,6 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // frame type (ping frame)
- 0x07,
- // frame type (padding frame)
- 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
-
- unsigned char packet39[] = {
- // public flags (8 byte connection_id)
- 0x28,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
0x12, 0x34, 0x56, 0x78,
// frame type (ping frame)
@@ -9580,7 +8521,7 @@
0x00, 0x00, 0x00, 0x00
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -9616,70 +8557,21 @@
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
packet_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
- packet_size = QUIC_ARRAYSIZE(packet47);
+ } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
+ packet_size = QUIC_ARRAYSIZE(packet46);
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
packet_size = QUIC_ARRAYSIZE(packet44);
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
- packet_size = QUIC_ARRAYSIZE(packet39);
}
std::unique_ptr<char[]> buffer(new char[kMaxPacketSize]);
- size_t length =
- framer_.BuildConnectivityProbingPacket(header, buffer.get(), packet_size);
+ size_t length = framer_.BuildConnectivityProbingPacket(
+ header, buffer.get(), packet_size, ENCRYPTION_NONE);
EXPECT_NE(0u, length);
- QuicPacket data(buffer.release(), length, true,
- header.destination_connection_id_length,
- header.source_connection_id_length, header.version_flag,
- header.nonce != nullptr, header.packet_number_length);
-
- test::CompareCharArraysWithHexError("constructed packet", data.data(),
- data.length(), AsChars(p), packet_size);
-}
-
-// Test that the IETF connectivity probing packet is serialized correctly as a
-// padded PING packet, v99 only.
-TEST_P(QuicFramerTest, BuildIetfConnectivityProbingPacket) {
- if (framer_.transport_version() != QUIC_VERSION_99) {
- return;
- }
- QuicPacketHeader header;
- header.destination_connection_id = FramerTestConnectionId();
- header.reset_flag = false;
- header.version_flag = false;
- header.packet_number = kPacketNumber;
-
- unsigned char packet99[] = {// type (short header, 4 byte packet number)
- 0x43,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // frame type (IETF_PING frame)
- 0x01,
- // frame type (padding frame)
- 0x00, 0x00, 0x00, 0x00, 0x00};
- // clang-format on
-
- unsigned char* p = packet99;
- size_t packet_size = QUIC_ARRAYSIZE(packet99);
-
- std::unique_ptr<char[]> buffer(new char[kMaxPacketSize]);
-
- size_t length = framer_.BuildIetfConnectivityProbingPacket(
- header, buffer.get(), packet_size);
-
- EXPECT_NE(0u, length);
- QuicPacket data(buffer.release(), length, true,
- header.destination_connection_id_length,
- header.source_connection_id_length, header.version_flag,
- header.nonce != nullptr, header.packet_number_length);
+ QuicPacket data(buffer.release(), length, true, header);
test::CompareCharArraysWithHexError("constructed packet", data.data(),
data.length(), AsChars(p), packet_size);
@@ -9722,17 +8614,15 @@
MockRandom randomizer;
size_t length = framer_.BuildPaddedPathChallengePacket(
- header, buffer.get(), QUIC_ARRAYSIZE(packet), &payload, &randomizer);
+ header, buffer.get(), QUIC_ARRAYSIZE(packet), &payload, &randomizer,
+ ENCRYPTION_NONE);
EXPECT_EQ(length, QUIC_ARRAYSIZE(packet));
// Payload has the random bytes that were generated. Copy them into packet,
// above, before checking that the generated packet is correct.
EXPECT_EQ(kQuicPathFrameBufferSize, payload.size());
- QuicPacket data(buffer.release(), length, true,
- header.destination_connection_id_length,
- header.source_connection_id_length, header.version_flag,
- header.nonce != nullptr, header.packet_number_length);
+ QuicPacket data(buffer.release(), length, true, header);
test::CompareCharArraysWithHexError("constructed packet", data.data(),
data.length(), AsChars(packet),
@@ -9777,12 +8667,9 @@
payloads.push_back(payload0);
size_t length = framer_.BuildPathResponsePacket(
header, buffer.get(), QUIC_ARRAYSIZE(packet), payloads,
- /*is_padded=*/false);
+ /*is_padded=*/false, ENCRYPTION_NONE);
EXPECT_EQ(length, QUIC_ARRAYSIZE(packet));
- QuicPacket data(buffer.release(), length, true,
- header.destination_connection_id_length,
- header.source_connection_id_length, header.version_flag,
- header.nonce != nullptr, header.packet_number_length);
+ QuicPacket data(buffer.release(), length, true, header);
test::CompareCharArraysWithHexError("constructed packet", data.data(),
data.length(), AsChars(packet),
@@ -9825,12 +8712,9 @@
payloads.push_back(payload0);
size_t length = framer_.BuildPathResponsePacket(
header, buffer.get(), QUIC_ARRAYSIZE(packet), payloads,
- /*is_padded=*/true);
+ /*is_padded=*/true, ENCRYPTION_NONE);
EXPECT_EQ(length, QUIC_ARRAYSIZE(packet));
- QuicPacket data(buffer.release(), length, true,
- header.destination_connection_id_length,
- header.source_connection_id_length, header.version_flag,
- header.nonce != nullptr, header.packet_number_length);
+ QuicPacket data(buffer.release(), length, true, header);
test::CompareCharArraysWithHexError("constructed packet", data.data(),
data.length(), AsChars(packet),
@@ -9878,12 +8762,9 @@
payloads.push_back(payload2);
size_t length = framer_.BuildPathResponsePacket(
header, buffer.get(), QUIC_ARRAYSIZE(packet), payloads,
- /*is_padded=*/false);
+ /*is_padded=*/false, ENCRYPTION_NONE);
EXPECT_EQ(length, QUIC_ARRAYSIZE(packet));
- QuicPacket data(buffer.release(), length, true,
- header.destination_connection_id_length,
- header.source_connection_id_length, header.version_flag,
- header.nonce != nullptr, header.packet_number_length);
+ QuicPacket data(buffer.release(), length, true, header);
test::CompareCharArraysWithHexError("constructed packet", data.data(),
data.length(), AsChars(packet),
@@ -9933,12 +8814,9 @@
payloads.push_back(payload2);
size_t length = framer_.BuildPathResponsePacket(
header, buffer.get(), QUIC_ARRAYSIZE(packet), payloads,
- /*is_padded=*/true);
+ /*is_padded=*/true, ENCRYPTION_NONE);
EXPECT_EQ(length, QUIC_ARRAYSIZE(packet));
- QuicPacket data(buffer.release(), length, true,
- header.destination_connection_id_length,
- header.source_connection_id_length, header.version_flag,
- header.nonce != nullptr, header.packet_number_length);
+ QuicPacket data(buffer.release(), length, true, header);
test::CompareCharArraysWithHexError("constructed packet", data.data(),
data.length(), AsChars(packet),
@@ -9962,18 +8840,6 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // frame type (ping frame)
- 0x07,
- };
-
- unsigned char packet39[] = {
- // public flags (8 byte connection_id)
- 0x28,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
0x12, 0x34, 0x56, 0x78,
// frame type (ping frame)
@@ -9992,7 +8858,7 @@
0x07,
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -10023,12 +8889,10 @@
unsigned char* p = packet;
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
- } else if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
+ } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
}
test::CompareCharArraysWithHexError(
@@ -10248,21 +9112,6 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // redundancy
- 'a', 'b', 'c', 'd',
- 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l',
- 'm', 'n', 'o', 'p',
- };
-
- unsigned char packet39[] = {
- // public flags (8 byte connection_id)
- 0x28,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
0x12, 0x34, 0x56, 0x78,
// redundancy
@@ -10287,7 +9136,7 @@
'm', 'n', 'o', 'p',
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -10321,18 +9170,17 @@
unsigned char* p = packet;
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
- } else if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
+ } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
}
std::unique_ptr<QuicPacket> raw(new QuicPacket(
AsChars(p), QUIC_ARRAYSIZE(packet), false, PACKET_8BYTE_CONNECTION_ID,
PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion,
- !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER));
+ !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER,
+ VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0));
char buffer[kMaxPacketSize];
size_t encrypted_length = framer_.EncryptPayload(
ENCRYPTION_NONE, packet_number, *raw, buffer, kMaxPacketSize);
@@ -10352,23 +9200,6 @@
// version tag
'Q', '.', '1', '0',
// packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // redundancy
- 'a', 'b', 'c', 'd',
- 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l',
- 'm', 'n', 'o', 'p',
- };
-
- unsigned char packet39[] = {
- // public flags (version, 8 byte connection_id)
- 0x29,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // version tag
- 'Q', '.', '1', '0',
- // packet number
0x12, 0x34, 0x56, 0x78,
// redundancy
@@ -10397,7 +9228,7 @@
'm', 'n', 'o', 'p',
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type (long header with packet type ZERO_RTT_PROTECTED)
0xD3,
// version tag
@@ -10439,12 +9270,10 @@
unsigned char* p = packet;
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
- } else if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
+ } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
}
std::unique_ptr<QuicPacket> raw(new QuicPacket(
@@ -10453,7 +9282,8 @@
: QUIC_ARRAYSIZE(packet),
false, PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID,
kIncludeVersion, !kIncludeDiversificationNonce,
- PACKET_4BYTE_PACKET_NUMBER));
+ PACKET_4BYTE_PACKET_NUMBER, VARIABLE_LENGTH_INTEGER_LENGTH_0, 0,
+ VARIABLE_LENGTH_INTEGER_LENGTH_0));
char buffer[kMaxPacketSize];
size_t encrypted_length = framer_.EncryptPayload(
ENCRYPTION_NONE, packet_number, *raw, buffer, kMaxPacketSize);
@@ -10594,43 +9424,6 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // frame type (stream frame with fin)
- 0xFF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0x3A,
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
-
- // frame type (ack frame)
- 0x40,
- // least packet number awaiting an ack
- 0xA0, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // largest observed packet number
- 0xBF, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // num missing packets
- 0x01,
- // missing packet
- 0xBE, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- };
-
- unsigned char packet39[] = {
- // public flags (8 byte connection_id)
- 0x28,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
0x12, 0x34, 0x56, 0x78,
// frame type (stream frame with fin)
@@ -10699,7 +9492,7 @@
0x9A, 0xBE,
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -10790,14 +9583,12 @@
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
- p_size = QUIC_ARRAYSIZE(packet47);
+ } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
+ p_size = QUIC_ARRAYSIZE(packet46);
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
p_size = QUIC_ARRAYSIZE(packet44);
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
}
QuicEncryptedPacket encrypted(AsChars(p), p_size, false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
@@ -10844,7 +9635,11 @@
EXPECT_CALL(visitor, OnDecryptedPacket(_)).Times(1);
EXPECT_CALL(visitor, OnError(_)).Times(0);
EXPECT_CALL(visitor, OnStreamFrame(_)).Times(0);
- EXPECT_CALL(visitor, OnStreamFrame(Truly(ExpectedStreamFrame))).Times(1);
+ if (framer_.version().transport_version < QUIC_VERSION_47) {
+ EXPECT_CALL(visitor, OnStreamFrame(Truly(ExpectedStreamFrame))).Times(1);
+ } else {
+ EXPECT_CALL(visitor, OnCryptoFrame(_)).Times(1);
+ }
EXPECT_CALL(visitor, OnPacketComplete()).Times(1);
EXPECT_TRUE(framer_.ProcessPacket(*packet));
@@ -10927,31 +9722,6 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x78, 0x56, 0x34, 0x12,
- // private flags
- 0x00,
-
- // frame type (stream frame with fin)
- 0xFF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0x3A,
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
-
- unsigned char packet39[] = {
- // public flags (8 byte connection_id)
- 0x2C,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
0x12, 0x34, 0x56, 0x78,
// private flags
0x00,
@@ -10992,7 +9762,7 @@
'r', 'l', 'd', '!',
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
// packet number
@@ -11038,12 +9808,10 @@
unsigned char* p = packet;
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
- } else if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
+ } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
}
QuicFramerFuzzFunc(p,
framer_.transport_version() > QUIC_VERSION_43
@@ -11127,7 +9895,7 @@
header.packet_number = kPacketNumber;
QuicBlockedFrame frame;
- frame.stream_id = 0;
+ frame.stream_id = QuicUtils::GetInvalidStreamId(framer_.transport_version());
frame.offset = kStreamOffset;
QuicFrames frames = {QuicFrame(&frame)};
@@ -11242,7 +10010,7 @@
QUIC_ARRAYSIZE(packet99));
}
-TEST_P(QuicFramerTest, MaxStreamIdFrame) {
+TEST_P(QuicFramerTest, ServerBiDiMaxStreamsFrame) {
// This test only for version 99.
if (framer_.transport_version() != QUIC_VERSION_99) {
return;
@@ -11259,12 +10027,12 @@
// packet number
{"",
{0x12, 0x34, 0x9A, 0xBC}},
- // frame type (IETF_MAX_STREAM_ID)
+ // frame type (IETF_MAX_STREAMS_BIDIRECTIONAL)
{"",
{0x12}},
- // max. stream id
- {"Can not read MAX_STREAM_ID stream id.",
- {kVarInt62OneByte + 0x01}},
+ // max. streams
+ {"Can not read MAX_STREAMS stream count.",
+ {kVarInt62OneByte + 0x03}},
};
// clang-format on
@@ -11278,26 +10046,173 @@
*encrypted, !kIncludeVersion, !kIncludeDiversificationNonce,
PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID));
- EXPECT_EQ(0x1u, visitor_.max_stream_id_frame_.max_stream_id);
-
+ // This test is a server receiving a MAX_STREAMS frame. The
+ // stream ID that it generates should be a server-initiated
+ // stream ID. The expected Stream ID is
+ // ((0x3-1) * 4) | 0x1 = 0x9
+ // count-to-id server inited, bidi
+ EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER,
+ /*bidirectional=*/true, 3),
+ visitor_.max_stream_id_frame_.max_stream_id);
CheckFramingBoundaries(packet99, QUIC_MAX_STREAM_ID_DATA);
}
-TEST_P(QuicFramerTest, BuildMaxStreamIdPacket) {
+TEST_P(QuicFramerTest, ClientBiDiMaxStreamsFrame) {
// This test only for version 99.
if (framer_.transport_version() != QUIC_VERSION_99) {
return;
}
- QuicPacketHeader header;
- header.destination_connection_id = FramerTestConnectionId();
- header.reset_flag = false;
- header.version_flag = false;
- header.packet_number = kPacketNumber;
+ // clang-format off
+ PacketFragments packet99 = {
+ // type (short header, 4 byte packet number)
+ {"",
+ {0x43}},
+ // Test runs in client mode, no connection id
+ // packet number
+ {"",
+ {0x12, 0x34, 0x9A, 0xBC}},
+ // frame type (IETF_MAX_STREAMS_BIDIRECTIONAL)
+ {"",
+ {0x12}},
+ // max. streams
+ {"Can not read MAX_STREAMS stream count.",
+ {kVarInt62OneByte + 0x03}},
+ };
+ // clang-format on
- QuicMaxStreamIdFrame frame;
- frame.max_stream_id = kTestQuicStreamId;
- QuicFrames frames = {QuicFrame(frame)};
+ std::unique_ptr<QuicEncryptedPacket> encrypted(
+ AssemblePacketFromFragments(packet99));
+ QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
+ EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(
+ *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce,
+ PACKET_0BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID));
+
+ // This test is a client receiving a MAX_STREAMS frame. The
+ // stream ID that it generates should be a client-initiated
+ // stream ID. The expected Stream ID is
+ // ((0x3-1) * 4) = 0xc
+ // It is not 8 because a client-initiated, bidi stream ID's
+ // low bits are 00 - which means that the old crypto stream
+ // falls into this category, and the first stream is streamid=4,
+ // not streamid=0.
+ EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT,
+ /*bidirectional=*/true, 3),
+ visitor_.max_stream_id_frame_.max_stream_id);
+
+ CheckFramingBoundaries(packet99, QUIC_MAX_STREAM_ID_DATA);
+}
+
+TEST_P(QuicFramerTest, ServerUniDiMaxStreamsFrame) {
+ // This test only for version 99.
+ if (framer_.transport_version() != QUIC_VERSION_99) {
+ return;
+ }
+
+ // clang-format off
+ PacketFragments packet99 = {
+ // type (short header, 4 byte packet number)
+ {"",
+ {0x43}},
+ // connection_id
+ {"",
+ {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+ // packet number
+ {"",
+ {0x12, 0x34, 0x9A, 0xBC}},
+ // frame type (IETF_MAX_STREAMS_UNIDIRECTIONAL)
+ {"",
+ {0x13}},
+ // max. streams
+ {"Can not read MAX_STREAMS stream count.",
+ {kVarInt62OneByte + 0x03}},
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicEncryptedPacket> encrypted(
+ AssemblePacketFromFragments(packet99));
+ EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(
+ *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce,
+ PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID));
+
+ // This test is a server receiving a MAX_STREAMS frame. The
+ // stream ID that it generates should be a server-initiated
+ // stream ID. The expected Stream ID is
+ // ((0x3-1) * 4) | 0x1 | 0x2 = 0xb
+ // count-to-id server inited, unidi
+ EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER,
+ /*bidirectional=*/false, 3),
+ visitor_.max_stream_id_frame_.max_stream_id);
+
+ CheckFramingBoundaries(packet99, QUIC_MAX_STREAM_ID_DATA);
+}
+
+TEST_P(QuicFramerTest, ClientUniDiMaxStreamsFrame) {
+ // This test only for version 99.
+ if (framer_.transport_version() != QUIC_VERSION_99) {
+ return;
+ }
+
+ // clang-format off
+ PacketFragments packet99 = {
+ // type (short header, 4 byte packet number)
+ {"",
+ {0x43}},
+ // Test runs in client mode, no connection id
+ // packet number
+ {"",
+ {0x12, 0x34, 0x9A, 0xBC}},
+ // frame type (IETF_MAX_STREAMS_UNIDIRECTIONAL)
+ {"",
+ {0x13}},
+ // max. streams
+ {"Can not read MAX_STREAMS stream count.",
+ {kVarInt62OneByte + 0x03}},
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicEncryptedPacket> encrypted(
+ AssemblePacketFromFragments(packet99));
+ QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
+ EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(
+ *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce,
+ PACKET_0BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID));
+
+ // This test is a client receiving a MAX_STREAMS frame. The
+ // stream ID that it generates should be a client-initiated
+ // stream ID. The expected Stream ID is
+ // ((0x3-1) * 4) | 0x02= 0xa
+ // count-to-id client/unidi
+ EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT,
+ /*bidirectional=*/false, 3),
+ visitor_.max_stream_id_frame_.max_stream_id);
+
+ CheckFramingBoundaries(packet99, QUIC_MAX_STREAM_ID_DATA);
+}
+
+// The following four tests ensure that the framer can deserialize a stream
+// count that is large enough to cause the resulting stream ID to exceed the
+// current implementation limit(32 bits). The intent is that when this happens,
+// the stream limit is pegged to the maximum supported value. There are four
+// tests, for the four combinations of uni- and bi-directional, server- and
+// client- initiated.
+TEST_P(QuicFramerTest, ServerBiDiMaxStreamsFrameTooBig) {
+ // This test only for version 99.
+ if (framer_.transport_version() != QUIC_VERSION_99) {
+ return;
+ }
// clang-format off
unsigned char packet99[] = {
@@ -11306,24 +10221,206 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x12, 0x34, 0x56, 0x78,
-
- // frame type (IETF_MAX_STREAM_ID frame)
+ 0x12, 0x34, 0x9A, 0xBC,
+ // frame type (IETF_MAX_STREAMS_BIDIRECTIONAL)
0x12,
- // Max stream id
- kVarInt62OneByte + 0x01
+
+ // max. streams. Max stream ID allowed is 0xffffffff
+ // This encodes a count of 0x40000000, leading to stream
+ // IDs in the range 0x1 00000000 to 0x1 00000003.
+ kVarInt62EightBytes + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00
};
// clang-format on
- std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
- ASSERT_TRUE(data != nullptr);
+ QuicEncryptedPacket encrypted(AsChars(packet99), QUIC_ARRAYSIZE(packet99),
+ false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(
+ encrypted, !kIncludeVersion, !kIncludeDiversificationNonce,
+ PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID));
- test::CompareCharArraysWithHexError("constructed packet", data->data(),
- data->length(), AsChars(packet99),
- QUIC_ARRAYSIZE(packet99));
+ // This test is a server receiving a MAX_STREAMS frame. The
+ // stream ID that it generates should be a server-initiated
+ // stream ID. The expected Stream ID is
+ // 0xfffffffc | 0x01 --> 0xfffffffd
+ // maxid server inited, bidi
+ EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER,
+ /*bidirectional=*/true, 0x40000000),
+ visitor_.max_stream_id_frame_.max_stream_id);
}
-TEST_P(QuicFramerTest, StreamIdBlockedFrame) {
+TEST_P(QuicFramerTest, ClientBiDiMaxStreamsFrameTooBig) {
+ // This test only for version 99.
+ if (framer_.transport_version() != QUIC_VERSION_99) {
+ return;
+ }
+
+ // clang-format off
+ unsigned char packet99[] = {
+ // type (short header, 4 byte packet number)
+ 0x43,
+ // Test runs in client mode, no connection id
+ // packet number
+ 0x12, 0x34, 0x9A, 0xBC,
+ // frame type (IETF_MAX_STREAMS_BIDIRECTIONAL)
+ 0x12,
+
+ // max. streams. Max stream ID allowed is 0xffffffff
+ // This encodes a count of 0x40000000, leading to stream
+ // IDs in the range 0x1 00000000 to 0x1 00000003.
+ kVarInt62EightBytes + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(AsChars(packet99), QUIC_ARRAYSIZE(packet99),
+ false);
+ QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(
+ encrypted, !kIncludeVersion, !kIncludeDiversificationNonce,
+ PACKET_0BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID));
+
+ // This test is a client receiving a MAX_STREAMS frame. The
+ // stream ID that it generates should be a client-initiated
+ // stream ID. The expected Stream ID is
+ // 0xfffffffc --> 0xfffffffc
+ // max id bidi/client-inited
+ // TODO(fkastenholz): Change -2 to -1 when stream id 0 is no longer
+ // special.
+ // Subtract 1 because client/bidi stream ids start counting at
+ // 4, not 0. If we didn;t subtract 1, the resulting math would wrap to stream
+ // id 0, not 0xfffffffc.
+ EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT,
+ /*bidirectional=*/true, (0x40000000 - 1)),
+ visitor_.max_stream_id_frame_.max_stream_id);
+}
+
+TEST_P(QuicFramerTest, ServerUniDiMaxStreamsFrameTooBig) {
+ // This test only for version 99.
+ if (framer_.transport_version() != QUIC_VERSION_99) {
+ return;
+ }
+
+ // clang-format off
+ unsigned char packet99[] = {
+ // type (short header, 4 byte packet number)
+ 0x43,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x9A, 0xBC,
+ // frame type (IETF_MAX_STREAMS_UNIDIRECTIONAL)
+ 0x13,
+
+ // max. streams. Max stream ID allowed is 0xffffffff
+ // This encodes a count of 0x40000000, leading to stream
+ // IDs in the range 0x1 00000000 to 0x1 00000003.
+ kVarInt62EightBytes + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(AsChars(packet99), QUIC_ARRAYSIZE(packet99),
+ false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(
+ encrypted, !kIncludeVersion, !kIncludeDiversificationNonce,
+ PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID));
+
+ // This test is a server receiving a MAX_STREAMS frame. The
+ // stream ID that it generates should be a server-initiated
+ // stream ID. The expected Stream ID is
+ // 0xfffffffc | 0x1 | 0x2 = 0xffffffff
+ // maxid server inited, unidi
+ EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER,
+ /*bidirectional=*/false, 0x40000000),
+ visitor_.max_stream_id_frame_.max_stream_id);
+}
+
+TEST_P(QuicFramerTest, ClientUniDiMaxStreamsFrameTooBig) {
+ // This test only for version 99.
+ if (framer_.transport_version() != QUIC_VERSION_99) {
+ return;
+ }
+
+ // clang-format off
+ unsigned char packet99[] = {
+ // type (short header, 4 byte packet number)
+ 0x43,
+ // Test runs in client mode, no connection id
+ // packet number
+ 0x12, 0x34, 0x9A, 0xBC,
+ // frame type (IETF_MAX_STREAMS_UNDIRECTIONAL)
+ 0x13,
+
+ // max. streams. Max stream ID allowed is 0xffffffff
+ // This encodes a count of 0x40000000, leading to stream
+ // IDs in the range 0x1 00000000 to 0x1 00000003.
+ kVarInt62EightBytes + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(AsChars(packet99), QUIC_ARRAYSIZE(packet99),
+ false);
+ QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(
+ encrypted, !kIncludeVersion, !kIncludeDiversificationNonce,
+ PACKET_0BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID));
+
+ // This test is a client receiving a MAX_STREAMS frame. The
+ // stream ID that it generates should be a client-initiated
+ // stream ID. The expected Stream ID is
+ // 0xfffffffc | 0x02= 0xfffffffe
+ // maxid client/unidi
+ EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT,
+ /*bidirectional=*/false, 0x40000000),
+ visitor_.max_stream_id_frame_.max_stream_id);
+}
+
+// Check that a stream count of 0 is rejected.
+// Directionality and intiation are not important for
+// this test.
+TEST_P(QuicFramerTest, MaxStreamsFrameZeroCount) {
+ // This test only for version 99.
+ if (framer_.transport_version() != QUIC_VERSION_99) {
+ return;
+ }
+
+ // clang-format off
+ unsigned char packet99[] = {
+ // type (short header, 4 byte packet number)
+ 0x43,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x9A, 0xBC,
+ // frame type (IETF_MAX_STREAMS_BIDIRECTIONAL)
+ 0x12,
+ // max. streams == 0.
+ kVarInt62OneByte + 0x00
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(AsChars(packet99), QUIC_ARRAYSIZE(packet99),
+ false);
+ EXPECT_FALSE(framer_.ProcessPacket(encrypted));
+ EXPECT_EQ(QUIC_MAX_STREAM_ID_DATA, framer_.error());
+ EXPECT_EQ(framer_.detailed_error(),
+ "MAX_STREAMS stream count of 0 not supported.");
+}
+
+TEST_P(QuicFramerTest, ServerBiDiStreamsBlockedFrame) {
// This test only for version 99.
if (framer_.transport_version() != QUIC_VERSION_99) {
return;
@@ -11340,12 +10437,12 @@
// packet number
{"",
{0x12, 0x34, 0x9A, 0xBC}},
- // frame type (IETF_STREAM_ID_BLOCKED frame)
+ // frame type (IETF_STREAMS_BLOCKED_BIDIRECTIONAL frame)
{"",
{0x16}},
// stream id
- {"Can not read STREAM_ID_BLOCKED stream id.",
- {kVarInt62OneByte + 0x01}},
+ {"Can not read STREAMS_BLOCKED stream id.",
+ {kVarInt62OneByte + 0x03}},
};
// clang-format on
@@ -11359,12 +10456,234 @@
*encrypted, !kIncludeVersion, !kIncludeDiversificationNonce,
PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID));
- EXPECT_EQ(0x1u, visitor_.stream_id_blocked_frame_.stream_id);
+ // This test is a server receiving a STREAMS_BLOCKED frame. The
+ // stream ID that it generates should be a client-initiated
+ // stream ID. The expected Stream ID is
+ // ((0x3-1) * 4) = 0xc
+ // count-to-id client inited, bidi
+ // It is not 8 because a client-initiated, bidi stream ID's
+ // low bits are 00 - which means that the old crypto stream
+ // falls into this category, and the first stream is streamid=4,
+ // not streamid=0.
+ EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT,
+ /*bidirectional=*/true, 3),
+ visitor_.stream_id_blocked_frame_.stream_id);
CheckFramingBoundaries(packet99, QUIC_STREAM_ID_BLOCKED_DATA);
}
-TEST_P(QuicFramerTest, BuildStreamIdBlockedPacket) {
+TEST_P(QuicFramerTest, ClientBiDiStreamsBlockedFrame) {
+ // This test only for version 99.
+ if (framer_.transport_version() != QUIC_VERSION_99) {
+ return;
+ }
+
+ // clang-format off
+ PacketFragments packet99 = {
+ // type (short header, 4 byte packet number)
+ {"",
+ {0x43}},
+ // Test runs in client mode, no connection id
+ // packet number
+ {"",
+ {0x12, 0x34, 0x9A, 0xBC}},
+ // frame type (IETF_STREAMS_BLOCKED_BIDIRECTIONAL frame)
+ {"",
+ {0x16}},
+ // stream id
+ {"Can not read STREAMS_BLOCKED stream id.",
+ {kVarInt62OneByte + 0x03}},
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicEncryptedPacket> encrypted(
+ AssemblePacketFromFragments(packet99));
+ QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
+ EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(
+ *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce,
+ PACKET_0BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID));
+
+ // This test is a client receiving a STREAMS_BLOCKED frame. The
+ // stream ID that it generates should be a server-initiated
+ // stream ID. The expected Stream ID is
+ // ((0x3-1) * 4) | 0x01 = 0x9
+ // count-to-id server inited, bidi
+ EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER,
+ /*bidirectional=*/true, 3),
+ visitor_.stream_id_blocked_frame_.stream_id);
+
+ CheckFramingBoundaries(packet99, QUIC_STREAM_ID_BLOCKED_DATA);
+}
+
+TEST_P(QuicFramerTest, ServerUniDiStreamsBlockedFrame) {
+ // This test only for version 99.
+ if (framer_.transport_version() != QUIC_VERSION_99) {
+ return;
+ }
+
+ // clang-format off
+ PacketFragments packet99 = {
+ // type (short header, 4 byte packet number)
+ {"",
+ {0x43}},
+ // connection_id
+ {"",
+ {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+ // packet number
+ {"",
+ {0x12, 0x34, 0x9A, 0xBC}},
+ // frame type (IETF_STREAMS_BLOCKED_UNIDIRECTIONAL frame)
+ {"",
+ {0x17}},
+ // stream id
+ {"Can not read STREAMS_BLOCKED stream id.",
+ {kVarInt62OneByte + 0x03}},
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicEncryptedPacket> encrypted(
+ AssemblePacketFromFragments(packet99));
+ EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(
+ *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce,
+ PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID));
+
+ // This test is a server receiving a STREAMS_BLOCKED frame. The
+ // stream ID that it generates should be a client-initiated
+ // stream ID. The expected Stream ID is
+ // ((0x3-1) * 4) | 0x2 = 0xa
+ // count-to-id client inited, unidi
+ EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT,
+ /*bidirectional=*/false, 3),
+ visitor_.stream_id_blocked_frame_.stream_id);
+
+ CheckFramingBoundaries(packet99, QUIC_STREAM_ID_BLOCKED_DATA);
+}
+
+TEST_P(QuicFramerTest, ClientUniDiStreamsBlockedFrame) {
+ // This test only for version 99.
+ if (framer_.transport_version() != QUIC_VERSION_99) {
+ return;
+ }
+
+ // clang-format off
+ PacketFragments packet99 = {
+ // type (short header, 4 byte packet number)
+ {"",
+ {0x43}},
+ // Test runs in client mode, no connection id
+ // packet number
+ {"",
+ {0x12, 0x34, 0x9A, 0xBC}},
+ // frame type (IETF_STREAMS_BLOCKED_UNIDIRECTIONAL frame)
+ {"",
+ {0x17}},
+ // stream id
+ {"Can not read STREAMS_BLOCKED stream id.",
+ {kVarInt62OneByte + 0x03}},
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicEncryptedPacket> encrypted(
+ AssemblePacketFromFragments(packet99));
+ QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
+ EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(
+ *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce,
+ PACKET_0BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID));
+
+ // This test is a client receiving a STREAMS_BLOCKED frame. The
+ // stream ID that it generates should be a server-initiated
+ // stream ID. The expected Stream ID is
+ // ((0x3-1) * 4) | 0x01 | 0x2 = 0xb
+ // count-to-id server inited, bidi
+ EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER,
+ /*bidirectional=*/false, 3),
+ visitor_.stream_id_blocked_frame_.stream_id);
+
+ CheckFramingBoundaries(packet99, QUIC_STREAM_ID_BLOCKED_DATA);
+}
+
+// Check that when we get a STREAMS_BLOCKED frame that specifies too large
+// a stream count, we reject with an appropriate error. There is no need to
+// check for different combinations of Uni/Bi directional and client/server
+// initiated; the logic does not take these into account.
+TEST_P(QuicFramerTest, StreamsBlockedFrameTooBig) {
+ // This test only for version 99.
+ if (framer_.transport_version() != QUIC_VERSION_99) {
+ return;
+ }
+
+ // clang-format off
+ unsigned char packet99[] = {
+ // type (short header, 4 byte packet number)
+ 0x43,
+ // Test runs in client mode, no connection id
+ // packet number
+ 0x12, 0x34, 0x9A, 0xBC,
+ // frame type (IETF_STREAMS_BLOCKED_BIDIRECTIONAL)
+ 0x17,
+
+ // max. streams. Max stream ID allowed is 0xffffffff
+ // This encodes a count of 0x40000000, leading to stream
+ // IDs in the range 0x1 00000000 to 0x1 00000003.
+ kVarInt62EightBytes + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x01
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(AsChars(packet99), QUIC_ARRAYSIZE(packet99),
+ false);
+ QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
+ EXPECT_FALSE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_STREAM_ID_BLOCKED_DATA, framer_.error());
+ EXPECT_EQ(framer_.detailed_error(),
+ "STREAMS_BLOCKED stream count exceeds implementation limit.");
+}
+
+// Test that count==0 is rejected.
+TEST_P(QuicFramerTest, StreamsBlockedFrameZeroCount) {
+ // This test only for version 99.
+ if (framer_.transport_version() != QUIC_VERSION_99) {
+ return;
+ }
+
+ // clang-format off
+ unsigned char packet99[] = {
+ // type (short header, 4 byte packet number)
+ 0x43,
+ // Test runs in client mode, no connection id
+ // packet number
+ 0x12, 0x34, 0x9A, 0xBC,
+ // frame type (IETF_STREAMS_BLOCKED_BIDIRECTIONAL)
+ 0x17,
+
+ // max. streams = 0
+ kVarInt62OneByte + 0x00
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(AsChars(packet99), QUIC_ARRAYSIZE(packet99),
+ false);
+ QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
+ EXPECT_FALSE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_STREAM_ID_BLOCKED_DATA, framer_.error());
+ EXPECT_EQ(framer_.detailed_error(),
+ "STREAMS_BLOCKED stream count 0 not supported.");
+}
+
+TEST_P(QuicFramerTest, BuildServerBiDiStreamsBlockedPacket) {
// This test only for version 99.
if (framer_.transport_version() != QUIC_VERSION_99) {
return;
@@ -11377,7 +10696,13 @@
header.packet_number = kPacketNumber;
QuicStreamIdBlockedFrame frame;
- frame.stream_id = kTestQuicStreamId;
+ // A server building a STREAMS_BLOCKED frame generates
+ // a server-initiated stream ID. This test is bidirectional.
+ // The low two bits of the stream ID are 01
+ // Expected value is 0x8u | 0x1u;
+ frame.stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER,
+ /*bidirectional=*/true, 3);
+
QuicFrames frames = {QuicFrame(frame)};
// clang-format off
@@ -11389,10 +10714,332 @@
// packet number
0x12, 0x34, 0x56, 0x78,
- // frame type (IETF_STREAM_ID_BLOCKED frame)
+ // frame type (IETF_STREAMS_BLOCKED_BIDIRECTIONAL frame)
0x16,
- // Max stream id
- kVarInt62OneByte + 0x01
+ // Stream count
+ kVarInt62OneByte + 0x03
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(packet99),
+ QUIC_ARRAYSIZE(packet99));
+}
+
+TEST_P(QuicFramerTest, BuildClientBiDiStreamsBlockedPacket) {
+ // This test only for version 99.
+ if (framer_.transport_version() != QUIC_VERSION_99) {
+ return;
+ }
+
+ // This test runs in client mode.
+ QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
+
+ QuicPacketHeader header;
+ header.destination_connection_id = FramerTestConnectionId();
+ header.reset_flag = false;
+ header.version_flag = false;
+ header.packet_number = kPacketNumber;
+
+ QuicStreamIdBlockedFrame frame;
+ // A client building a STREAMS_BLOCKED frame generates
+ // a client-initiated stream ID. This test is bidirectional.
+ // The low two bits of the stream ID are 00. Expected value is 0x8
+ frame.stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT,
+ /*bidirectional=*/true, 3);
+ QuicFrames frames = {QuicFrame(frame)};
+
+ // clang-format off
+ unsigned char packet99[] = {
+ // type (short header, 4 byte packet number)
+ 0x43,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+
+ // frame type (IETF_STREAMS_BLOCKED_BIDIRECTIONAL frame)
+ 0x16,
+ // Stream count
+ kVarInt62OneByte + 0x03
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(packet99),
+ QUIC_ARRAYSIZE(packet99));
+}
+
+TEST_P(QuicFramerTest, BuildServerUniStreamsBlockedPacket) {
+ // This test only for version 99.
+ if (framer_.transport_version() != QUIC_VERSION_99) {
+ return;
+ }
+
+ QuicPacketHeader header;
+ header.destination_connection_id = FramerTestConnectionId();
+ header.reset_flag = false;
+ header.version_flag = false;
+ header.packet_number = kPacketNumber;
+
+ QuicStreamIdBlockedFrame frame;
+ // A server building a STREAMS_BLOCKED frame generates
+ // a server-initiated stream ID. This test is bidirectional.
+ // The low two bits of the stream ID are 11. Expected value is 0xb
+ frame.stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER,
+ /*bidirectional=*/false, 3);
+ QuicFrames frames = {QuicFrame(frame)};
+
+ // clang-format off
+ unsigned char packet99[] = {
+ // type (short header, 4 byte packet number)
+ 0x43,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+
+ // frame type (IETF_STREAMS_BLOCKED_UNIDIRECTIONAL frame)
+ 0x17,
+ // Stream count
+ kVarInt62OneByte + 0x03
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(packet99),
+ QUIC_ARRAYSIZE(packet99));
+}
+
+TEST_P(QuicFramerTest, BuildClientUniDiStreamsBlockedPacket) {
+ // This test only for version 99.
+ if (framer_.transport_version() != QUIC_VERSION_99) {
+ return;
+ }
+
+ // This test runs in client mode.
+ QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
+
+ QuicPacketHeader header;
+ header.destination_connection_id = FramerTestConnectionId();
+ header.reset_flag = false;
+ header.version_flag = false;
+ header.packet_number = kPacketNumber;
+
+ QuicStreamIdBlockedFrame frame;
+ // A client building a STREAMS_BLOCKED frame generates
+ // a client-initiated stream ID. This test is bidirectional.
+ // The low two bits of the stream ID are 10. Expected value is 0xa
+ frame.stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT,
+ /*bidirectional=*/false, 3);
+ QuicFrames frames = {QuicFrame(frame)};
+
+ // clang-format off
+ unsigned char packet99[] = {
+ // type (short header, 4 byte packet number)
+ 0x43,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+
+ // frame type (IETF_STREAMS_BLOCKED_UNIDIRECTIONAL frame)
+ 0x17,
+ // Stream count
+ kVarInt62OneByte + 0x03
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(packet99),
+ QUIC_ARRAYSIZE(packet99));
+}
+
+TEST_P(QuicFramerTest, BuildServerBiDiMaxStreamsPacket) {
+ // This test only for version 99.
+ if (framer_.transport_version() != QUIC_VERSION_99) {
+ return;
+ }
+
+ QuicPacketHeader header;
+ header.destination_connection_id = FramerTestConnectionId();
+ header.reset_flag = false;
+ header.version_flag = false;
+ header.packet_number = kPacketNumber;
+
+ QuicMaxStreamIdFrame frame;
+ // A server building a MAX_STREAMS frame generates
+ // a client-initiated stream ID. This test is bidirectional.
+ // The low two bits of the stream ID are 00. Expected value is 0xc
+ // because streamid==0 is special and the first client/bidi
+ // stream is 4, not 0.
+ frame.max_stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT,
+ /*bidirectional=*/true, 3);
+ QuicFrames frames = {QuicFrame(frame)};
+
+ // clang-format off
+ unsigned char packet99[] = {
+ // type (short header, 4 byte packet number)
+ 0x43,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+
+ // frame type (IETF_MAX_STREAMS_BIDIRECTIONAL frame)
+ 0x12,
+ // Stream count
+ kVarInt62OneByte + 0x03
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(packet99),
+ QUIC_ARRAYSIZE(packet99));
+}
+
+TEST_P(QuicFramerTest, BuildClientBiDiMaxStreamsPacket) {
+ // This test only for version 99.
+ if (framer_.transport_version() != QUIC_VERSION_99) {
+ return;
+ }
+
+ // This test runs in client mode.
+ QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
+
+ QuicPacketHeader header;
+ header.destination_connection_id = FramerTestConnectionId();
+ header.reset_flag = false;
+ header.version_flag = false;
+ header.packet_number = kPacketNumber;
+
+ QuicMaxStreamIdFrame frame;
+ // A client building a MAX_STREAMS frame generates
+ // a server-initiated stream ID. This test is bidirectional.
+ // The low two bits of the stream ID are 01. Expected value is 0x9
+ frame.max_stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER,
+ /*bidirectional=*/true, 3);
+ QuicFrames frames = {QuicFrame(frame)};
+
+ // clang-format off
+ unsigned char packet99[] = {
+ // type (short header, 4 byte packet number)
+ 0x43,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+
+ // frame type (IETF_MAX_STREAMS_BIDIRECTIONAL frame)
+ 0x12,
+ // Stream count
+ kVarInt62OneByte + 0x03
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(packet99),
+ QUIC_ARRAYSIZE(packet99));
+}
+
+TEST_P(QuicFramerTest, BuildServerUniMaxStreamsPacket) {
+ // This test only for version 99.
+ if (framer_.transport_version() != QUIC_VERSION_99) {
+ return;
+ }
+
+ QuicPacketHeader header;
+ header.destination_connection_id = FramerTestConnectionId();
+ header.reset_flag = false;
+ header.version_flag = false;
+ header.packet_number = kPacketNumber;
+
+ QuicMaxStreamIdFrame frame;
+ // A server building a MAX_STREAMS frame generates
+ // a client-initiated stream ID. This test is bidirectional.
+ // The low two bits of the stream ID are 10. Expected value is 0xa
+ frame.max_stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT,
+ /*bidirectional=*/false, 3);
+ QuicFrames frames = {QuicFrame(frame)};
+
+ // clang-format off
+ unsigned char packet99[] = {
+ // type (short header, 4 byte packet number)
+ 0x43,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+
+ // frame type (IETF_MAX_STREAMS_UNIDIRECTIONAL frame)
+ 0x13,
+ // Stream count
+ kVarInt62OneByte + 0x03
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(packet99),
+ QUIC_ARRAYSIZE(packet99));
+}
+
+TEST_P(QuicFramerTest, BuildClientUniDiMaxStreamsPacket) {
+ // This test only for version 99.
+ if (framer_.transport_version() != QUIC_VERSION_99) {
+ return;
+ }
+
+ // This test runs in client mode.
+ QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
+
+ QuicPacketHeader header;
+ header.destination_connection_id = FramerTestConnectionId();
+ header.reset_flag = false;
+ header.version_flag = false;
+ header.packet_number = kPacketNumber;
+
+ QuicMaxStreamIdFrame frame;
+ // A client building a MAX_STREAMS frame generates
+ // a server-initiated stream ID. This test is bidirectional.
+ // The low two bits of the stream ID are 11. Expected value is 0xb
+ frame.max_stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER,
+ /*bidirectional=*/false, 3);
+ QuicFrames frames = {QuicFrame(frame)};
+
+ // clang-format off
+ unsigned char packet99[] = {
+ // type (short header, 4 byte packet number)
+ 0x43,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+
+ // frame type (IETF_MAX_STREAMS_UNIDIRECTIONAL frame)
+ 0x13,
+ // Stream count
+ kVarInt62OneByte + 0x03
};
// clang-format on
@@ -11901,14 +11548,14 @@
framer_.transport_version(), QuicFrame(&new_connection_id)));
QuicMaxStreamIdFrame max_stream_id(6, 3);
- EXPECT_EQ(QuicFramer::GetMaxStreamIdFrameSize(framer_.transport_version(),
- max_stream_id),
+ EXPECT_EQ(QuicFramer::GetMaxStreamsFrameSize(framer_.transport_version(),
+ max_stream_id),
QuicFramer::GetRetransmittableControlFrameSize(
framer_.transport_version(), QuicFrame(max_stream_id)));
QuicStreamIdBlockedFrame stream_id_blocked(7, 3);
- EXPECT_EQ(QuicFramer::GetStreamIdBlockedFrameSize(framer_.transport_version(),
- stream_id_blocked),
+ EXPECT_EQ(QuicFramer::GetStreamsBlockedFrameSize(framer_.transport_version(),
+ stream_id_blocked),
QuicFramer::GetRetransmittableControlFrameSize(
framer_.transport_version(), QuicFrame(stream_id_blocked)));
@@ -12658,26 +12305,6 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // frame type (ack frame)
- 0x45,
- // largest observed
- 0x00, 0x00,
- // Zero delta time.
- 0x00, 0x00,
- // first ack block length.
- 0x00, 0x00,
- // num timestamps.
- 0x00
- };
-
- unsigned char packet39[] = {
- // public flags (8 byte connection_id)
- 0x2C,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
0x12, 0x34, 0x56, 0x78,
// frame type (ack frame)
@@ -12712,7 +12339,7 @@
0x00
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -12758,21 +12385,14 @@
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
+ } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
p_size = QUIC_ARRAYSIZE(packet44);
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
}
QuicEncryptedPacket encrypted(AsChars(p), p_size, false);
- if (!GetQuicReloadableFlag(quic_disallow_peer_ack_0) &&
- framer_.transport_version() != QUIC_VERSION_99) {
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
- return;
- }
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(framer_.detailed_error(), "Largest acked is 0.");
}
@@ -12785,26 +12405,6 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // frame type (ack frame)
- 0x45,
- // largest observed
- 0x02, 0x00,
- // Zero delta time.
- 0x00, 0x00,
- // first ack block length.
- 0x03, 0x00,
- // num timestamps.
- 0x00
- };
-
- unsigned char packet39[] = {
- // public flags (8 byte connection_id)
- 0x2C,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
0x12, 0x34, 0x56, 0x78,
// frame type (ack frame)
@@ -12839,7 +12439,7 @@
0x00
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -12885,22 +12485,15 @@
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
- p_size = QUIC_ARRAYSIZE(packet47);
+ } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
+ p_size = QUIC_ARRAYSIZE(packet46);
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
p_size = QUIC_ARRAYSIZE(packet44);
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
}
QuicEncryptedPacket encrypted(AsChars(p), p_size, false);
- if (!GetQuicReloadableFlag(quic_disallow_peer_ack_0) &&
- framer_.transport_version() != QUIC_VERSION_99) {
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
- return;
- }
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(framer_.detailed_error(),
"Underflow with first ack block length 3 largest acked is 2.");
@@ -12914,36 +12507,6 @@
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
- 0x78, 0x56, 0x34, 0x12,
-
- // frame type (ack frame)
- 0x60,
- // largest observed
- 0x0A,
- // Zero delta time.
- 0x00, 0x00,
- // Num of ack blocks
- 0x02,
- // first ack block length.
- 0x02,
- // gap to next block
- 0x01,
- // ack block length
- 0x01,
- // gap to next block
- 0x01,
- // ack block length
- 0x06,
- // num timestamps.
- 0x00
- };
-
- unsigned char packet39[] = {
- // public flags (8 byte connection_id)
- 0x2C,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
0x12, 0x34, 0x56, 0x78,
// frame type (ack frame)
@@ -12998,7 +12561,7 @@
0x00
};
- unsigned char packet47[] = {
+ unsigned char packet46[] = {
// type (short header, 4 byte packet number)
0x43,
// connection_id
@@ -13062,22 +12625,15 @@
if (framer_.transport_version() == QUIC_VERSION_99) {
p = packet99;
p_size = QUIC_ARRAYSIZE(packet99);
- } else if (framer_.transport_version() > QUIC_VERSION_46) {
- p = packet47;
- p_size = QUIC_ARRAYSIZE(packet47);
+ } else if (framer_.transport_version() > QUIC_VERSION_44) {
+ p = packet46;
+ p_size = QUIC_ARRAYSIZE(packet46);
} else if (framer_.transport_version() > QUIC_VERSION_43) {
p = packet44;
p_size = QUIC_ARRAYSIZE(packet44);
- } else if (framer_.transport_version() != QUIC_VERSION_35) {
- p = packet39;
}
QuicEncryptedPacket encrypted(AsChars(p), p_size, false);
- if (!GetQuicReloadableFlag(quic_disallow_peer_ack_0) &&
- framer_.transport_version() != QUIC_VERSION_99) {
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
- return;
- }
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
if (framer_.transport_version() == QUIC_VERSION_99) {
EXPECT_EQ(framer_.detailed_error(),
@@ -13088,6 +12644,242 @@
}
}
+TEST_P(QuicFramerTest, CoalescedPacket) {
+ if (!QuicVersionHasLongHeaderLengths(framer_.transport_version())) {
+ return;
+ }
+ // clang-format off
+ unsigned char packet[] = {
+ // first coalesced packet
+ // public flags (long header with packet type ZERO_RTT_PROTECTED and
+ // 4-byte packet number)
+ 0xD3,
+ // version
+ QUIC_VERSION_BYTES,
+ // destination connection ID length
+ 0x50,
+ // destination connection ID
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // long header packet length
+ 0x1E,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+ // frame type (IETF_STREAM frame with FIN, LEN, and OFFSET bits set)
+ 0x08 | 0x01 | 0x02 | 0x04,
+ // stream id
+ kVarInt62FourBytes + 0x00, 0x02, 0x03, 0x04,
+ // offset
+ kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC,
+ 0x32, 0x10, 0x76, 0x54,
+ // data length
+ kVarInt62OneByte + 0x0c,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ // second coalesced packet
+ // public flags (long header with packet type ZERO_RTT_PROTECTED and
+ // 4-byte packet number)
+ 0xD3,
+ // version
+ QUIC_VERSION_BYTES,
+ // destination connection ID length
+ 0x50,
+ // destination connection ID
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // long header packet length
+ 0x1E,
+ // packet number
+ 0x12, 0x34, 0x56, 0x79,
+ // frame type (IETF_STREAM frame with FIN, LEN, and OFFSET bits set)
+ 0x08 | 0x01 | 0x02 | 0x04,
+ // stream id
+ kVarInt62FourBytes + 0x00, 0x02, 0x03, 0x04,
+ // offset
+ kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC,
+ 0x32, 0x10, 0x76, 0x54,
+ // data length
+ kVarInt62OneByte + 0x0c,
+ // data
+ 'H', 'E', 'L', 'L',
+ 'O', '_', 'W', 'O',
+ 'R', 'L', 'D', '?',
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+
+ ASSERT_EQ(1u, visitor_.stream_frames_.size());
+ EXPECT_EQ(0u, visitor_.ack_frames_.size());
+
+ // Stream ID should be the last 3 bytes of kStreamId.
+ EXPECT_EQ(0x00FFFFFF & kStreamId, visitor_.stream_frames_[0]->stream_id);
+ EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
+ EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset);
+ CheckStreamFrameData("hello world!", visitor_.stream_frames_[0].get());
+
+ ASSERT_EQ(visitor_.coalesced_packets_.size(), 1);
+ EXPECT_TRUE(framer_.ProcessPacket(*visitor_.coalesced_packets_[0].get()));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+
+ ASSERT_EQ(2u, visitor_.stream_frames_.size());
+ EXPECT_EQ(0u, visitor_.ack_frames_.size());
+
+ // Stream ID should be the last 3 bytes of kStreamId.
+ EXPECT_EQ(0x00FFFFFF & kStreamId, visitor_.stream_frames_[1]->stream_id);
+ EXPECT_TRUE(visitor_.stream_frames_[1]->fin);
+ EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[1]->offset);
+ CheckStreamFrameData("HELLO_WORLD?", visitor_.stream_frames_[1].get());
+}
+
+TEST_P(QuicFramerTest, MismatchedCoalescedPacket) {
+ if (!QuicVersionHasLongHeaderLengths(framer_.transport_version())) {
+ return;
+ }
+ // clang-format off
+ unsigned char packet[] = {
+ // first coalesced packet
+ // public flags (long header with packet type ZERO_RTT_PROTECTED and
+ // 4-byte packet number)
+ 0xD3,
+ // version
+ QUIC_VERSION_BYTES,
+ // destination connection ID length
+ 0x50,
+ // destination connection ID
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // long header packet length
+ 0x1E,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+ // frame type (IETF_STREAM frame with FIN, LEN, and OFFSET bits set)
+ 0x08 | 0x01 | 0x02 | 0x04,
+ // stream id
+ kVarInt62FourBytes + 0x00, 0x02, 0x03, 0x04,
+ // offset
+ kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC,
+ 0x32, 0x10, 0x76, 0x54,
+ // data length
+ kVarInt62OneByte + 0x0c,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ // second coalesced packet
+ // public flags (long header with packet type ZERO_RTT_PROTECTED and
+ // 4-byte packet number)
+ 0xD3,
+ // version
+ QUIC_VERSION_BYTES,
+ // destination connection ID length
+ 0x50,
+ // destination connection ID
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x11,
+ // long header packet length
+ 0x1E,
+ // packet number
+ 0x12, 0x34, 0x56, 0x79,
+ // frame type (IETF_STREAM frame with FIN, LEN, and OFFSET bits set)
+ 0x08 | 0x01 | 0x02 | 0x04,
+ // stream id
+ kVarInt62FourBytes + 0x00, 0x02, 0x03, 0x04,
+ // offset
+ kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC,
+ 0x32, 0x10, 0x76, 0x54,
+ // data length
+ kVarInt62OneByte + 0x0c,
+ // data
+ 'H', 'E', 'L', 'L',
+ 'O', '_', 'W', 'O',
+ 'R', 'L', 'D', '?',
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false);
+ EXPECT_QUIC_PEER_BUG(EXPECT_TRUE(framer_.ProcessPacket(encrypted)),
+ "Server: Received mismatched coalesced header.*");
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+
+ ASSERT_EQ(1u, visitor_.stream_frames_.size());
+ EXPECT_EQ(0u, visitor_.ack_frames_.size());
+
+ // Stream ID should be the last 3 bytes of kStreamId.
+ EXPECT_EQ(0x00FFFFFF & kStreamId, visitor_.stream_frames_[0]->stream_id);
+ EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
+ EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset);
+ CheckStreamFrameData("hello world!", visitor_.stream_frames_[0].get());
+
+ ASSERT_EQ(visitor_.coalesced_packets_.size(), 0);
+}
+
+TEST_P(QuicFramerTest, InvalidCoalescedPacket) {
+ if (!QuicVersionHasLongHeaderLengths(framer_.transport_version())) {
+ return;
+ }
+ // clang-format off
+ unsigned char packet[] = {
+ // first coalesced packet
+ // public flags (long header with packet type ZERO_RTT_PROTECTED and
+ // 4-byte packet number)
+ 0xD3,
+ // version
+ QUIC_VERSION_BYTES,
+ // destination connection ID length
+ 0x50,
+ // destination connection ID
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // long header packet length
+ 0x1E,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+ // frame type (IETF_STREAM frame with FIN, LEN, and OFFSET bits set)
+ 0x08 | 0x01 | 0x02 | 0x04,
+ // stream id
+ kVarInt62FourBytes + 0x00, 0x02, 0x03, 0x04,
+ // offset
+ kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC,
+ 0x32, 0x10, 0x76, 0x54,
+ // data length
+ kVarInt62OneByte + 0x0c,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ // second coalesced packet
+ // public flags (long header with packet type ZERO_RTT_PROTECTED and
+ // 4-byte packet number)
+ 0xD3,
+ // version would be here but we cut off the invalid coalesced header.
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false);
+ EXPECT_QUIC_PEER_BUG(EXPECT_TRUE(framer_.ProcessPacket(encrypted)),
+ "Server: Failed to parse received coalesced header.*");
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+
+ ASSERT_EQ(1u, visitor_.stream_frames_.size());
+ EXPECT_EQ(0u, visitor_.ack_frames_.size());
+
+ // Stream ID should be the last 3 bytes of kStreamId.
+ EXPECT_EQ(0x00FFFFFF & kStreamId, visitor_.stream_frames_[0]->stream_id);
+ EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
+ EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset);
+ CheckStreamFrameData("hello world!", visitor_.stream_frames_[0].get());
+
+ ASSERT_EQ(visitor_.coalesced_packets_.size(), 0);
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/quic/core/quic_ietf_framer_test.cc b/quic/core/quic_ietf_framer_test.cc
index d35800a..100fe8d 100644
--- a/quic/core/quic_ietf_framer_test.cc
+++ b/quic/core/quic_ietf_framer_test.cc
@@ -45,9 +45,12 @@
namespace {
const size_t kNormalPacketBufferSize = 1400;
-// several different stream ids, should be encoded
+// Several different stream ids, should be encoded
// in 8, 4, 2, and 1 byte, respectively. Last one
// checks that value==0 works.
+// All stream IDs end in 0x0, so the client/server- initiated
+// and Uni/Bi-directional bits are available to alter, as any
+// given test may wish.
const QuicIetfStreamId kStreamId8 = UINT64_C(0x3EDCBA9876543210);
const QuicIetfStreamId kStreamId4 = UINT64_C(0x36543210);
const QuicIetfStreamId kStreamId2 = UINT64_C(0x3210);
@@ -110,6 +113,8 @@
bool OnPacketHeader(const QuicPacketHeader& header) override { return true; }
+ void OnCoalescedPacket(const QuicEncryptedPacket& packet) override {}
+
bool OnStreamFrame(const QuicStreamFrame& frame) override { return true; }
bool OnCryptoFrame(const QuicCryptoFrame& frame) override { return true; }
@@ -452,6 +457,129 @@
EXPECT_EQ(receive_frame.byte_offset, transmit_frame.byte_offset);
}
+ void TryMaxStreamsFrame(QuicStreamId stream_id,
+ bool unidirectional,
+ bool stream_id_server_initiated) {
+ if (!unidirectional && !stream_id_server_initiated && stream_id == 0) {
+ // For bidirectional, client initiated, streams, 0 is not allowed,
+ // it's used for the crypto stream and is not included in the counting.
+ return;
+ }
+
+ char packet_buffer[kNormalPacketBufferSize];
+ memset(packet_buffer, 0, sizeof(packet_buffer));
+
+ Perspective old_perspective = framer_.perspective();
+ // Set up the writer and transmit QuicMaxStreamIdFrame
+ QuicDataWriter writer(sizeof(packet_buffer), packet_buffer,
+ NETWORK_BYTE_ORDER);
+ if (stream_id_server_initiated) {
+ stream_id |= 0x01;
+ }
+ if (unidirectional) {
+ stream_id |= 0x02;
+ }
+
+ // Set the perspective of the sender. If the stream id is supposed to
+ // be server-initiated, then the sender of the MAX_STREAMS should be
+ // a client, and vice versa. Do this prior to constructing the frame or
+ // generating the packet, so that any internal dependencies are satisfied.
+ QuicFramerPeer::SetPerspective(&framer_, (stream_id_server_initiated)
+ ? Perspective::IS_CLIENT
+ : Perspective::IS_SERVER);
+ QuicMaxStreamIdFrame transmit_frame(0, stream_id);
+
+ // Add the frame.
+ EXPECT_TRUE(QuicFramerPeer::AppendMaxStreamsFrame(&framer_, transmit_frame,
+ &writer));
+
+ // Check that buffer length is in the expected range
+ EXPECT_LE(1u, writer.length());
+ EXPECT_GE(8u, writer.length());
+
+ // Set the perspective for the receiver.
+ QuicFramerPeer::SetPerspective(&framer_, (stream_id_server_initiated)
+ ? Perspective::IS_SERVER
+ : Perspective::IS_CLIENT);
+
+ // Set up reader and empty receive QuicPaddingFrame.
+ QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER);
+ QuicMaxStreamIdFrame receive_frame;
+
+ // Deframe it
+ EXPECT_TRUE(QuicFramerPeer::ProcessMaxStreamsFrame(
+ &framer_, &reader, &receive_frame,
+ (unidirectional) ? IETF_MAX_STREAMS_UNIDIRECTIONAL
+ : IETF_MAX_STREAMS_BIDIRECTIONAL))
+ << " Error: " << framer_.detailed_error();
+
+ // Now check that received and sent data are equivalent
+ EXPECT_EQ(stream_id, receive_frame.max_stream_id);
+ EXPECT_EQ(transmit_frame.max_stream_id, receive_frame.max_stream_id);
+ QuicFramerPeer::SetPerspective(&framer_, old_perspective);
+ }
+
+ void TryStreamsBlockedFrame(QuicStreamId stream_id,
+ bool unidirectional,
+ bool stream_id_server_initiated) {
+ if (!unidirectional && !stream_id_server_initiated && stream_id == 0) {
+ // For bidirectional, client initiated, streams, 0 is not allowed,
+ // it's used for the crypto stream and is not included in the counting.
+ return;
+ }
+
+ char packet_buffer[kNormalPacketBufferSize];
+ memset(packet_buffer, 0, sizeof(packet_buffer));
+
+ Perspective old_perspective = framer_.perspective();
+ // Set up the writer and transmit QuicMaxStreamIdFrame
+ QuicDataWriter writer(sizeof(packet_buffer), packet_buffer,
+ NETWORK_BYTE_ORDER);
+ if (stream_id_server_initiated) {
+ stream_id |= 0x01;
+ }
+ if (unidirectional) {
+ stream_id |= 0x02;
+ }
+
+ // Set the perspective of the sender. If the stream id is supposed to
+ // be server-initiated, then the sender of the MAX_STREAMS should be
+ // a client, and vice versa. Do this prior to constructing the frame or
+ // generating the packet, so that any internal dependencies are satisfied.
+ QuicFramerPeer::SetPerspective(&framer_, (stream_id_server_initiated)
+ ? Perspective::IS_SERVER
+ : Perspective::IS_CLIENT);
+ QuicStreamIdBlockedFrame transmit_frame(0, stream_id);
+
+ // Add the frame.
+ EXPECT_TRUE(QuicFramerPeer::AppendStreamsBlockedFrame(
+ &framer_, transmit_frame, &writer));
+
+ // Check that buffer length is in the expected range
+ EXPECT_LE(1u, writer.length());
+ EXPECT_GE(8u, writer.length());
+
+ // Set the perspective for the receiver.
+ QuicFramerPeer::SetPerspective(&framer_, (stream_id_server_initiated)
+ ? Perspective::IS_CLIENT
+ : Perspective::IS_SERVER);
+
+ // Set up reader and empty receive QuicPaddingFrame.
+ QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER);
+ QuicStreamIdBlockedFrame receive_frame;
+
+ // Deframe it
+ EXPECT_TRUE(QuicFramerPeer::ProcessStreamsBlockedFrame(
+ &framer_, &reader, &receive_frame,
+ (unidirectional) ? IETF_STREAMS_BLOCKED_UNIDIRECTIONAL
+ : IETF_STREAMS_BLOCKED_BIDIRECTIONAL));
+
+ // Now check that received and sent data are equivalent
+ EXPECT_EQ(stream_id, receive_frame.stream_id);
+ EXPECT_EQ(transmit_frame.stream_id, receive_frame.stream_id);
+ QuicFramerPeer::SetPerspective(&framer_, old_perspective);
+ }
+
QuicTime start_;
QuicFramer framer_;
test::TestQuicVisitor visitor_;
@@ -1082,7 +1210,8 @@
// Now check that the received data equals the sent data.
EXPECT_EQ(transmit_frame.byte_offset, window_size);
EXPECT_EQ(transmit_frame.byte_offset, receive_frame.byte_offset);
- EXPECT_EQ(0u, receive_frame.stream_id);
+ EXPECT_EQ(QuicUtils::GetInvalidStreamId(framer_.transport_version()),
+ receive_frame.stream_id);
}
}
@@ -1128,38 +1257,21 @@
}
}
-TEST_F(QuicIetfFramerTest, MaxStreamIdFrame) {
- char packet_buffer[kNormalPacketBufferSize];
+TEST_F(QuicIetfFramerTest, MaxStreamsFrame) {
QuicIetfStreamId stream_ids[] = {kStreamId4, kStreamId2, kStreamId1,
kStreamId0};
for (QuicIetfStreamId stream_id : stream_ids) {
- memset(packet_buffer, 0, sizeof(packet_buffer));
-
- // Set up the writer and transmit QuicMaxStreamIdFrame
- QuicDataWriter writer(sizeof(packet_buffer), packet_buffer,
- NETWORK_BYTE_ORDER);
- QuicMaxStreamIdFrame transmit_frame(0, stream_id);
-
- // Add the frame.
- EXPECT_TRUE(QuicFramerPeer::AppendMaxStreamIdFrame(&framer_, transmit_frame,
- &writer));
-
- // Check that buffer length is in the expected range
- EXPECT_LE(1u, writer.length());
- EXPECT_GE(8u, writer.length());
-
- // Set up reader and empty receive QuicPaddingFrame.
- QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER);
- QuicMaxStreamIdFrame receive_frame;
-
- // Deframe it
- EXPECT_TRUE(QuicFramerPeer::ProcessMaxStreamIdFrame(&framer_, &reader,
- &receive_frame));
-
- // Now check that received and sent data are equivalent
- EXPECT_EQ(stream_id, receive_frame.max_stream_id);
- EXPECT_EQ(transmit_frame.max_stream_id, receive_frame.max_stream_id);
+ // Cover all four combinations of uni/bi-directional and
+ // server-/client- initiation.
+ TryMaxStreamsFrame(stream_id, /*unidirectional=*/true,
+ /*stream_id_server_initiated=*/true);
+ TryMaxStreamsFrame(stream_id, /*unidirectional=*/true,
+ /*stream_id_server_initiated=*/false);
+ TryMaxStreamsFrame(stream_id, /*unidirectional=*/false,
+ /*stream_id_server_initiated=*/true);
+ TryMaxStreamsFrame(stream_id, /*unidirectional=*/false,
+ /*stream_id_server_initiated=*/false);
}
}
@@ -1174,7 +1286,8 @@
// Set up the writer and transmit QuicBlockedFrame
QuicDataWriter writer(sizeof(packet_buffer), packet_buffer,
NETWORK_BYTE_ORDER);
- QuicBlockedFrame transmit_frame(0, 0, offset);
+ QuicBlockedFrame transmit_frame(
+ 0, QuicUtils::GetInvalidStreamId(framer_.transport_version()), offset);
// Add the frame.
EXPECT_TRUE(QuicFramerPeer::AppendIetfBlockedFrame(&framer_, transmit_frame,
@@ -1193,7 +1306,8 @@
&receive_frame));
// Check that received and sent data are equivalent
- EXPECT_EQ(0u, receive_frame.stream_id);
+ EXPECT_EQ(QuicUtils::GetInvalidStreamId(framer_.transport_version()),
+ receive_frame.stream_id);
EXPECT_EQ(offset, receive_frame.offset);
EXPECT_EQ(transmit_frame.offset, receive_frame.offset);
}
@@ -1241,38 +1355,23 @@
}
}
-TEST_F(QuicIetfFramerTest, StreamIdBlockedFrame) {
- char packet_buffer[kNormalPacketBufferSize];
+TEST_F(QuicIetfFramerTest, StreamsBlockedFrame) {
QuicIetfStreamId stream_ids[] = {kStreamId4, kStreamId2, kStreamId1,
kStreamId0};
for (QuicIetfStreamId stream_id : stream_ids) {
- memset(packet_buffer, 0, sizeof(packet_buffer));
-
- // Set up the writer and transmit QuicStreamIdBlockedFrame
- QuicDataWriter writer(sizeof(packet_buffer), packet_buffer,
- NETWORK_BYTE_ORDER);
- QuicStreamIdBlockedFrame transmit_frame(0, stream_id);
-
- // Add the frame.
- EXPECT_TRUE(QuicFramerPeer::AppendStreamIdBlockedFrame(
- &framer_, transmit_frame, &writer));
-
- // Check that buffer length is in the expected range
- EXPECT_LE(1u, writer.length());
- EXPECT_GE(8u, writer.length());
-
- // Set up reader and empty receive QuicPaddingFrame.
- QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER);
- QuicStreamIdBlockedFrame receive_frame;
-
- // Deframe it
- EXPECT_TRUE(QuicFramerPeer::ProcessStreamIdBlockedFrame(&framer_, &reader,
- &receive_frame));
-
- // Now check that received == sent
- EXPECT_EQ(stream_id, receive_frame.stream_id);
- EXPECT_EQ(transmit_frame.stream_id, receive_frame.stream_id);
+ TryStreamsBlockedFrame(stream_id,
+ /*unidirectional=*/false,
+ /*stream_id_server_initiated=*/false);
+ TryStreamsBlockedFrame(stream_id,
+ /*unidirectional=*/false,
+ /*stream_id_server_initiated=*/true);
+ TryStreamsBlockedFrame(stream_id,
+ /*unidirectional=*/true,
+ /*stream_id_server_initiated=*/false);
+ TryStreamsBlockedFrame(stream_id,
+ /*unidirectional=*/true,
+ /*stream_id_server_initiated=*/true);
}
}
diff --git a/quic/core/quic_interval.h b/quic/core/quic_interval.h
new file mode 100644
index 0000000..d5bf171
--- /dev/null
+++ b/quic/core/quic_interval.h
@@ -0,0 +1,379 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_CORE_QUIC_INTERVAL_H_
+#define QUICHE_QUIC_CORE_QUIC_INTERVAL_H_
+
+// An QuicInterval<T> is a data structure used to represent a contiguous,
+// mutable range over an ordered type T. Supported operations include testing a
+// value to see whether it is included in the QuicInterval, comparing two
+// QuicIntervals, and performing their union, intersection, and difference. For
+// the purposes of this library, an "ordered type" is any type that induces a
+// total order on its values via its less-than operator (operator<()). Examples
+// of such types are basic arithmetic types like int and double as well as class
+// types like string.
+//
+// An QuicInterval<T> is represented using the usual C++ STL convention, namely
+// as the half-open QuicInterval [min, max). A point p is considered to be
+// contained in the QuicInterval iff p >= min && p < max. One consequence of
+// this definition is that for any non-empty QuicInterval, min is contained in
+// the QuicInterval but max is not. There is no canonical representation for the
+// empty QuicInterval; rather, any QuicInterval where max <= min is regarded as
+// empty. As a consequence, two empty QuicIntervals will still compare as equal
+// despite possibly having different underlying min() or max() values. Also
+// beware of the terminology used here: the library uses the terms "min" and
+// "max" rather than "begin" and "end" as is conventional for the STL.
+//
+// T is required to be default- and copy-constructable, to have an assignment
+// operator, and the full complement of comparison operators (<, <=, ==, !=, >=,
+// >). A difference operator (operator-()) is required if
+// QuicInterval<T>::Length is used.
+//
+// QuicInterval supports operator==. Two QuicIntervals are considered equal if
+// either they are both empty or if their corresponding min and max fields
+// compare equal. QuicInterval also provides an operator<. Unfortunately,
+// operator< is currently buggy because its behavior is inconsistent with
+// operator==: two empty ranges with different representations may be regarded
+// as equal by operator== but regarded as different by operator<. Bug 9240050
+// has been created to address this.
+//
+//
+// Examples:
+// QuicInterval<int> r1(0, 100); // The QuicInterval [0, 100).
+// EXPECT_TRUE(r1.Contains(0));
+// EXPECT_TRUE(r1.Contains(50));
+// EXPECT_FALSE(r1.Contains(100)); // 100 is just outside the QuicInterval.
+//
+// QuicInterval<int> r2(50, 150); // The QuicInterval [50, 150).
+// EXPECT_TRUE(r1.Intersects(r2));
+// EXPECT_FALSE(r1.Contains(r2));
+// EXPECT_TRUE(r1.IntersectWith(r2)); // Mutates r1.
+// EXPECT_EQ(QuicInterval<int>(50, 100), r1); // r1 is now [50, 100).
+//
+// QuicInterval<int> r3(1000, 2000); // The QuicInterval [1000, 2000).
+// EXPECT_TRUE(r1.IntersectWith(r3)); // Mutates r1.
+// EXPECT_TRUE(r1.Empty()); // Now r1 is empty.
+// EXPECT_FALSE(r1.Contains(r1.min())); // e.g. doesn't contain its own min.
+
+#include <stddef.h>
+#include <algorithm>
+#include <ostream>
+#include <string>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+namespace quic {
+
+template <typename T>
+class QuicInterval {
+ private:
+ // Type trait for deriving the return type for QuicInterval::Length. If
+ // operator-() is not defined for T, then the return type is void. This makes
+ // the signature for Length compile so that the class can be used for such T,
+ // but code that calls Length would still generate a compilation error.
+ template <typename U>
+ class DiffTypeOrVoid {
+ private:
+ template <typename V>
+ static auto f(const V* v) -> decltype(*v - *v);
+ template <typename V>
+ static void f(...);
+
+ public:
+ using type = typename std::decay<decltype(f<U>(nullptr))>::type;
+ };
+
+ public:
+ // Construct an QuicInterval representing an empty QuicInterval.
+ QuicInterval() : min_(), max_() {}
+
+ // Construct an QuicInterval representing the QuicInterval [min, max). If min
+ // < max, the constructed object will represent the non-empty QuicInterval
+ // containing all values from min up to (but not including) max. On the other
+ // hand, if min >= max, the constructed object will represent the empty
+ // QuicInterval.
+ QuicInterval(const T& min, const T& max) : min_(min), max_(max) {}
+
+ template <typename U1,
+ typename U2,
+ typename = typename std::enable_if<
+ std::is_convertible<U1, T>::value &&
+ std::is_convertible<U2, T>::value>::type>
+ QuicInterval(U1&& min, U2&& max)
+ : min_(std::forward<U1>(min)), max_(std::forward<U2>(max)) {}
+
+ const T& min() const { return min_; }
+ const T& max() const { return max_; }
+ void SetMin(const T& t) { min_ = t; }
+ void SetMax(const T& t) { max_ = t; }
+
+ void Set(const T& min, const T& max) {
+ SetMin(min);
+ SetMax(max);
+ }
+
+ void Clear() { *this = {}; }
+
+ bool Empty() const { return min() >= max(); }
+
+ // Returns the length of this QuicInterval. The value returned is zero if
+ // Empty() is true; otherwise the value returned is max() - min().
+ typename DiffTypeOrVoid<T>::type Length() const {
+ return (Empty() ? min() : max()) - min();
+ }
+
+ // Returns true iff t >= min() && t < max().
+ bool Contains(const T& t) const { return min() <= t && max() > t; }
+
+ // Returns true iff *this and i are non-empty, and *this includes i. "*this
+ // includes i" means that for all t, if i.Contains(t) then this->Contains(t).
+ // Note the unintuitive consequence of this definition: this method always
+ // returns false when i is the empty QuicInterval.
+ bool Contains(const QuicInterval& i) const {
+ return !Empty() && !i.Empty() && min() <= i.min() && max() >= i.max();
+ }
+
+ // Returns true iff there exists some point t for which this->Contains(t) &&
+ // i.Contains(t) evaluates to true, i.e. if the intersection is non-empty.
+ bool Intersects(const QuicInterval& i) const {
+ return !Empty() && !i.Empty() && min() < i.max() && max() > i.min();
+ }
+
+ // Returns true iff there exists some point t for which this->Contains(t) &&
+ // i.Contains(t) evaluates to true, i.e. if the intersection is non-empty.
+ // Furthermore, if the intersection is non-empty and the out pointer is not
+ // null, this method stores the calculated intersection in *out.
+ bool Intersects(const QuicInterval& i, QuicInterval* out) const;
+
+ // Sets *this to be the intersection of itself with i. Returns true iff
+ // *this was modified.
+ bool IntersectWith(const QuicInterval& i);
+
+ // Calculates the smallest QuicInterval containing both *this i, and updates
+ // *this to represent that QuicInterval, and returns true iff *this was
+ // modified.
+ bool SpanningUnion(const QuicInterval& i);
+
+ // Determines the difference between two QuicIntervals by finding all points
+ // that are contained in *this but not in i, coalesces those points into the
+ // largest possible contiguous QuicIntervals, and appends those QuicIntervals
+ // to the *difference vector. Intuitively this can be thought of as "erasing"
+ // i from *this. This will either completely erase *this (leaving nothing
+ // behind), partially erase some of *this from the left or right side (leaving
+ // some residual behind), or erase a hole in the middle of *this (leaving
+ // behind an QuicInterval on either side). Therefore, 0, 1, or 2 QuicIntervals
+ // will be appended to *difference. The method returns true iff the
+ // intersection of *this and i is non-empty. The caller owns the vector and
+ // the QuicInterval* pointers inside it. The difference vector is required to
+ // be non-null.
+ bool Difference(const QuicInterval& i,
+ std::vector<QuicInterval*>* difference) const;
+
+ // Determines the difference between two QuicIntervals as in
+ // Difference(QuicInterval&, vector*), but stores the results directly in out
+ // parameters rather than dynamically allocating an QuicInterval* and
+ // appending it to a vector. If two results are generated, the one with the
+ // smaller value of min() will be stored in *lo and the other in *hi.
+ // Otherwise (if fewer than two results are generated), unused arguments will
+ // be set to the empty QuicInterval (it is possible that *lo will be empty and
+ // *hi non-empty). The method returns true iff the intersection of *this and i
+ // is non-empty.
+ bool Difference(const QuicInterval& i,
+ QuicInterval* lo,
+ QuicInterval* hi) const;
+
+ friend bool operator==(const QuicInterval& a, const QuicInterval& b) {
+ bool ae = a.Empty();
+ bool be = b.Empty();
+ if (ae && be)
+ return true; // All empties are equal.
+ if (ae != be)
+ return false; // Empty cannot equal nonempty.
+ return a.min() == b.min() && a.max() == b.max();
+ }
+
+ friend bool operator!=(const QuicInterval& a, const QuicInterval& b) {
+ return !(a == b);
+ }
+
+ // Defines a comparator which can be used to induce an order on QuicIntervals,
+ // so that, for example, they can be stored in an ordered container such as
+ // std::set. The ordering is arbitrary, but does provide the guarantee that,
+ // for non-empty QuicIntervals X and Y, if X contains Y, then X <= Y.
+ // TODO(kosak): The current implementation of this comparator has a problem
+ // because the ordering it induces is inconsistent with that of Equals(). In
+ // particular, this comparator does not properly consider all empty
+ // QuicIntervals equivalent. Bug 9240050 has been created to track this.
+ friend bool operator<(const QuicInterval& a, const QuicInterval& b) {
+ return a.min() < b.min() || (!(b.min() < a.min()) && b.max() < a.max());
+ }
+
+ private:
+ T min_; // Inclusive lower bound.
+ T max_; // Exclusive upper bound.
+};
+
+// Constructs an QuicInterval by deducing the types from the function arguments.
+template <typename T>
+QuicInterval<T> MakeQuicInterval(T&& lhs, T&& rhs) {
+ return QuicInterval<T>(std::forward<T>(lhs), std::forward<T>(rhs));
+}
+
+// Note: ideally we'd use
+// decltype(out << "[" << i.min() << ", " << i.max() << ")")
+// as return type of the function, but as of July 2017 this triggers g++
+// "sorry, unimplemented: string literal in function template signature" error.
+template <typename T>
+auto operator<<(std::ostream& out, const QuicInterval<T>& i)
+ -> decltype(out << i.min()) {
+ return out << "[" << i.min() << ", " << i.max() << ")";
+}
+
+//==============================================================================
+// Implementation details: Clients can stop reading here.
+
+template <typename T>
+bool QuicInterval<T>::Intersects(const QuicInterval& i,
+ QuicInterval* out) const {
+ if (!Intersects(i))
+ return false;
+ if (out != nullptr) {
+ *out = QuicInterval(std::max(min(), i.min()), std::min(max(), i.max()));
+ }
+ return true;
+}
+
+template <typename T>
+bool QuicInterval<T>::IntersectWith(const QuicInterval& i) {
+ if (Empty())
+ return false;
+ bool modified = false;
+ if (i.min() > min()) {
+ SetMin(i.min());
+ modified = true;
+ }
+ if (i.max() < max()) {
+ SetMax(i.max());
+ modified = true;
+ }
+ return modified;
+}
+
+template <typename T>
+bool QuicInterval<T>::SpanningUnion(const QuicInterval& i) {
+ if (i.Empty())
+ return false;
+ if (Empty()) {
+ *this = i;
+ return true;
+ }
+ bool modified = false;
+ if (i.min() < min()) {
+ SetMin(i.min());
+ modified = true;
+ }
+ if (i.max() > max()) {
+ SetMax(i.max());
+ modified = true;
+ }
+ return modified;
+}
+
+template <typename T>
+bool QuicInterval<T>::Difference(const QuicInterval& i,
+ std::vector<QuicInterval*>* difference) const {
+ if (Empty()) {
+ // <empty> - <i> = <empty>
+ return false;
+ }
+ if (i.Empty()) {
+ // <this> - <empty> = <this>
+ difference->push_back(new QuicInterval(*this));
+ return false;
+ }
+ if (min() < i.max() && min() >= i.min() && max() > i.max()) {
+ // [------ this ------)
+ // [------ i ------)
+ // [-- result ---)
+ difference->push_back(new QuicInterval(i.max(), max()));
+ return true;
+ }
+ if (max() > i.min() && max() <= i.max() && min() < i.min()) {
+ // [------ this ------)
+ // [------ i ------)
+ // [- result -)
+ difference->push_back(new QuicInterval(min(), i.min()));
+ return true;
+ }
+ if (min() < i.min() && max() > i.max()) {
+ // [------- this --------)
+ // [---- i ----)
+ // [ R1 ) [ R2 )
+ // There are two results: R1 and R2.
+ difference->push_back(new QuicInterval(min(), i.min()));
+ difference->push_back(new QuicInterval(i.max(), max()));
+ return true;
+ }
+ if (min() >= i.min() && max() <= i.max()) {
+ // [--- this ---)
+ // [------ i --------)
+ // Intersection is <this>, so difference yields the empty QuicInterval.
+ // Nothing is appended to *difference.
+ return true;
+ }
+ // No intersection. Append <this>.
+ difference->push_back(new QuicInterval(*this));
+ return false;
+}
+
+template <typename T>
+bool QuicInterval<T>::Difference(const QuicInterval& i,
+ QuicInterval* lo,
+ QuicInterval* hi) const {
+ // Initialize *lo and *hi to empty
+ *lo = {};
+ *hi = {};
+ if (Empty())
+ return false;
+ if (i.Empty()) {
+ *lo = *this;
+ return false;
+ }
+ if (min() < i.max() && min() >= i.min() && max() > i.max()) {
+ // [------ this ------)
+ // [------ i ------)
+ // [-- result ---)
+ *hi = QuicInterval(i.max(), max());
+ return true;
+ }
+ if (max() > i.min() && max() <= i.max() && min() < i.min()) {
+ // [------ this ------)
+ // [------ i ------)
+ // [- result -)
+ *lo = QuicInterval(min(), i.min());
+ return true;
+ }
+ if (min() < i.min() && max() > i.max()) {
+ // [------- this --------)
+ // [---- i ----)
+ // [ R1 ) [ R2 )
+ // There are two results: R1 and R2.
+ *lo = QuicInterval(min(), i.min());
+ *hi = QuicInterval(i.max(), max());
+ return true;
+ }
+ if (min() >= i.min() && max() <= i.max()) {
+ // [--- this ---)
+ // [------ i --------)
+ // Intersection is <this>, so difference yields the empty QuicInterval.
+ return true;
+ }
+ *lo = *this; // No intersection.
+ return false;
+}
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_CORE_QUIC_INTERVAL_H_
diff --git a/quic/core/quic_interval_set.h b/quic/core/quic_interval_set.h
new file mode 100644
index 0000000..937412a
--- /dev/null
+++ b/quic/core/quic_interval_set.h
@@ -0,0 +1,883 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_CORE_QUIC_INTERVAL_SET_H_
+#define QUICHE_QUIC_CORE_QUIC_INTERVAL_SET_H_
+
+// QuicIntervalSet<T> is a data structure used to represent a sorted set of
+// non-empty, non-adjacent, and mutually disjoint intervals. Mutations to an
+// interval set preserve these properties, altering the set as needed. For
+// example, adding [2, 3) to a set containing only [1, 2) would result in the
+// set containing the single interval [1, 3).
+//
+// Supported operations include testing whether an Interval is contained in the
+// QuicIntervalSet, comparing two QuicIntervalSets, and performing
+// QuicIntervalSet union, intersection, and difference.
+//
+// QuicIntervalSet maintains the minimum number of entries needed to represent
+// the set of underlying intervals. When the QuicIntervalSet is modified (e.g.
+// due to an Add operation), other interval entries may be coalesced, removed,
+// or otherwise modified in order to maintain this invariant. The intervals are
+// maintained in sorted order, by ascending min() value.
+//
+// The reader is cautioned to beware of the terminology used here: this library
+// uses the terms "min" and "max" rather than "begin" and "end" as is
+// conventional for the STL. The terminology [min, max) refers to the half-open
+// interval which (if the interval is not empty) contains min but does not
+// contain max. An interval is considered empty if min >= max.
+//
+// T is required to be default- and copy-constructible, to have an assignment
+// operator, a difference operator (operator-()), and the full complement of
+// comparison operators (<, <=, ==, !=, >=, >). These requirements are inherited
+// from value_type.
+//
+// QuicIntervalSet has constant-time move operations.
+//
+//
+// Examples:
+// QuicIntervalSet<int> intervals;
+// intervals.Add(Interval<int>(10, 20));
+// intervals.Add(Interval<int>(30, 40));
+// // intervals contains [10,20) and [30,40).
+// intervals.Add(Interval<int>(15, 35));
+// // intervals has been coalesced. It now contains the single range [10,40).
+// EXPECT_EQ(1, intervals.Size());
+// EXPECT_TRUE(intervals.Contains(Interval<int>(10, 40)));
+//
+// intervals.Difference(Interval<int>(10, 20));
+// // intervals should now contain the single range [20, 40).
+// EXPECT_EQ(1, intervals.Size());
+// EXPECT_TRUE(intervals.Contains(Interval<int>(20, 40)));
+
+#include <stddef.h>
+#include <algorithm>
+#include <initializer_list>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "net/third_party/quiche/src/quic/core/quic_interval.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+
+namespace quic {
+
+template <typename T>
+class QuicIntervalSet {
+ public:
+ typedef QuicInterval<T> value_type;
+
+ private:
+ struct IntervalLess {
+ bool operator()(const value_type& a, const value_type& b) const;
+ };
+ typedef std::set<value_type, IntervalLess> Set;
+
+ public:
+ typedef typename Set::const_iterator const_iterator;
+ typedef typename Set::const_reverse_iterator const_reverse_iterator;
+
+ // Instantiates an empty QuicIntervalSet.
+ QuicIntervalSet() {}
+
+ // Instantiates an QuicIntervalSet containing exactly one initial half-open
+ // interval [min, max), unless the given interval is empty, in which case the
+ // QuicIntervalSet will be empty.
+ explicit QuicIntervalSet(const value_type& interval) { Add(interval); }
+
+ // Instantiates an QuicIntervalSet containing the half-open interval [min,
+ // max).
+ QuicIntervalSet(const T& min, const T& max) { Add(min, max); }
+
+ QuicIntervalSet(std::initializer_list<value_type> il) { assign(il); }
+
+ // Clears this QuicIntervalSet.
+ void Clear() { intervals_.clear(); }
+
+ // Returns the number of disjoint intervals contained in this QuicIntervalSet.
+ size_t Size() const { return intervals_.size(); }
+
+ // Returns the smallest interval that contains all intervals in this
+ // QuicIntervalSet, or the empty interval if the set is empty.
+ value_type SpanningInterval() const;
+
+ // Adds "interval" to this QuicIntervalSet. Adding the empty interval has no
+ // effect.
+ void Add(const value_type& interval);
+
+ // Adds the interval [min, max) to this QuicIntervalSet. Adding the empty
+ // interval has no effect.
+ void Add(const T& min, const T& max) { Add(value_type(min, max)); }
+
+ // DEPRECATED(kosak). Use Union() instead. This method merges all of the
+ // values contained in "other" into this QuicIntervalSet.
+ void Add(const QuicIntervalSet& other);
+
+ // Returns true if this QuicIntervalSet is empty.
+ bool Empty() const { return intervals_.empty(); }
+
+ // Returns true if any interval in this QuicIntervalSet contains the indicated
+ // value.
+ bool Contains(const T& value) const;
+
+ // Returns true if there is some interval in this QuicIntervalSet that wholly
+ // contains the given interval. An interval O "wholly contains" a non-empty
+ // interval I if O.Contains(p) is true for every p in I. This is the same
+ // definition used by value_type::Contains(). This method returns false on
+ // the empty interval, due to a (perhaps unintuitive) convention inherited
+ // from value_type.
+ // Example:
+ // Assume an QuicIntervalSet containing the entries { [10,20), [30,40) }.
+ // Contains(Interval(15, 16)) returns true, because [10,20) contains
+ // [15,16). However, Contains(Interval(15, 35)) returns false.
+ bool Contains(const value_type& interval) const;
+
+ // Returns true if for each interval in "other", there is some (possibly
+ // different) interval in this QuicIntervalSet which wholly contains it. See
+ // Contains(const value_type& interval) for the meaning of "wholly contains".
+ // Perhaps unintuitively, this method returns false if "other" is the empty
+ // set. The algorithmic complexity of this method is O(other.Size() *
+ // log(this->Size())). The method could be rewritten to run in O(other.Size()
+ // + this->Size()), and this alternative could be implemented as a free
+ // function using the public API.
+ bool Contains(const QuicIntervalSet<T>& other) const;
+
+ // Returns true if there is some interval in this QuicIntervalSet that wholly
+ // contains the interval [min, max). See Contains(const value_type&).
+ bool Contains(const T& min, const T& max) const {
+ return Contains(value_type(min, max));
+ }
+
+ // Returns true if for some interval in "other", there is some interval in
+ // this QuicIntervalSet that intersects with it. See value_type::Intersects()
+ // for the definition of interval intersection.
+ bool Intersects(const QuicIntervalSet& other) const;
+
+ // Returns an iterator to the value_type in the QuicIntervalSet that contains
+ // the given value. In other words, returns an iterator to the unique interval
+ // [min, max) in the QuicIntervalSet that has the property min <= value < max.
+ // If there is no such interval, this method returns end().
+ const_iterator Find(const T& value) const;
+
+ // Returns an iterator to the value_type in the QuicIntervalSet that wholly
+ // contains the given interval. In other words, returns an iterator to the
+ // unique interval outer in the QuicIntervalSet that has the property that
+ // outer.Contains(interval). If there is no such interval, or if interval is
+ // empty, returns end().
+ const_iterator Find(const value_type& interval) const;
+
+ // Returns an iterator to the value_type in the QuicIntervalSet that wholly
+ // contains [min, max). In other words, returns an iterator to the unique
+ // interval outer in the QuicIntervalSet that has the property that
+ // outer.Contains(Interval<T>(min, max)). If there is no such interval, or if
+ // interval is empty, returns end().
+ const_iterator Find(const T& min, const T& max) const {
+ return Find(value_type(min, max));
+ }
+
+ // Returns an iterator pointing to the first value_type which contains or
+ // goes after the given value.
+ //
+ // Example:
+ // [10, 20) [30, 40)
+ // ^ LowerBound(10)
+ // ^ LowerBound(15)
+ // ^ LowerBound(20)
+ // ^ LowerBound(25)
+ const_iterator LowerBound(const T& value) const;
+
+ // Returns an iterator pointing to the first value_type which goes after
+ // the given value.
+ //
+ // Example:
+ // [10, 20) [30, 40)
+ // ^ UpperBound(10)
+ // ^ UpperBound(15)
+ // ^ UpperBound(20)
+ // ^ UpperBound(25)
+ const_iterator UpperBound(const T& value) const;
+
+ // Returns true if every value within the passed interval is not Contained
+ // within the QuicIntervalSet.
+ // Note that empty intervals are always considered disjoint from the
+ // QuicIntervalSet (even though the QuicIntervalSet doesn't `Contain` them).
+ bool IsDisjoint(const value_type& interval) const;
+
+ // Merges all the values contained in "other" into this QuicIntervalSet.
+ void Union(const QuicIntervalSet& other);
+
+ // Modifies this QuicIntervalSet so that it contains only those values that
+ // are currently present both in *this and in the QuicIntervalSet "other".
+ void Intersection(const QuicIntervalSet& other);
+
+ // Mutates this QuicIntervalSet so that it contains only those values that are
+ // currently in *this but not in "interval".
+ void Difference(const value_type& interval);
+
+ // Mutates this QuicIntervalSet so that it contains only those values that are
+ // currently in *this but not in the interval [min, max).
+ void Difference(const T& min, const T& max);
+
+ // Mutates this QuicIntervalSet so that it contains only those values that are
+ // currently in *this but not in the QuicIntervalSet "other".
+ void Difference(const QuicIntervalSet& other);
+
+ // Mutates this QuicIntervalSet so that it contains only those values that are
+ // in [min, max) but not currently in *this.
+ void Complement(const T& min, const T& max);
+
+ // QuicIntervalSet's begin() iterator. The invariants of QuicIntervalSet
+ // guarantee that for each entry e in the set, e.min() < e.max() (because the
+ // entries are non-empty) and for each entry f that appears later in the set,
+ // e.max() < f.min() (because the entries are ordered, pairwise-disjoint, and
+ // non-adjacent). Modifications to this QuicIntervalSet invalidate these
+ // iterators.
+ const_iterator begin() const { return intervals_.begin(); }
+
+ // QuicIntervalSet's end() iterator.
+ const_iterator end() const { return intervals_.end(); }
+
+ // QuicIntervalSet's rbegin() and rend() iterators. Iterator invalidation
+ // semantics are the same as those for begin() / end().
+ const_reverse_iterator rbegin() const { return intervals_.rbegin(); }
+
+ const_reverse_iterator rend() const { return intervals_.rend(); }
+
+ template <typename Iter>
+ void assign(Iter first, Iter last) {
+ Clear();
+ for (; first != last; ++first)
+ Add(*first);
+ }
+
+ void assign(std::initializer_list<value_type> il) {
+ assign(il.begin(), il.end());
+ }
+
+ // Returns a human-readable representation of this set. This will typically be
+ // (though is not guaranteed to be) of the form
+ // "[a1, b1) [a2, b2) ... [an, bn)"
+ // where the intervals are in the same order as given by traversal from
+ // begin() to end(). This representation is intended for human consumption;
+ // computer programs should not rely on the output being in exactly this form.
+ string ToString() const;
+
+ QuicIntervalSet& operator=(std::initializer_list<value_type> il) {
+ assign(il.begin(), il.end());
+ return *this;
+ }
+
+ // Swap this QuicIntervalSet with *other. This is a constant-time operation.
+ void Swap(QuicIntervalSet<T>* other) { intervals_.swap(other->intervals_); }
+
+ friend bool operator==(const QuicIntervalSet& a, const QuicIntervalSet& b) {
+ return a.Size() == b.Size() &&
+ std::equal(a.begin(), a.end(), b.begin(), NonemptyIntervalEq());
+ }
+
+ friend bool operator!=(const QuicIntervalSet& a, const QuicIntervalSet& b) {
+ return !(a == b);
+ }
+
+ private:
+ // Simple member-wise equality, since all intervals are non-empty.
+ struct NonemptyIntervalEq {
+ bool operator()(const value_type& a, const value_type& b) const {
+ return a.min() == b.min() && a.max() == b.max();
+ }
+ };
+
+ // Removes overlapping ranges and coalesces adjacent intervals as needed.
+ void Compact(const typename Set::iterator& begin,
+ const typename Set::iterator& end);
+
+ // Returns true if this set is valid (i.e. all intervals in it are non-empty,
+ // non-adjacent, and mutually disjoint). Currently this is used as an
+ // integrity check by the Intersection() and Difference() methods, but is only
+ // invoked for debug builds (via DCHECK).
+ bool Valid() const;
+
+ // Finds the first interval that potentially intersects 'other'.
+ const_iterator FindIntersectionCandidate(const QuicIntervalSet& other) const;
+
+ // Finds the first interval that potentially intersects 'interval'.
+ const_iterator FindIntersectionCandidate(const value_type& interval) const;
+
+ // Helper for Intersection() and Difference(): Finds the next pair of
+ // intervals from 'x' and 'y' that intersect. 'mine' is an iterator
+ // over x->intervals_. 'theirs' is an iterator over y.intervals_. 'mine'
+ // and 'theirs' are advanced until an intersecting pair is found.
+ // Non-intersecting intervals (aka "holes") from x->intervals_ can be
+ // optionally erased by "on_hole".
+ template <typename X, typename Func>
+ static bool FindNextIntersectingPairImpl(X* x,
+ const QuicIntervalSet& y,
+ const_iterator* mine,
+ const_iterator* theirs,
+ Func on_hole);
+
+ // The variant of the above method that doesn't mutate this QuicIntervalSet.
+ bool FindNextIntersectingPair(const QuicIntervalSet& other,
+ const_iterator* mine,
+ const_iterator* theirs) const {
+ return FindNextIntersectingPairImpl(
+ this, other, mine, theirs,
+ [](const QuicIntervalSet*, const_iterator, const_iterator) {});
+ }
+
+ // The variant of the above method that mutates this QuicIntervalSet by
+ // erasing holes.
+ bool FindNextIntersectingPairAndEraseHoles(const QuicIntervalSet& other,
+ const_iterator* mine,
+ const_iterator* theirs) {
+ return FindNextIntersectingPairImpl(
+ this, other, mine, theirs,
+ [](QuicIntervalSet* x, const_iterator from, const_iterator to) {
+ x->intervals_.erase(from, to);
+ });
+ }
+
+ // The representation for the intervals. The intervals in this set are
+ // non-empty, pairwise-disjoint, non-adjacent and ordered in ascending order
+ // by min().
+ Set intervals_;
+};
+
+template <typename T>
+auto operator<<(std::ostream& out, const QuicIntervalSet<T>& seq)
+ -> decltype(out << *seq.begin()) {
+ out << "{";
+ for (const auto& interval : seq) {
+ out << " " << interval;
+ }
+ out << " }";
+
+ return out;
+}
+
+template <typename T>
+void swap(QuicIntervalSet<T>& x, QuicIntervalSet<T>& y);
+
+//==============================================================================
+// Implementation details: Clients can stop reading here.
+
+template <typename T>
+typename QuicIntervalSet<T>::value_type QuicIntervalSet<T>::SpanningInterval()
+ const {
+ value_type result;
+ if (!intervals_.empty()) {
+ result.SetMin(intervals_.begin()->min());
+ result.SetMax(intervals_.rbegin()->max());
+ }
+ return result;
+}
+
+template <typename T>
+void QuicIntervalSet<T>::Add(const value_type& interval) {
+ if (interval.Empty())
+ return;
+ std::pair<typename Set::iterator, bool> ins = intervals_.insert(interval);
+ if (!ins.second) {
+ // This interval already exists.
+ return;
+ }
+ // Determine the minimal range that will have to be compacted. We know that
+ // the QuicIntervalSet was valid before the addition of the interval, so only
+ // need to start with the interval itself (although Compact takes an open
+ // range so begin needs to be the interval to the left). We don't know how
+ // many ranges this interval may cover, so we need to find the appropriate
+ // interval to end with on the right.
+ typename Set::iterator begin = ins.first;
+ if (begin != intervals_.begin())
+ --begin;
+ const value_type target_end(interval.max(), interval.max());
+ const typename Set::iterator end = intervals_.upper_bound(target_end);
+ Compact(begin, end);
+}
+
+template <typename T>
+void QuicIntervalSet<T>::Add(const QuicIntervalSet& other) {
+ for (const_iterator it = other.begin(); it != other.end(); ++it) {
+ Add(*it);
+ }
+}
+
+template <typename T>
+bool QuicIntervalSet<T>::Contains(const T& value) const {
+ value_type tmp(value, value);
+ // Find the first interval with min() > value, then move back one step
+ const_iterator it = intervals_.upper_bound(tmp);
+ if (it == intervals_.begin())
+ return false;
+ --it;
+ return it->Contains(value);
+}
+
+template <typename T>
+bool QuicIntervalSet<T>::Contains(const value_type& interval) const {
+ // Find the first interval with min() > value, then move back one step.
+ const_iterator it = intervals_.upper_bound(interval);
+ if (it == intervals_.begin())
+ return false;
+ --it;
+ return it->Contains(interval);
+}
+
+template <typename T>
+bool QuicIntervalSet<T>::Contains(const QuicIntervalSet<T>& other) const {
+ if (!SpanningInterval().Contains(other.SpanningInterval())) {
+ return false;
+ }
+
+ for (const_iterator i = other.begin(); i != other.end(); ++i) {
+ // If we don't contain the interval, can return false now.
+ if (!Contains(*i)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+// This method finds the interval that Contains() "value", if such an interval
+// exists in the QuicIntervalSet. The way this is done is to locate the
+// "candidate interval", the only interval that could *possibly* contain value,
+// and test it using Contains(). The candidate interval is the interval with the
+// largest min() having min() <= value.
+//
+// Determining the candidate interval takes a couple of steps. First, since the
+// underlying std::set stores intervals, not values, we need to create a "probe
+// interval" suitable for use as a search key. The probe interval used is
+// [value, value). Now we can restate the problem as finding the largest
+// interval in the QuicIntervalSet that is <= the probe interval.
+//
+// This restatement only works if the set's comparator behaves in a certain way.
+// In particular it needs to order first by ascending min(), and then by
+// descending max(). The comparator used by this library is defined in exactly
+// this way. To see why descending max() is required, consider the following
+// example. Assume an QuicIntervalSet containing these intervals:
+//
+// [0, 5) [10, 20) [50, 60)
+//
+// Consider searching for the value 15. The probe interval [15, 15) is created,
+// and [10, 20) is identified as the largest interval in the set <= the probe
+// interval. This is the correct interval needed for the Contains() test, which
+// will then return true.
+//
+// Now consider searching for the value 30. The probe interval [30, 30) is
+// created, and again [10, 20] is identified as the largest interval <= the
+// probe interval. This is again the correct interval needed for the Contains()
+// test, which in this case returns false.
+//
+// Finally, consider searching for the value 10. The probe interval [10, 10) is
+// created. Here the ordering relationship between [10, 10) and [10, 20) becomes
+// vitally important. If [10, 10) were to come before [10, 20), then [0, 5)
+// would be the largest interval <= the probe, leading to the wrong choice of
+// interval for the Contains() test. Therefore [10, 10) needs to come after
+// [10, 20). The simplest way to make this work in the general case is to order
+// by ascending min() but descending max(). In this ordering, the empty interval
+// is larger than any non-empty interval with the same min(). The comparator
+// used by this library is careful to induce this ordering.
+//
+// Another detail involves the choice of which std::set method to use to try to
+// find the candidate interval. The most appropriate entry point is
+// set::upper_bound(), which finds the smallest interval which is > the probe
+// interval. The semantics of upper_bound() are slightly different from what we
+// want (namely, to find the largest interval which is <= the probe interval)
+// but they are close enough; the interval found by upper_bound() will always be
+// one step past the interval we are looking for (if it exists) or at begin()
+// (if it does not). Getting to the proper interval is a simple matter of
+// decrementing the iterator.
+template <typename T>
+typename QuicIntervalSet<T>::const_iterator QuicIntervalSet<T>::Find(
+ const T& value) const {
+ value_type tmp(value, value);
+ const_iterator it = intervals_.upper_bound(tmp);
+ if (it == intervals_.begin())
+ return intervals_.end();
+ --it;
+ if (it->Contains(value))
+ return it;
+ else
+ return intervals_.end();
+}
+
+// This method finds the interval that Contains() the interval "probe", if such
+// an interval exists in the QuicIntervalSet. The way this is done is to locate
+// the "candidate interval", the only interval that could *possibly* contain
+// "probe", and test it using Contains(). The candidate interval is the largest
+// interval that is <= the probe interval.
+//
+// The search for the candidate interval only works if the comparator used
+// behaves in a certain way. In particular it needs to order first by ascending
+// min(), and then by descending max(). The comparator used by this library is
+// defined in exactly this way. To see why descending max() is required,
+// consider the following example. Assume an QuicIntervalSet containing these
+// intervals:
+//
+// [0, 5) [10, 20) [50, 60)
+//
+// Consider searching for the probe [15, 17). [10, 20) is the largest interval
+// in the set which is <= the probe interval. This is the correct interval
+// needed for the Contains() test, which will then return true, because [10, 20)
+// contains [15, 17).
+//
+// Now consider searching for the probe [30, 32). Again [10, 20] is the largest
+// interval <= the probe interval. This is again the correct interval needed for
+// the Contains() test, which in this case returns false, because [10, 20) does
+// not contain [30, 32).
+//
+// Finally, consider searching for the probe [10, 12). Here the ordering
+// relationship between [10, 12) and [10, 20) becomes vitally important. If
+// [10, 12) were to come before [10, 20), then [0, 5) would be the largest
+// interval <= the probe, leading to the wrong choice of interval for the
+// Contains() test. Therefore [10, 12) needs to come after [10, 20). The
+// simplest way to make this work in the general case is to order by ascending
+// min() but descending max(). In this ordering, given two intervals with the
+// same min(), the wider one goes before the narrower one. The comparator used
+// by this library is careful to induce this ordering.
+//
+// Another detail involves the choice of which std::set method to use to try to
+// find the candidate interval. The most appropriate entry point is
+// set::upper_bound(), which finds the smallest interval which is > the probe
+// interval. The semantics of upper_bound() are slightly different from what we
+// want (namely, to find the largest interval which is <= the probe interval)
+// but they are close enough; the interval found by upper_bound() will always be
+// one step past the interval we are looking for (if it exists) or at begin()
+// (if it does not). Getting to the proper interval is a simple matter of
+// decrementing the iterator.
+template <typename T>
+typename QuicIntervalSet<T>::const_iterator QuicIntervalSet<T>::Find(
+ const value_type& probe) const {
+ const_iterator it = intervals_.upper_bound(probe);
+ if (it == intervals_.begin())
+ return intervals_.end();
+ --it;
+ if (it->Contains(probe))
+ return it;
+ else
+ return intervals_.end();
+}
+
+template <typename T>
+typename QuicIntervalSet<T>::const_iterator QuicIntervalSet<T>::LowerBound(
+ const T& value) const {
+ const_iterator it = intervals_.lower_bound(value_type(value, value));
+ if (it == intervals_.begin()) {
+ return it;
+ }
+
+ // The previous intervals_.lower_bound() checking is essentially based on
+ // interval.min(), so we need to check whether the `value` is contained in
+ // the previous interval.
+ --it;
+ if (it->Contains(value)) {
+ return it;
+ } else {
+ return ++it;
+ }
+}
+
+template <typename T>
+typename QuicIntervalSet<T>::const_iterator QuicIntervalSet<T>::UpperBound(
+ const T& value) const {
+ return intervals_.upper_bound(value_type(value, value));
+}
+
+template <typename T>
+bool QuicIntervalSet<T>::IsDisjoint(const value_type& interval) const {
+ if (interval.Empty())
+ return true;
+ value_type tmp(interval.min(), interval.min());
+ // Find the first interval with min() > interval.min()
+ const_iterator it = intervals_.upper_bound(tmp);
+ if (it != intervals_.end() && interval.max() > it->min())
+ return false;
+ if (it == intervals_.begin())
+ return true;
+ --it;
+ return it->max() <= interval.min();
+}
+
+template <typename T>
+void QuicIntervalSet<T>::Union(const QuicIntervalSet& other) {
+ intervals_.insert(other.begin(), other.end());
+ Compact(intervals_.begin(), intervals_.end());
+}
+
+template <typename T>
+typename QuicIntervalSet<T>::const_iterator
+QuicIntervalSet<T>::FindIntersectionCandidate(
+ const QuicIntervalSet& other) const {
+ return FindIntersectionCandidate(*other.intervals_.begin());
+}
+
+template <typename T>
+typename QuicIntervalSet<T>::const_iterator
+QuicIntervalSet<T>::FindIntersectionCandidate(
+ const value_type& interval) const {
+ // Use upper_bound to efficiently find the first interval in intervals_
+ // where min() is greater than interval.min(). If the result
+ // isn't the beginning of intervals_ then move backwards one interval since
+ // the interval before it is the first candidate where max() may be
+ // greater than interval.min().
+ // In other words, no interval before that can possibly intersect with any
+ // of other.intervals_.
+ const_iterator mine = intervals_.upper_bound(interval);
+ if (mine != intervals_.begin()) {
+ --mine;
+ }
+ return mine;
+}
+
+template <typename T>
+template <typename X, typename Func>
+bool QuicIntervalSet<T>::FindNextIntersectingPairImpl(X* x,
+ const QuicIntervalSet& y,
+ const_iterator* mine,
+ const_iterator* theirs,
+ Func on_hole) {
+ CHECK(x != nullptr);
+ if ((*mine == x->intervals_.end()) || (*theirs == y.intervals_.end())) {
+ return false;
+ }
+ while (!(**mine).Intersects(**theirs)) {
+ const_iterator erase_first = *mine;
+ // Skip over intervals in 'mine' that don't reach 'theirs'.
+ while (*mine != x->intervals_.end() && (**mine).max() <= (**theirs).min()) {
+ ++(*mine);
+ }
+ on_hole(x, erase_first, *mine);
+ // We're done if the end of intervals_ is reached.
+ if (*mine == x->intervals_.end()) {
+ return false;
+ }
+ // Skip over intervals 'theirs' that don't reach 'mine'.
+ while (*theirs != y.intervals_.end() &&
+ (**theirs).max() <= (**mine).min()) {
+ ++(*theirs);
+ }
+ // If the end of other.intervals_ is reached, we're done.
+ if (*theirs == y.intervals_.end()) {
+ on_hole(x, *mine, x->intervals_.end());
+ return false;
+ }
+ }
+ return true;
+}
+
+template <typename T>
+void QuicIntervalSet<T>::Intersection(const QuicIntervalSet& other) {
+ if (!SpanningInterval().Intersects(other.SpanningInterval())) {
+ intervals_.clear();
+ return;
+ }
+
+ const_iterator mine = FindIntersectionCandidate(other);
+ // Remove any intervals that cannot possibly intersect with other.intervals_.
+ intervals_.erase(intervals_.begin(), mine);
+ const_iterator theirs = other.FindIntersectionCandidate(*this);
+
+ while (FindNextIntersectingPairAndEraseHoles(other, &mine, &theirs)) {
+ // OK, *mine and *theirs intersect. Now, we find the largest
+ // span of intervals in other (starting at theirs) - say [a..b]
+ // - that intersect *mine, and we replace *mine with (*mine
+ // intersect x) for all x in [a..b] Note that subsequent
+ // intervals in this can't intersect any intervals in [a..b) --
+ // they may only intersect b or subsequent intervals in other.
+ value_type i(*mine);
+ intervals_.erase(mine);
+ mine = intervals_.end();
+ value_type intersection;
+ while (theirs != other.intervals_.end() &&
+ i.Intersects(*theirs, &intersection)) {
+ std::pair<typename Set::iterator, bool> ins =
+ intervals_.insert(intersection);
+ DCHECK(ins.second);
+ mine = ins.first;
+ ++theirs;
+ }
+ DCHECK(mine != intervals_.end());
+ --theirs;
+ ++mine;
+ }
+ DCHECK(Valid());
+}
+
+template <typename T>
+bool QuicIntervalSet<T>::Intersects(const QuicIntervalSet& other) const {
+ if (!SpanningInterval().Intersects(other.SpanningInterval())) {
+ return false;
+ }
+
+ const_iterator mine = FindIntersectionCandidate(other);
+ if (mine == intervals_.end()) {
+ return false;
+ }
+ const_iterator theirs = other.FindIntersectionCandidate(*mine);
+
+ return FindNextIntersectingPair(other, &mine, &theirs);
+}
+
+template <typename T>
+void QuicIntervalSet<T>::Difference(const value_type& interval) {
+ if (!SpanningInterval().Intersects(interval)) {
+ return;
+ }
+ Difference(QuicIntervalSet<T>(interval));
+}
+
+template <typename T>
+void QuicIntervalSet<T>::Difference(const T& min, const T& max) {
+ Difference(value_type(min, max));
+}
+
+template <typename T>
+void QuicIntervalSet<T>::Difference(const QuicIntervalSet& other) {
+ if (!SpanningInterval().Intersects(other.SpanningInterval())) {
+ return;
+ }
+
+ const_iterator mine = FindIntersectionCandidate(other);
+ // If no interval in mine reaches the first interval of theirs then we're
+ // done.
+ if (mine == intervals_.end()) {
+ return;
+ }
+ const_iterator theirs = other.FindIntersectionCandidate(*this);
+
+ while (FindNextIntersectingPair(other, &mine, &theirs)) {
+ // At this point *mine and *theirs overlap. Remove mine from
+ // intervals_ and replace it with the possibly two intervals that are
+ // the difference between mine and theirs.
+ value_type i(*mine);
+ intervals_.erase(mine++);
+ value_type lo;
+ value_type hi;
+ i.Difference(*theirs, &lo, &hi);
+
+ if (!lo.Empty()) {
+ // We have a low end. This can't intersect anything else.
+ std::pair<typename Set::iterator, bool> ins = intervals_.insert(lo);
+ DCHECK(ins.second);
+ }
+
+ if (!hi.Empty()) {
+ std::pair<typename Set::iterator, bool> ins = intervals_.insert(hi);
+ DCHECK(ins.second);
+ mine = ins.first;
+ }
+ }
+ DCHECK(Valid());
+}
+
+template <typename T>
+void QuicIntervalSet<T>::Complement(const T& min, const T& max) {
+ QuicIntervalSet<T> span(min, max);
+ span.Difference(*this);
+ intervals_.swap(span.intervals_);
+}
+
+template <typename T>
+string QuicIntervalSet<T>::ToString() const {
+ std::ostringstream os;
+ os << *this;
+ return os.str();
+}
+
+// This method compacts the QuicIntervalSet, merging pairs of overlapping
+// intervals into a single interval. In the steady state, the QuicIntervalSet
+// does not contain any such pairs. However, the way the Union() and Add()
+// methods work is to temporarily put the QuicIntervalSet into such a state and
+// then to call Compact() to "fix it up" so that it is no longer in that state.
+//
+// Compact() needs the interval set to allow two intervals [a,b) and [a,c)
+// (having the same min() but different max()) to briefly coexist in the set at
+// the same time, and be adjacent to each other, so that they can be efficiently
+// located and merged into a single interval. This state would be impossible
+// with a comparator which only looked at min(), as such a comparator would
+// consider such pairs equal. Fortunately, the comparator used by
+// QuicIntervalSet does exactly what is needed, ordering first by ascending
+// min(), then by descending max().
+template <typename T>
+void QuicIntervalSet<T>::Compact(const typename Set::iterator& begin,
+ const typename Set::iterator& end) {
+ if (begin == end)
+ return;
+ typename Set::iterator next = begin;
+ typename Set::iterator prev = begin;
+ typename Set::iterator it = begin;
+ ++it;
+ ++next;
+ while (it != end) {
+ ++next;
+ if (prev->max() >= it->min()) {
+ // Overlapping / coalesced range; merge the two intervals.
+ T min = prev->min();
+ T max = std::max(prev->max(), it->max());
+ value_type i(min, max);
+ intervals_.erase(prev);
+ intervals_.erase(it);
+ std::pair<typename Set::iterator, bool> ins = intervals_.insert(i);
+ DCHECK(ins.second);
+ prev = ins.first;
+ } else {
+ prev = it;
+ }
+ it = next;
+ }
+}
+
+template <typename T>
+bool QuicIntervalSet<T>::Valid() const {
+ const_iterator prev = end();
+ for (const_iterator it = begin(); it != end(); ++it) {
+ // invalid or empty interval.
+ if (it->min() >= it->max())
+ return false;
+ // Not sorted, not disjoint, or adjacent.
+ if (prev != end() && prev->max() >= it->min())
+ return false;
+ prev = it;
+ }
+ return true;
+}
+
+template <typename T>
+void swap(QuicIntervalSet<T>& x, QuicIntervalSet<T>& y) {
+ x.Swap(&y);
+}
+
+// This comparator orders intervals first by ascending min() and then by
+// descending max(). Readers who are satisified with that explanation can stop
+// reading here. The remainder of this comment is for the benefit of future
+// maintainers of this library.
+//
+// The reason for this ordering is that this comparator has to serve two
+// masters. First, it has to maintain the intervals in its internal set in the
+// order that clients expect to see them. Clients see these intervals via the
+// iterators provided by begin()/end() or as a result of invoking Get(). For
+// this reason, the comparator orders intervals by ascending min().
+//
+// If client iteration were the only consideration, then ordering by ascending
+// min() would be good enough. This is because the intervals in the
+// QuicIntervalSet are non-empty, non-adjacent, and mutually disjoint; such
+// intervals happen to always have disjoint min() values, so such a comparator
+// would never even have to look at max() in order to work correctly for this
+// class.
+//
+// However, in addition to ordering by ascending min(), this comparator also has
+// a second responsibility: satisfying the special needs of this library's
+// peculiar internal implementation. These needs require the comparator to order
+// first by ascending min() and then by descending max(). The best way to
+// understand why this is so is to check out the comments associated with the
+// Find() and Compact() methods.
+template <typename T>
+bool QuicIntervalSet<T>::IntervalLess::operator()(const value_type& a,
+ const value_type& b) const {
+ return a.min() < b.min() || (a.min() == b.min() && a.max() > b.max());
+}
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_CORE_QUIC_INTERVAL_SET_H_
diff --git a/quic/core/quic_interval_set_test.cc b/quic/core/quic_interval_set_test.cc
new file mode 100644
index 0000000..65d1d32
--- /dev/null
+++ b/quic/core/quic_interval_set_test.cc
@@ -0,0 +1,979 @@
+// 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_interval_set.h"
+
+#include <stdarg.h>
+#include <algorithm>
+#include <iostream>
+#include <iterator>
+#include <limits>
+#include <vector>
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+
+namespace quic {
+namespace test {
+namespace {
+
+using ::testing::ElementsAreArray;
+
+class QuicIntervalSetTest : public QuicTest {
+ protected:
+ virtual void SetUp() {
+ // Initialize two QuicIntervalSets for union, intersection, and difference
+ // tests
+ is.Add(100, 200);
+ is.Add(300, 400);
+ is.Add(500, 600);
+ is.Add(700, 800);
+ is.Add(900, 1000);
+ is.Add(1100, 1200);
+ is.Add(1300, 1400);
+ is.Add(1500, 1600);
+ is.Add(1700, 1800);
+ is.Add(1900, 2000);
+ is.Add(2100, 2200);
+
+ // Lots of different cases:
+ other.Add(50, 70); // disjoint, at the beginning
+ other.Add(2250, 2270); // disjoint, at the end
+ other.Add(650, 670); // disjoint, in the middle
+ other.Add(350, 360); // included
+ other.Add(370, 380); // also included (two at once)
+ other.Add(470, 530); // overlaps low end
+ other.Add(770, 830); // overlaps high end
+ other.Add(870, 900); // meets at low end
+ other.Add(1200, 1230); // meets at high end
+ other.Add(1270, 1830); // overlaps multiple ranges
+ }
+
+ virtual void TearDown() {
+ is.Clear();
+ EXPECT_TRUE(is.Empty());
+ other.Clear();
+ EXPECT_TRUE(other.Empty());
+ }
+ QuicIntervalSet<int> is;
+ QuicIntervalSet<int> other;
+};
+
+TEST_F(QuicIntervalSetTest, IsDisjoint) {
+ EXPECT_TRUE(is.IsDisjoint(QuicInterval<int>(0, 99)));
+ EXPECT_TRUE(is.IsDisjoint(QuicInterval<int>(0, 100)));
+ EXPECT_TRUE(is.IsDisjoint(QuicInterval<int>(200, 200)));
+ EXPECT_TRUE(is.IsDisjoint(QuicInterval<int>(200, 299)));
+ EXPECT_TRUE(is.IsDisjoint(QuicInterval<int>(400, 407)));
+ EXPECT_TRUE(is.IsDisjoint(QuicInterval<int>(405, 499)));
+ EXPECT_TRUE(is.IsDisjoint(QuicInterval<int>(2300, 2300)));
+ EXPECT_TRUE(
+ is.IsDisjoint(QuicInterval<int>(2300, std::numeric_limits<int>::max())));
+ EXPECT_FALSE(is.IsDisjoint(QuicInterval<int>(100, 105)));
+ EXPECT_FALSE(is.IsDisjoint(QuicInterval<int>(199, 300)));
+ EXPECT_FALSE(is.IsDisjoint(QuicInterval<int>(250, 450)));
+ EXPECT_FALSE(is.IsDisjoint(QuicInterval<int>(299, 400)));
+ EXPECT_FALSE(is.IsDisjoint(QuicInterval<int>(250, 2000)));
+ EXPECT_FALSE(
+ is.IsDisjoint(QuicInterval<int>(2199, std::numeric_limits<int>::max())));
+ // Empty intervals.
+ EXPECT_TRUE(is.IsDisjoint(QuicInterval<int>(90, 90)));
+ EXPECT_TRUE(is.IsDisjoint(QuicInterval<int>(100, 100)));
+ EXPECT_TRUE(is.IsDisjoint(QuicInterval<int>(100, 90)));
+ EXPECT_TRUE(is.IsDisjoint(QuicInterval<int>(150, 150)));
+ EXPECT_TRUE(is.IsDisjoint(QuicInterval<int>(200, 200)));
+ EXPECT_TRUE(is.IsDisjoint(QuicInterval<int>(400, 300)));
+}
+
+// Base helper method for verifying the contents of an interval set.
+// Returns true iff <is> contains <count> intervals whose successive
+// endpoints match the sequence of args in <ap>:
+static bool VA_Check(const QuicIntervalSet<int>& is, int count, va_list ap) {
+ std::vector<QuicInterval<int>> intervals(is.begin(), is.end());
+ if (count != static_cast<int>(intervals.size())) {
+ LOG(ERROR) << "Expected " << count << " intervals, got " << intervals.size()
+ << ": " << is;
+ return false;
+ }
+ if (count != static_cast<int>(is.Size())) {
+ LOG(ERROR) << "Expected " << count << " intervals, got Size " << is.Size()
+ << ": " << is;
+ return false;
+ }
+ bool result = true;
+ for (int i = 0; i < count; i++) {
+ int min = va_arg(ap, int);
+ int max = va_arg(ap, int);
+ if (min != intervals[i].min() || max != intervals[i].max()) {
+ LOG(ERROR) << "Expected: [" << min << ", " << max << ") got "
+ << intervals[i] << " in " << is;
+ result = false;
+ }
+ }
+ return result;
+}
+
+static bool Check(const QuicIntervalSet<int>& is, int count, ...) {
+ va_list ap;
+ va_start(ap, count);
+ const bool result = VA_Check(is, count, ap);
+ va_end(ap);
+ return result;
+}
+
+// Some helper functions for testing Contains and Find, which are logically the
+// same.
+static void TestContainsAndFind(const QuicIntervalSet<int>& is, int value) {
+ EXPECT_TRUE(is.Contains(value)) << "Set does not contain " << value;
+ auto it = is.Find(value);
+ EXPECT_NE(it, is.end()) << "No iterator to interval containing " << value;
+ EXPECT_TRUE(it->Contains(value)) << "Iterator does not contain " << value;
+}
+
+static void TestContainsAndFind(const QuicIntervalSet<int>& is,
+ int min,
+ int max) {
+ EXPECT_TRUE(is.Contains(min, max))
+ << "Set does not contain interval with min " << min << "and max " << max;
+ auto it = is.Find(min, max);
+ EXPECT_NE(it, is.end()) << "No iterator to interval with min " << min
+ << "and max " << max;
+ EXPECT_TRUE(it->Contains(QuicInterval<int>(min, max)))
+ << "Iterator does not contain interval with min " << min << "and max "
+ << max;
+}
+
+static void TestNotContainsAndFind(const QuicIntervalSet<int>& is, int value) {
+ EXPECT_FALSE(is.Contains(value)) << "Set contains " << value;
+ auto it = is.Find(value);
+ EXPECT_EQ(it, is.end()) << "There is iterator to interval containing "
+ << value;
+}
+
+static void TestNotContainsAndFind(const QuicIntervalSet<int>& is,
+ int min,
+ int max) {
+ EXPECT_FALSE(is.Contains(min, max))
+ << "Set contains interval with min " << min << "and max " << max;
+ auto it = is.Find(min, max);
+ EXPECT_EQ(it, is.end()) << "There is iterator to interval with min " << min
+ << "and max " << max;
+}
+
+TEST_F(QuicIntervalSetTest, QuicIntervalSetBasic) {
+ // Test Add, Get, Contains and Find
+ QuicIntervalSet<int> iset;
+ EXPECT_TRUE(iset.Empty());
+ EXPECT_EQ(0, iset.Size());
+ iset.Add(100, 200);
+ EXPECT_FALSE(iset.Empty());
+ EXPECT_EQ(1, iset.Size());
+ iset.Add(100, 150);
+ iset.Add(150, 200);
+ iset.Add(130, 170);
+ iset.Add(90, 150);
+ iset.Add(170, 220);
+ iset.Add(300, 400);
+ iset.Add(250, 450);
+ EXPECT_FALSE(iset.Empty());
+ EXPECT_EQ(2, iset.Size());
+ EXPECT_TRUE(Check(iset, 2, 90, 220, 250, 450));
+
+ // Test two intervals with a.max == b.min, that will just join up.
+ iset.Clear();
+ iset.Add(100, 200);
+ iset.Add(200, 300);
+ EXPECT_FALSE(iset.Empty());
+ EXPECT_EQ(1, iset.Size());
+ EXPECT_TRUE(Check(iset, 1, 100, 300));
+
+ // Test adding two sets together.
+ iset.Clear();
+ QuicIntervalSet<int> iset_add;
+ iset.Add(100, 200);
+ iset.Add(100, 150);
+ iset.Add(150, 200);
+ iset.Add(130, 170);
+ iset_add.Add(90, 150);
+ iset_add.Add(170, 220);
+ iset_add.Add(300, 400);
+ iset_add.Add(250, 450);
+
+ iset.Add(iset_add);
+ EXPECT_FALSE(iset.Empty());
+ EXPECT_EQ(2, iset.Size());
+ EXPECT_TRUE(Check(iset, 2, 90, 220, 250, 450));
+
+ // Test begin()/end(), and rbegin()/rend()
+ // to iterate over intervals.
+ {
+ std::vector<QuicInterval<int>> expected(iset.begin(), iset.end());
+
+ std::vector<QuicInterval<int>> actual1;
+ std::copy(iset.begin(), iset.end(), back_inserter(actual1));
+ ASSERT_EQ(expected.size(), actual1.size());
+
+ std::vector<QuicInterval<int>> actual2;
+ std::copy(iset.begin(), iset.end(), back_inserter(actual2));
+ ASSERT_EQ(expected.size(), actual2.size());
+
+ for (size_t i = 0; i < expected.size(); i++) {
+ EXPECT_EQ(expected[i].min(), actual1[i].min());
+ EXPECT_EQ(expected[i].max(), actual1[i].max());
+
+ EXPECT_EQ(expected[i].min(), actual2[i].min());
+ EXPECT_EQ(expected[i].max(), actual2[i].max());
+ }
+
+ // Ensure that the rbegin()/rend() iterators correctly yield the intervals
+ // in reverse order.
+ EXPECT_THAT(std::vector<QuicInterval<int>>(iset.rbegin(), iset.rend()),
+ ElementsAreArray(expected.rbegin(), expected.rend()));
+ }
+
+ TestNotContainsAndFind(iset, 89);
+ TestContainsAndFind(iset, 90);
+ TestContainsAndFind(iset, 120);
+ TestContainsAndFind(iset, 219);
+ TestNotContainsAndFind(iset, 220);
+ TestNotContainsAndFind(iset, 235);
+ TestNotContainsAndFind(iset, 249);
+ TestContainsAndFind(iset, 250);
+ TestContainsAndFind(iset, 300);
+ TestContainsAndFind(iset, 449);
+ TestNotContainsAndFind(iset, 450);
+ TestNotContainsAndFind(iset, 451);
+
+ TestNotContainsAndFind(iset, 50, 60);
+ TestNotContainsAndFind(iset, 50, 90);
+ TestNotContainsAndFind(iset, 50, 200);
+ TestNotContainsAndFind(iset, 90, 90);
+ TestContainsAndFind(iset, 90, 200);
+ TestContainsAndFind(iset, 100, 200);
+ TestContainsAndFind(iset, 100, 220);
+ TestNotContainsAndFind(iset, 100, 221);
+ TestNotContainsAndFind(iset, 220, 220);
+ TestNotContainsAndFind(iset, 240, 300);
+ TestContainsAndFind(iset, 250, 300);
+ TestContainsAndFind(iset, 260, 300);
+ TestContainsAndFind(iset, 300, 450);
+ TestNotContainsAndFind(iset, 300, 451);
+
+ QuicIntervalSet<int> iset_contains;
+ iset_contains.Add(50, 90);
+ EXPECT_FALSE(iset.Contains(iset_contains));
+ iset_contains.Clear();
+
+ iset_contains.Add(90, 200);
+ EXPECT_TRUE(iset.Contains(iset_contains));
+ iset_contains.Add(100, 200);
+ EXPECT_TRUE(iset.Contains(iset_contains));
+ iset_contains.Add(100, 220);
+ EXPECT_TRUE(iset.Contains(iset_contains));
+ iset_contains.Add(250, 300);
+ EXPECT_TRUE(iset.Contains(iset_contains));
+ iset_contains.Add(300, 450);
+ EXPECT_TRUE(iset.Contains(iset_contains));
+ iset_contains.Add(300, 451);
+ EXPECT_FALSE(iset.Contains(iset_contains));
+ EXPECT_FALSE(iset.Contains(QuicInterval<int>()));
+ EXPECT_FALSE(iset.Contains(QuicIntervalSet<int>()));
+}
+
+TEST_F(QuicIntervalSetTest, QuicIntervalSetContainsEmpty) {
+ const QuicIntervalSet<int> empty;
+ const QuicIntervalSet<int> other_empty;
+ const QuicIntervalSet<int> non_empty({{10, 20}, {40, 50}});
+ EXPECT_FALSE(empty.Contains(empty));
+ EXPECT_FALSE(empty.Contains(other_empty));
+ EXPECT_FALSE(empty.Contains(non_empty));
+ EXPECT_FALSE(non_empty.Contains(empty));
+}
+
+TEST_F(QuicIntervalSetTest, Equality) {
+ QuicIntervalSet<int> is_copy = is;
+ EXPECT_EQ(is, is);
+ EXPECT_EQ(is, is_copy);
+ EXPECT_NE(is, other);
+ EXPECT_NE(is, QuicIntervalSet<int>());
+ EXPECT_EQ(QuicIntervalSet<int>(), QuicIntervalSet<int>());
+}
+
+TEST_F(QuicIntervalSetTest, LowerAndUpperBound) {
+ QuicIntervalSet<int> intervals;
+ intervals.Add(10, 20);
+ intervals.Add(30, 40);
+
+ // [10, 20) [30, 40) end
+ // ^ LowerBound(5)
+ // ^ LowerBound(10)
+ // ^ LowerBound(15)
+ // ^ LowerBound(20)
+ // ^ LowerBound(25)
+ // ^ LowerBound(30)
+ // ^ LowerBound(35)
+ // ^ LowerBound(40)
+ // ^ LowerBound(50)
+ EXPECT_EQ(intervals.LowerBound(5)->min(), 10);
+ EXPECT_EQ(intervals.LowerBound(10)->min(), 10);
+ EXPECT_EQ(intervals.LowerBound(15)->min(), 10);
+ EXPECT_EQ(intervals.LowerBound(20)->min(), 30);
+ EXPECT_EQ(intervals.LowerBound(25)->min(), 30);
+ EXPECT_EQ(intervals.LowerBound(30)->min(), 30);
+ EXPECT_EQ(intervals.LowerBound(35)->min(), 30);
+ EXPECT_EQ(intervals.LowerBound(40), intervals.end());
+ EXPECT_EQ(intervals.LowerBound(50), intervals.end());
+
+ // [10, 20) [30, 40) end
+ // ^ UpperBound(5)
+ // ^ UpperBound(10)
+ // ^ UpperBound(15)
+ // ^ UpperBound(20)
+ // ^ UpperBound(25)
+ // ^ UpperBound(30)
+ // ^ UpperBound(35)
+ // ^ UpperBound(40)
+ // ^ UpperBound(50)
+ EXPECT_EQ(intervals.UpperBound(5)->min(), 10);
+ EXPECT_EQ(intervals.UpperBound(10)->min(), 30);
+ EXPECT_EQ(intervals.UpperBound(15)->min(), 30);
+ EXPECT_EQ(intervals.UpperBound(20)->min(), 30);
+ EXPECT_EQ(intervals.UpperBound(25)->min(), 30);
+ EXPECT_EQ(intervals.UpperBound(30), intervals.end());
+ EXPECT_EQ(intervals.UpperBound(35), intervals.end());
+ EXPECT_EQ(intervals.UpperBound(40), intervals.end());
+ EXPECT_EQ(intervals.UpperBound(50), intervals.end());
+}
+
+TEST_F(QuicIntervalSetTest, SpanningInterval) {
+ // Spanning interval of an empty set is empty:
+ {
+ QuicIntervalSet<int> iset;
+ const QuicInterval<int>& ival = iset.SpanningInterval();
+ EXPECT_TRUE(ival.Empty());
+ }
+
+ // Spanning interval of a set with one interval is that interval:
+ {
+ QuicIntervalSet<int> iset;
+ iset.Add(100, 200);
+ const QuicInterval<int>& ival = iset.SpanningInterval();
+ EXPECT_EQ(100, ival.min());
+ EXPECT_EQ(200, ival.max());
+ }
+
+ // Spanning interval of a set with multiple elements is determined
+ // by the endpoints of the first and last element:
+ {
+ const QuicInterval<int>& ival = is.SpanningInterval();
+ EXPECT_EQ(100, ival.min());
+ EXPECT_EQ(2200, ival.max());
+ }
+ {
+ const QuicInterval<int>& ival = other.SpanningInterval();
+ EXPECT_EQ(50, ival.min());
+ EXPECT_EQ(2270, ival.max());
+ }
+}
+
+TEST_F(QuicIntervalSetTest, QuicIntervalSetUnion) {
+ is.Union(other);
+ EXPECT_TRUE(Check(is, 12, 50, 70, 100, 200, 300, 400, 470, 600, 650, 670, 700,
+ 830, 870, 1000, 1100, 1230, 1270, 1830, 1900, 2000, 2100,
+ 2200, 2250, 2270));
+}
+
+TEST_F(QuicIntervalSetTest, QuicIntervalSetIntersection) {
+ EXPECT_TRUE(is.Intersects(other));
+ EXPECT_TRUE(other.Intersects(is));
+ is.Intersection(other);
+ EXPECT_TRUE(Check(is, 7, 350, 360, 370, 380, 500, 530, 770, 800, 1300, 1400,
+ 1500, 1600, 1700, 1800));
+ EXPECT_TRUE(is.Intersects(other));
+ EXPECT_TRUE(other.Intersects(is));
+}
+
+TEST_F(QuicIntervalSetTest, QuicIntervalSetIntersectionBothEmpty) {
+ QuicIntervalSet<string> mine, theirs;
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+ mine.Intersection(theirs);
+ EXPECT_TRUE(mine.Empty());
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+}
+
+TEST_F(QuicIntervalSetTest, QuicIntervalSetIntersectionEmptyMine) {
+ QuicIntervalSet<string> mine;
+ QuicIntervalSet<string> theirs("a", "b");
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+ mine.Intersection(theirs);
+ EXPECT_TRUE(mine.Empty());
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+}
+
+TEST_F(QuicIntervalSetTest, QuicIntervalSetIntersectionEmptyTheirs) {
+ QuicIntervalSet<string> mine("a", "b");
+ QuicIntervalSet<string> theirs;
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+ mine.Intersection(theirs);
+ EXPECT_TRUE(mine.Empty());
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+}
+
+TEST_F(QuicIntervalSetTest, QuicIntervalSetIntersectionTheirsBeforeMine) {
+ QuicIntervalSet<string> mine("y", "z");
+ QuicIntervalSet<string> theirs;
+ theirs.Add("a", "b");
+ theirs.Add("c", "d");
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+ mine.Intersection(theirs);
+ EXPECT_TRUE(mine.Empty());
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+}
+
+TEST_F(QuicIntervalSetTest, QuicIntervalSetIntersectionMineBeforeTheirs) {
+ QuicIntervalSet<string> mine;
+ mine.Add("a", "b");
+ mine.Add("c", "d");
+ QuicIntervalSet<string> theirs("y", "z");
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+ mine.Intersection(theirs);
+ EXPECT_TRUE(mine.Empty());
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+}
+
+TEST_F(QuicIntervalSetTest,
+ QuicIntervalSetIntersectionTheirsBeforeMineInt64Singletons) {
+ QuicIntervalSet<int64_t> mine({{10, 15}});
+ QuicIntervalSet<int64_t> theirs({{-20, -5}});
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+ mine.Intersection(theirs);
+ EXPECT_TRUE(mine.Empty());
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+}
+
+TEST_F(QuicIntervalSetTest,
+ QuicIntervalSetIntersectionMineBeforeTheirsIntSingletons) {
+ QuicIntervalSet<int> mine({{10, 15}});
+ QuicIntervalSet<int> theirs({{90, 95}});
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+ mine.Intersection(theirs);
+ EXPECT_TRUE(mine.Empty());
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+}
+
+TEST_F(QuicIntervalSetTest, QuicIntervalSetIntersectionTheirsBetweenMine) {
+ QuicIntervalSet<int64_t> mine({{0, 5}, {40, 50}});
+ QuicIntervalSet<int64_t> theirs({{10, 15}});
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+ mine.Intersection(theirs);
+ EXPECT_TRUE(mine.Empty());
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+}
+
+TEST_F(QuicIntervalSetTest, QuicIntervalSetIntersectionMineBetweenTheirs) {
+ QuicIntervalSet<int> mine({{20, 25}});
+ QuicIntervalSet<int> theirs({{10, 15}, {30, 32}});
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+ mine.Intersection(theirs);
+ EXPECT_TRUE(mine.Empty());
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+}
+
+TEST_F(QuicIntervalSetTest, QuicIntervalSetIntersectionAlternatingIntervals) {
+ QuicIntervalSet<int> mine, theirs;
+ mine.Add(10, 20);
+ mine.Add(40, 50);
+ mine.Add(60, 70);
+ theirs.Add(25, 39);
+ theirs.Add(55, 59);
+ theirs.Add(75, 79);
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+ mine.Intersection(theirs);
+ EXPECT_TRUE(mine.Empty());
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+}
+
+TEST_F(QuicIntervalSetTest,
+ QuicIntervalSetIntersectionAdjacentAlternatingNonIntersectingIntervals) {
+ // Make sure that intersection with adjacent interval set is empty.
+ const QuicIntervalSet<int> x1({{0, 10}});
+ const QuicIntervalSet<int> y1({{-50, 0}, {10, 95}});
+
+ QuicIntervalSet<int> result1 = x1;
+ result1.Intersection(y1);
+ EXPECT_TRUE(result1.Empty()) << result1;
+
+ const QuicIntervalSet<int16_t> x2({{0, 10}, {20, 30}, {40, 90}});
+ const QuicIntervalSet<int16_t> y2(
+ {{-50, -40}, {-2, 0}, {10, 20}, {32, 40}, {90, 95}});
+
+ QuicIntervalSet<int16_t> result2 = x2;
+ result2.Intersection(y2);
+ EXPECT_TRUE(result2.Empty()) << result2;
+
+ const QuicIntervalSet<int64_t> x3({{-1, 5}, {5, 10}});
+ const QuicIntervalSet<int64_t> y3({{-10, -1}, {10, 95}});
+
+ QuicIntervalSet<int64_t> result3 = x3;
+ result3.Intersection(y3);
+ EXPECT_TRUE(result3.Empty()) << result3;
+}
+
+TEST_F(QuicIntervalSetTest,
+ QuicIntervalSetIntersectionAlternatingIntersectingIntervals) {
+ const QuicIntervalSet<int> x1({{0, 10}});
+ const QuicIntervalSet<int> y1({{-50, 1}, {9, 95}});
+ const QuicIntervalSet<int> expected_result1({{0, 1}, {9, 10}});
+
+ QuicIntervalSet<int> result1 = x1;
+ result1.Intersection(y1);
+ EXPECT_EQ(result1, expected_result1);
+
+ const QuicIntervalSet<int16_t> x2({{0, 10}, {20, 30}, {40, 90}});
+ const QuicIntervalSet<int16_t> y2(
+ {{-50, -40}, {-2, 2}, {9, 21}, {32, 41}, {85, 95}});
+ const QuicIntervalSet<int16_t> expected_result2(
+ {{0, 2}, {9, 10}, {20, 21}, {40, 41}, {85, 90}});
+
+ QuicIntervalSet<int16_t> result2 = x2;
+ result2.Intersection(y2);
+ EXPECT_EQ(result2, expected_result2);
+
+ const QuicIntervalSet<int64_t> x3({{-1, 5}, {5, 10}});
+ const QuicIntervalSet<int64_t> y3({{-10, 3}, {4, 95}});
+ const QuicIntervalSet<int64_t> expected_result3({{-1, 3}, {4, 10}});
+
+ QuicIntervalSet<int64_t> result3 = x3;
+ result3.Intersection(y3);
+ EXPECT_EQ(result3, expected_result3);
+}
+
+TEST_F(QuicIntervalSetTest, QuicIntervalSetIntersectionIdentical) {
+ QuicIntervalSet<int> copy(is);
+ EXPECT_TRUE(copy.Intersects(is));
+ EXPECT_TRUE(is.Intersects(copy));
+ is.Intersection(copy);
+ EXPECT_EQ(copy, is);
+}
+
+TEST_F(QuicIntervalSetTest, QuicIntervalSetIntersectionSuperset) {
+ QuicIntervalSet<int> mine(-1, 10000);
+ EXPECT_TRUE(mine.Intersects(is));
+ EXPECT_TRUE(is.Intersects(mine));
+ mine.Intersection(is);
+ EXPECT_EQ(is, mine);
+}
+
+TEST_F(QuicIntervalSetTest, QuicIntervalSetIntersectionSubset) {
+ QuicIntervalSet<int> copy(is);
+ QuicIntervalSet<int> theirs(-1, 10000);
+ EXPECT_TRUE(copy.Intersects(theirs));
+ EXPECT_TRUE(theirs.Intersects(copy));
+ is.Intersection(theirs);
+ EXPECT_EQ(copy, is);
+}
+
+TEST_F(QuicIntervalSetTest, QuicIntervalSetIntersectionLargeSet) {
+ QuicIntervalSet<int> mine, theirs;
+ // mine: [0, 9), [10, 19), ..., [990, 999)
+ for (int i = 0; i < 1000; i += 10) {
+ mine.Add(i, i + 9);
+ }
+
+ theirs.Add(500, 520);
+ theirs.Add(535, 545);
+ theirs.Add(801, 809);
+ EXPECT_TRUE(mine.Intersects(theirs));
+ EXPECT_TRUE(theirs.Intersects(mine));
+ mine.Intersection(theirs);
+ EXPECT_TRUE(Check(mine, 5, 500, 509, 510, 519, 535, 539, 540, 545, 801, 809));
+ EXPECT_TRUE(mine.Intersects(theirs));
+ EXPECT_TRUE(theirs.Intersects(mine));
+}
+
+TEST_F(QuicIntervalSetTest, QuicIntervalSetDifference) {
+ is.Difference(other);
+ EXPECT_TRUE(Check(is, 10, 100, 200, 300, 350, 360, 370, 380, 400, 530, 600,
+ 700, 770, 900, 1000, 1100, 1200, 1900, 2000, 2100, 2200));
+ QuicIntervalSet<int> copy = is;
+ is.Difference(copy);
+ EXPECT_TRUE(is.Empty());
+}
+
+TEST_F(QuicIntervalSetTest, QuicIntervalSetDifferenceSingleBounds) {
+ std::vector<QuicInterval<int>> ivals(other.begin(), other.end());
+ for (const QuicInterval<int>& ival : ivals) {
+ is.Difference(ival.min(), ival.max());
+ }
+ EXPECT_TRUE(Check(is, 10, 100, 200, 300, 350, 360, 370, 380, 400, 530, 600,
+ 700, 770, 900, 1000, 1100, 1200, 1900, 2000, 2100, 2200));
+}
+
+TEST_F(QuicIntervalSetTest, QuicIntervalSetDifferenceSingleInterval) {
+ std::vector<QuicInterval<int>> ivals(other.begin(), other.end());
+ for (const QuicInterval<int>& ival : ivals) {
+ is.Difference(ival);
+ }
+ EXPECT_TRUE(Check(is, 10, 100, 200, 300, 350, 360, 370, 380, 400, 530, 600,
+ 700, 770, 900, 1000, 1100, 1200, 1900, 2000, 2100, 2200));
+}
+
+TEST_F(QuicIntervalSetTest, QuicIntervalSetDifferenceAlternatingIntervals) {
+ QuicIntervalSet<int> mine, theirs;
+ mine.Add(10, 20);
+ mine.Add(40, 50);
+ mine.Add(60, 70);
+ theirs.Add(25, 39);
+ theirs.Add(55, 59);
+ theirs.Add(75, 79);
+
+ mine.Difference(theirs);
+ EXPECT_TRUE(Check(mine, 3, 10, 20, 40, 50, 60, 70));
+}
+
+TEST_F(QuicIntervalSetTest, QuicIntervalSetDifferenceEmptyMine) {
+ QuicIntervalSet<string> mine, theirs;
+ theirs.Add("a", "b");
+
+ mine.Difference(theirs);
+ EXPECT_TRUE(mine.Empty());
+}
+
+TEST_F(QuicIntervalSetTest, QuicIntervalSetDifferenceEmptyTheirs) {
+ QuicIntervalSet<string> mine, theirs;
+ mine.Add("a", "b");
+
+ mine.Difference(theirs);
+ EXPECT_EQ(1, mine.Size());
+ EXPECT_EQ("a", mine.begin()->min());
+ EXPECT_EQ("b", mine.begin()->max());
+}
+
+TEST_F(QuicIntervalSetTest, QuicIntervalSetDifferenceTheirsBeforeMine) {
+ QuicIntervalSet<string> mine, theirs;
+ mine.Add("y", "z");
+ theirs.Add("a", "b");
+
+ mine.Difference(theirs);
+ EXPECT_EQ(1, mine.Size());
+ EXPECT_EQ("y", mine.begin()->min());
+ EXPECT_EQ("z", mine.begin()->max());
+}
+
+TEST_F(QuicIntervalSetTest, QuicIntervalSetDifferenceMineBeforeTheirs) {
+ QuicIntervalSet<string> mine, theirs;
+ mine.Add("a", "b");
+ theirs.Add("y", "z");
+
+ mine.Difference(theirs);
+ EXPECT_EQ(1, mine.Size());
+ EXPECT_EQ("a", mine.begin()->min());
+ EXPECT_EQ("b", mine.begin()->max());
+}
+
+TEST_F(QuicIntervalSetTest, QuicIntervalSetDifferenceIdentical) {
+ QuicIntervalSet<string> mine;
+ mine.Add("a", "b");
+ mine.Add("c", "d");
+ QuicIntervalSet<string> theirs(mine);
+
+ mine.Difference(theirs);
+ EXPECT_TRUE(mine.Empty());
+}
+
+TEST_F(QuicIntervalSetTest, EmptyComplement) {
+ // The complement of an empty set is the input interval:
+ QuicIntervalSet<int> iset;
+ iset.Complement(100, 200);
+ EXPECT_TRUE(Check(iset, 1, 100, 200));
+}
+
+TEST(QuicIntervalSetMultipleCompactionTest, OuterCovering) {
+ QuicIntervalSet<int> iset;
+ // First add a bunch of disjoint ranges
+ iset.Add(100, 150);
+ iset.Add(200, 250);
+ iset.Add(300, 350);
+ iset.Add(400, 450);
+ EXPECT_TRUE(Check(iset, 4, 100, 150, 200, 250, 300, 350, 400, 450));
+ // Now add a big range that covers all of these ranges
+ iset.Add(0, 500);
+ EXPECT_TRUE(Check(iset, 1, 0, 500));
+}
+
+TEST(QuicIntervalSetMultipleCompactionTest, InnerCovering) {
+ QuicIntervalSet<int> iset;
+ // First add a bunch of disjoint ranges
+ iset.Add(100, 150);
+ iset.Add(200, 250);
+ iset.Add(300, 350);
+ iset.Add(400, 450);
+ EXPECT_TRUE(Check(iset, 4, 100, 150, 200, 250, 300, 350, 400, 450));
+ // Now add a big range that partially covers the left and right most ranges.
+ iset.Add(125, 425);
+ EXPECT_TRUE(Check(iset, 1, 100, 450));
+}
+
+TEST(QuicIntervalSetMultipleCompactionTest, LeftCovering) {
+ QuicIntervalSet<int> iset;
+ // First add a bunch of disjoint ranges
+ iset.Add(100, 150);
+ iset.Add(200, 250);
+ iset.Add(300, 350);
+ iset.Add(400, 450);
+ EXPECT_TRUE(Check(iset, 4, 100, 150, 200, 250, 300, 350, 400, 450));
+ // Now add a big range that partially covers the left most range.
+ iset.Add(125, 500);
+ EXPECT_TRUE(Check(iset, 1, 100, 500));
+}
+
+TEST(QuicIntervalSetMultipleCompactionTest, RightCovering) {
+ QuicIntervalSet<int> iset;
+ // First add a bunch of disjoint ranges
+ iset.Add(100, 150);
+ iset.Add(200, 250);
+ iset.Add(300, 350);
+ iset.Add(400, 450);
+ EXPECT_TRUE(Check(iset, 4, 100, 150, 200, 250, 300, 350, 400, 450));
+ // Now add a big range that partially covers the right most range.
+ iset.Add(0, 425);
+ EXPECT_TRUE(Check(iset, 1, 0, 450));
+}
+
+// Helper method for testing and verifying the results of a one-interval
+// completement case.
+static bool CheckOneComplement(int add_min,
+ int add_max,
+ int comp_min,
+ int comp_max,
+ int count,
+ ...) {
+ QuicIntervalSet<int> iset;
+ iset.Add(add_min, add_max);
+ iset.Complement(comp_min, comp_max);
+ bool result = true;
+ va_list ap;
+ va_start(ap, count);
+ if (!VA_Check(iset, count, ap)) {
+ result = false;
+ }
+ va_end(ap);
+ return result;
+}
+
+TEST_F(QuicIntervalSetTest, SingleIntervalComplement) {
+ // Verify the complement of a set with one interval (i):
+ // |----- i -----|
+ // |----- args -----|
+ EXPECT_TRUE(CheckOneComplement(0, 10, 50, 150, 1, 50, 150));
+
+ // |----- i -----|
+ // |----- args -----|
+ EXPECT_TRUE(CheckOneComplement(50, 150, 0, 100, 1, 0, 50));
+
+ // |----- i -----|
+ // |----- args -----|
+ EXPECT_TRUE(CheckOneComplement(50, 150, 50, 150, 0));
+
+ // |---------- i ----------|
+ // |----- args -----|
+ EXPECT_TRUE(CheckOneComplement(50, 500, 100, 300, 0));
+
+ // |----- i -----|
+ // |---------- args ----------|
+ EXPECT_TRUE(CheckOneComplement(50, 500, 0, 800, 2, 0, 50, 500, 800));
+
+ // |----- i -----|
+ // |----- args -----|
+ EXPECT_TRUE(CheckOneComplement(50, 150, 100, 300, 1, 150, 300));
+
+ // |----- i -----|
+ // |----- args -----|
+ EXPECT_TRUE(CheckOneComplement(50, 150, 200, 300, 1, 200, 300));
+}
+
+// Helper method that copies <iset> and takes its complement,
+// returning false if Check succeeds.
+static bool CheckComplement(const QuicIntervalSet<int>& iset,
+ int comp_min,
+ int comp_max,
+ int count,
+ ...) {
+ QuicIntervalSet<int> iset_copy = iset;
+ iset_copy.Complement(comp_min, comp_max);
+ bool result = true;
+ va_list ap;
+ va_start(ap, count);
+ if (!VA_Check(iset_copy, count, ap)) {
+ result = false;
+ }
+ va_end(ap);
+ return result;
+}
+
+TEST_F(QuicIntervalSetTest, MultiIntervalComplement) {
+ // Initialize a small test set:
+ QuicIntervalSet<int> iset;
+ iset.Add(100, 200);
+ iset.Add(300, 400);
+ iset.Add(500, 600);
+
+ // |----- i -----|
+ // |----- comp -----|
+ EXPECT_TRUE(CheckComplement(iset, 0, 50, 1, 0, 50));
+
+ // |----- i -----|
+ // |----- comp -----|
+ EXPECT_TRUE(CheckComplement(iset, 0, 200, 1, 0, 100));
+ EXPECT_TRUE(CheckComplement(iset, 0, 220, 2, 0, 100, 200, 220));
+
+ // |----- i -----|
+ // |----- comp -----|
+ EXPECT_TRUE(CheckComplement(iset, 100, 600, 2, 200, 300, 400, 500));
+
+ // |---------- i ----------|
+ // |----- comp -----|
+ EXPECT_TRUE(CheckComplement(iset, 300, 400, 0));
+ EXPECT_TRUE(CheckComplement(iset, 250, 400, 1, 250, 300));
+ EXPECT_TRUE(CheckComplement(iset, 300, 450, 1, 400, 450));
+ EXPECT_TRUE(CheckComplement(iset, 250, 450, 2, 250, 300, 400, 450));
+
+ // |----- i -----|
+ // |---------- comp ----------|
+ EXPECT_TRUE(
+ CheckComplement(iset, 0, 700, 4, 0, 100, 200, 300, 400, 500, 600, 700));
+
+ // |----- i -----|
+ // |----- comp -----|
+ EXPECT_TRUE(CheckComplement(iset, 400, 700, 2, 400, 500, 600, 700));
+ EXPECT_TRUE(CheckComplement(iset, 350, 700, 2, 400, 500, 600, 700));
+
+ // |----- i -----|
+ // |----- comp -----|
+ EXPECT_TRUE(CheckComplement(iset, 700, 800, 1, 700, 800));
+}
+
+// Verifies ToString, operator<< don't assert.
+TEST_F(QuicIntervalSetTest, ToString) {
+ QuicIntervalSet<int> iset;
+ iset.Add(300, 400);
+ iset.Add(100, 200);
+ iset.Add(500, 600);
+ EXPECT_TRUE(!iset.ToString().empty());
+ QUIC_VLOG(2) << iset;
+ // Order and format of ToString() output is guaranteed.
+ EXPECT_EQ("{ [100, 200) [300, 400) [500, 600) }", iset.ToString());
+ EXPECT_EQ("{ [1, 2) }", QuicIntervalSet<int>(1, 2).ToString());
+ EXPECT_EQ("{ }", QuicIntervalSet<int>().ToString());
+}
+
+TEST_F(QuicIntervalSetTest, ConstructionDiscardsEmptyInterval) {
+ EXPECT_TRUE(QuicIntervalSet<int>(QuicInterval<int>(2, 2)).Empty());
+ EXPECT_TRUE(QuicIntervalSet<int>(2, 2).Empty());
+ EXPECT_FALSE(QuicIntervalSet<int>(QuicInterval<int>(2, 3)).Empty());
+ EXPECT_FALSE(QuicIntervalSet<int>(2, 3).Empty());
+}
+
+TEST_F(QuicIntervalSetTest, Swap) {
+ QuicIntervalSet<int> a, b;
+ a.Add(300, 400);
+ b.Add(100, 200);
+ b.Add(500, 600);
+ a.Swap(&b);
+ EXPECT_TRUE(Check(a, 2, 100, 200, 500, 600));
+ EXPECT_TRUE(Check(b, 1, 300, 400));
+ swap(a, b);
+ EXPECT_TRUE(Check(a, 1, 300, 400));
+ EXPECT_TRUE(Check(b, 2, 100, 200, 500, 600));
+}
+
+TEST_F(QuicIntervalSetTest, OutputReturnsOstreamRef) {
+ std::stringstream ss;
+ const QuicIntervalSet<int> v(QuicInterval<int>(1, 2));
+ auto return_type_is_a_ref = [](std::ostream&) {};
+ return_type_is_a_ref(ss << v);
+}
+
+struct NotOstreamable {
+ bool operator<(const NotOstreamable& other) const { return false; }
+ bool operator>(const NotOstreamable& other) const { return false; }
+ bool operator!=(const NotOstreamable& other) const { return false; }
+ bool operator>=(const NotOstreamable& other) const { return true; }
+ bool operator<=(const NotOstreamable& other) const { return true; }
+ bool operator==(const NotOstreamable& other) const { return true; }
+};
+
+TEST_F(QuicIntervalSetTest, IntervalOfTypeWithNoOstreamSupport) {
+ const NotOstreamable v;
+ const QuicIntervalSet<NotOstreamable> d(QuicInterval<NotOstreamable>(v, v));
+ // EXPECT_EQ builds a string representation of d. If d::operator<<()
+ // would be defined then this test would not compile because NotOstreamable
+ // objects lack the operator<<() support.
+ EXPECT_EQ(d, d);
+}
+
+class QuicIntervalSetInitTest : public QuicTest {
+ protected:
+ const std::vector<QuicInterval<int>> intervals_{{0, 1}, {2, 4}};
+};
+
+TEST_F(QuicIntervalSetInitTest, DirectInit) {
+ std::initializer_list<QuicInterval<int>> il = {{0, 1}, {2, 3}, {3, 4}};
+ QuicIntervalSet<int> s(il);
+ EXPECT_THAT(s, ElementsAreArray(intervals_));
+}
+
+TEST_F(QuicIntervalSetInitTest, CopyInit) {
+ std::initializer_list<QuicInterval<int>> il = {{0, 1}, {2, 3}, {3, 4}};
+ QuicIntervalSet<int> s = il;
+ EXPECT_THAT(s, ElementsAreArray(intervals_));
+}
+
+TEST_F(QuicIntervalSetInitTest, AssignIterPair) {
+ QuicIntervalSet<int> s(0, 1000); // Make sure assign clears.
+ s.assign(intervals_.begin(), intervals_.end());
+ EXPECT_THAT(s, ElementsAreArray(intervals_));
+}
+
+TEST_F(QuicIntervalSetInitTest, AssignInitList) {
+ QuicIntervalSet<int> s(0, 1000); // Make sure assign clears.
+ s.assign({{0, 1}, {2, 3}, {3, 4}});
+ EXPECT_THAT(s, ElementsAreArray(intervals_));
+}
+
+TEST_F(QuicIntervalSetInitTest, AssignmentInitList) {
+ std::initializer_list<QuicInterval<int>> il = {{0, 1}, {2, 3}, {3, 4}};
+ QuicIntervalSet<int> s;
+ s = il;
+ EXPECT_THAT(s, ElementsAreArray(intervals_));
+}
+
+TEST_F(QuicIntervalSetInitTest, BracedInitThenBracedAssign) {
+ QuicIntervalSet<int> s{{0, 1}, {2, 3}, {3, 4}};
+ s = {{0, 1}, {2, 4}};
+ EXPECT_THAT(s, ElementsAreArray(intervals_));
+}
+
+} // namespace
+} // namespace test
+} // namespace quic
diff --git a/quic/core/quic_interval_test.cc b/quic/core/quic_interval_test.cc
new file mode 100644
index 0000000..3cb134e
--- /dev/null
+++ b/quic/core/quic_interval_test.cc
@@ -0,0 +1,457 @@
+// 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_interval.h"
+
+#include <sstream>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include "net/third_party/quiche/src/quic/core/quic_time.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+
+namespace quic {
+namespace test {
+namespace {
+
+template <typename ForwardIterator>
+void STLDeleteContainerPointers(ForwardIterator begin, ForwardIterator end) {
+ while (begin != end) {
+ auto temp = begin;
+ ++begin;
+ delete *temp;
+ }
+}
+
+template <typename T>
+void STLDeleteElements(T* container) {
+ if (!container)
+ return;
+ STLDeleteContainerPointers(container->begin(), container->end());
+ container->clear();
+}
+
+class ConstructorListener {
+ public:
+ ConstructorListener(int* copy_construct_counter, int* move_construct_counter)
+ : copy_construct_counter_(copy_construct_counter),
+ move_construct_counter_(move_construct_counter) {
+ *copy_construct_counter_ = 0;
+ *move_construct_counter_ = 0;
+ }
+ ConstructorListener(const ConstructorListener& other) {
+ copy_construct_counter_ = other.copy_construct_counter_;
+ move_construct_counter_ = other.move_construct_counter_;
+ ++*copy_construct_counter_;
+ }
+ ConstructorListener(ConstructorListener&& other) {
+ copy_construct_counter_ = other.copy_construct_counter_;
+ move_construct_counter_ = other.move_construct_counter_;
+ ++*move_construct_counter_;
+ }
+ bool operator<(const ConstructorListener&) { return false; }
+ bool operator>(const ConstructorListener&) { return false; }
+ bool operator<=(const ConstructorListener&) { return true; }
+ bool operator>=(const ConstructorListener&) { return true; }
+ bool operator==(const ConstructorListener&) { return true; }
+
+ private:
+ int* copy_construct_counter_;
+ int* move_construct_counter_;
+};
+
+TEST(IntervalConstructorTest, Move) {
+ int object1_copy_count, object1_move_count;
+ ConstructorListener object1(&object1_copy_count, &object1_move_count);
+ int object2_copy_count, object2_move_count;
+ ConstructorListener object2(&object2_copy_count, &object2_move_count);
+
+ QuicInterval<ConstructorListener> interval(object1, std::move(object2));
+ EXPECT_EQ(1, object1_copy_count);
+ EXPECT_EQ(0, object1_move_count);
+ EXPECT_EQ(0, object2_copy_count);
+ EXPECT_EQ(1, object2_move_count);
+}
+
+TEST(IntervalConstructorTest, ImplicitConversion) {
+ struct WrappedInt {
+ WrappedInt(int value) : value(value) {}
+ bool operator<(const WrappedInt& other) { return value < other.value; }
+ bool operator>(const WrappedInt& other) { return value > other.value; }
+ bool operator<=(const WrappedInt& other) { return value <= other.value; }
+ bool operator>=(const WrappedInt& other) { return value >= other.value; }
+ bool operator==(const WrappedInt& other) { return value == other.value; }
+ int value;
+ };
+
+ static_assert(std::is_convertible<int, WrappedInt>::value, "");
+ static_assert(
+ std::is_constructible<QuicInterval<WrappedInt>, int, int>::value, "");
+
+ QuicInterval<WrappedInt> i(10, 20);
+ EXPECT_EQ(10, i.min().value);
+ EXPECT_EQ(20, i.max().value);
+}
+
+class IntervalTest : public QuicTest {
+ protected:
+ // Test intersection between the two intervals i1 and i2. Tries
+ // i1.IntersectWith(i2) and vice versa. The intersection should change i1 iff
+ // changes_i1 is true, and the same for changes_i2. The resulting
+ // intersection should be result.
+ void TestIntersect(const QuicInterval<int64_t>& i1,
+ const QuicInterval<int64_t>& i2,
+ bool changes_i1,
+ bool changes_i2,
+ const QuicInterval<int64_t>& result) {
+ QuicInterval<int64_t> i;
+ i = i1;
+ EXPECT_TRUE(i.IntersectWith(i2) == changes_i1 && i == result);
+ i = i2;
+ EXPECT_TRUE(i.IntersectWith(i1) == changes_i2 && i == result);
+ }
+};
+
+TEST_F(IntervalTest, ConstructorsCopyAndClear) {
+ QuicInterval<int32_t> empty;
+ EXPECT_TRUE(empty.Empty());
+
+ QuicInterval<int32_t> d2(0, 100);
+ EXPECT_EQ(0, d2.min());
+ EXPECT_EQ(100, d2.max());
+ EXPECT_EQ(QuicInterval<int32_t>(0, 100), d2);
+ EXPECT_NE(QuicInterval<int32_t>(0, 99), d2);
+
+ empty = d2;
+ EXPECT_EQ(0, d2.min());
+ EXPECT_EQ(100, d2.max());
+ EXPECT_TRUE(empty == d2);
+ EXPECT_EQ(empty, d2);
+ EXPECT_TRUE(d2 == empty);
+ EXPECT_EQ(d2, empty);
+
+ QuicInterval<int32_t> max_less_than_min(40, 20);
+ EXPECT_TRUE(max_less_than_min.Empty());
+ EXPECT_EQ(40, max_less_than_min.min());
+ EXPECT_EQ(20, max_less_than_min.max());
+
+ QuicInterval<int> d3(10, 20);
+ d3.Clear();
+ EXPECT_TRUE(d3.Empty());
+}
+
+TEST_F(IntervalTest, MakeQuicInterval) {
+ static_assert(
+ std::is_same<QuicInterval<int>, decltype(MakeQuicInterval(0, 3))>::value,
+ "Type is deduced incorrectly.");
+ static_assert(std::is_same<QuicInterval<double>,
+ decltype(MakeQuicInterval(0., 3.))>::value,
+ "Type is deduced incorrectly.");
+
+ EXPECT_EQ(MakeQuicInterval(0., 3.), QuicInterval<double>(0, 3));
+}
+
+TEST_F(IntervalTest, GettersSetters) {
+ QuicInterval<int32_t> d1(100, 200);
+
+ // SetMin:
+ d1.SetMin(30);
+ EXPECT_EQ(30, d1.min());
+ EXPECT_EQ(200, d1.max());
+
+ // SetMax:
+ d1.SetMax(220);
+ EXPECT_EQ(30, d1.min());
+ EXPECT_EQ(220, d1.max());
+
+ // Set:
+ d1.Clear();
+ d1.Set(30, 220);
+ EXPECT_EQ(30, d1.min());
+ EXPECT_EQ(220, d1.max());
+
+ // SpanningUnion:
+ QuicInterval<int32_t> d2;
+ EXPECT_TRUE(!d1.SpanningUnion(d2));
+ EXPECT_EQ(30, d1.min());
+ EXPECT_EQ(220, d1.max());
+
+ EXPECT_TRUE(d2.SpanningUnion(d1));
+ EXPECT_EQ(30, d2.min());
+ EXPECT_EQ(220, d2.max());
+
+ d2.SetMin(40);
+ d2.SetMax(100);
+ EXPECT_TRUE(!d1.SpanningUnion(d2));
+ EXPECT_EQ(30, d1.min());
+ EXPECT_EQ(220, d1.max());
+
+ d2.SetMin(20);
+ d2.SetMax(100);
+ EXPECT_TRUE(d1.SpanningUnion(d2));
+ EXPECT_EQ(20, d1.min());
+ EXPECT_EQ(220, d1.max());
+
+ d2.SetMin(50);
+ d2.SetMax(300);
+ EXPECT_TRUE(d1.SpanningUnion(d2));
+ EXPECT_EQ(20, d1.min());
+ EXPECT_EQ(300, d1.max());
+
+ d2.SetMin(0);
+ d2.SetMax(500);
+ EXPECT_TRUE(d1.SpanningUnion(d2));
+ EXPECT_EQ(0, d1.min());
+ EXPECT_EQ(500, d1.max());
+
+ d2.SetMin(100);
+ d2.SetMax(0);
+ EXPECT_TRUE(!d1.SpanningUnion(d2));
+ EXPECT_EQ(0, d1.min());
+ EXPECT_EQ(500, d1.max());
+ EXPECT_TRUE(d2.SpanningUnion(d1));
+ EXPECT_EQ(0, d2.min());
+ EXPECT_EQ(500, d2.max());
+}
+
+TEST_F(IntervalTest, CoveringOps) {
+ const QuicInterval<int64_t> empty;
+ const QuicInterval<int64_t> d(100, 200);
+ const QuicInterval<int64_t> d1(0, 50);
+ const QuicInterval<int64_t> d2(50, 110);
+ const QuicInterval<int64_t> d3(110, 180);
+ const QuicInterval<int64_t> d4(180, 220);
+ const QuicInterval<int64_t> d5(220, 300);
+ const QuicInterval<int64_t> d6(100, 150);
+ const QuicInterval<int64_t> d7(150, 200);
+ const QuicInterval<int64_t> d8(0, 300);
+
+ // Intersection:
+ EXPECT_TRUE(d.Intersects(d));
+ EXPECT_TRUE(!empty.Intersects(d) && !d.Intersects(empty));
+ EXPECT_TRUE(!d.Intersects(d1) && !d1.Intersects(d));
+ EXPECT_TRUE(d.Intersects(d2) && d2.Intersects(d));
+ EXPECT_TRUE(d.Intersects(d3) && d3.Intersects(d));
+ EXPECT_TRUE(d.Intersects(d4) && d4.Intersects(d));
+ EXPECT_TRUE(!d.Intersects(d5) && !d5.Intersects(d));
+ EXPECT_TRUE(d.Intersects(d6) && d6.Intersects(d));
+ EXPECT_TRUE(d.Intersects(d7) && d7.Intersects(d));
+ EXPECT_TRUE(d.Intersects(d8) && d8.Intersects(d));
+
+ QuicInterval<int64_t> i;
+ EXPECT_TRUE(d.Intersects(d, &i) && d == i);
+ EXPECT_TRUE(!empty.Intersects(d, nullptr) && !d.Intersects(empty, nullptr));
+ EXPECT_TRUE(!d.Intersects(d1, nullptr) && !d1.Intersects(d, nullptr));
+ EXPECT_TRUE(d.Intersects(d2, &i) && i == QuicInterval<int64_t>(100, 110));
+ EXPECT_TRUE(d2.Intersects(d, &i) && i == QuicInterval<int64_t>(100, 110));
+ EXPECT_TRUE(d.Intersects(d3, &i) && i == d3);
+ EXPECT_TRUE(d3.Intersects(d, &i) && i == d3);
+ EXPECT_TRUE(d.Intersects(d4, &i) && i == QuicInterval<int64_t>(180, 200));
+ EXPECT_TRUE(d4.Intersects(d, &i) && i == QuicInterval<int64_t>(180, 200));
+ EXPECT_TRUE(!d.Intersects(d5, nullptr) && !d5.Intersects(d, nullptr));
+ EXPECT_TRUE(d.Intersects(d6, &i) && i == d6);
+ EXPECT_TRUE(d6.Intersects(d, &i) && i == d6);
+ EXPECT_TRUE(d.Intersects(d7, &i) && i == d7);
+ EXPECT_TRUE(d7.Intersects(d, &i) && i == d7);
+ EXPECT_TRUE(d.Intersects(d8, &i) && i == d);
+ EXPECT_TRUE(d8.Intersects(d, &i) && i == d);
+
+ // Test IntersectsWith().
+ // Arguments are TestIntersect(i1, i2, changes_i1, changes_i2, result).
+ TestIntersect(empty, d, false, true, empty);
+ TestIntersect(d, d1, true, true, empty);
+ TestIntersect(d1, d2, true, true, empty);
+ TestIntersect(d, d2, true, true, QuicInterval<int64_t>(100, 110));
+ TestIntersect(d8, d, true, false, d);
+ TestIntersect(d8, d1, true, false, d1);
+ TestIntersect(d8, d5, true, false, d5);
+
+ // Contains:
+ EXPECT_TRUE(!empty.Contains(d) && !d.Contains(empty));
+ EXPECT_TRUE(d.Contains(d));
+ EXPECT_TRUE(!d.Contains(d1) && !d1.Contains(d));
+ EXPECT_TRUE(!d.Contains(d2) && !d2.Contains(d));
+ EXPECT_TRUE(d.Contains(d3) && !d3.Contains(d));
+ EXPECT_TRUE(!d.Contains(d4) && !d4.Contains(d));
+ EXPECT_TRUE(!d.Contains(d5) && !d5.Contains(d));
+ EXPECT_TRUE(d.Contains(d6) && !d6.Contains(d));
+ EXPECT_TRUE(d.Contains(d7) && !d7.Contains(d));
+ EXPECT_TRUE(!d.Contains(d8) && d8.Contains(d));
+
+ EXPECT_TRUE(d.Contains(100));
+ EXPECT_TRUE(!d.Contains(200));
+ EXPECT_TRUE(d.Contains(150));
+ EXPECT_TRUE(!d.Contains(99));
+ EXPECT_TRUE(!d.Contains(201));
+
+ // Difference:
+ std::vector<QuicInterval<int64_t>*> diff;
+
+ EXPECT_TRUE(!d.Difference(empty, &diff));
+ EXPECT_EQ(1, diff.size());
+ EXPECT_EQ(100, diff[0]->min());
+ EXPECT_EQ(200, diff[0]->max());
+ STLDeleteElements(&diff);
+ EXPECT_TRUE(!empty.Difference(d, &diff) && diff.empty());
+
+ EXPECT_TRUE(d.Difference(d, &diff) && diff.empty());
+ EXPECT_TRUE(!d.Difference(d1, &diff));
+ EXPECT_EQ(1, diff.size());
+ EXPECT_EQ(100, diff[0]->min());
+ EXPECT_EQ(200, diff[0]->max());
+ STLDeleteElements(&diff);
+
+ QuicInterval<int64_t> lo;
+ QuicInterval<int64_t> hi;
+
+ EXPECT_TRUE(d.Difference(d2, &lo, &hi));
+ EXPECT_TRUE(lo.Empty());
+ EXPECT_EQ(110, hi.min());
+ EXPECT_EQ(200, hi.max());
+ EXPECT_TRUE(d.Difference(d2, &diff));
+ EXPECT_EQ(1, diff.size());
+ EXPECT_EQ(110, diff[0]->min());
+ EXPECT_EQ(200, diff[0]->max());
+ STLDeleteElements(&diff);
+
+ EXPECT_TRUE(d.Difference(d3, &lo, &hi));
+ EXPECT_EQ(100, lo.min());
+ EXPECT_EQ(110, lo.max());
+ EXPECT_EQ(180, hi.min());
+ EXPECT_EQ(200, hi.max());
+ EXPECT_TRUE(d.Difference(d3, &diff));
+ EXPECT_EQ(2, diff.size());
+ EXPECT_EQ(100, diff[0]->min());
+ EXPECT_EQ(110, diff[0]->max());
+ EXPECT_EQ(180, diff[1]->min());
+ EXPECT_EQ(200, diff[1]->max());
+ STLDeleteElements(&diff);
+
+ EXPECT_TRUE(d.Difference(d4, &lo, &hi));
+ EXPECT_EQ(100, lo.min());
+ EXPECT_EQ(180, lo.max());
+ EXPECT_TRUE(hi.Empty());
+ EXPECT_TRUE(d.Difference(d4, &diff));
+ EXPECT_EQ(1, diff.size());
+ EXPECT_EQ(100, diff[0]->min());
+ EXPECT_EQ(180, diff[0]->max());
+ STLDeleteElements(&diff);
+
+ EXPECT_FALSE(d.Difference(d5, &lo, &hi));
+ EXPECT_EQ(100, lo.min());
+ EXPECT_EQ(200, lo.max());
+ EXPECT_TRUE(hi.Empty());
+ EXPECT_FALSE(d.Difference(d5, &diff));
+ EXPECT_EQ(1, diff.size());
+ EXPECT_EQ(100, diff[0]->min());
+ EXPECT_EQ(200, diff[0]->max());
+ STLDeleteElements(&diff);
+
+ EXPECT_TRUE(d.Difference(d6, &lo, &hi));
+ EXPECT_TRUE(lo.Empty());
+ EXPECT_EQ(150, hi.min());
+ EXPECT_EQ(200, hi.max());
+ EXPECT_TRUE(d.Difference(d6, &diff));
+ EXPECT_EQ(1, diff.size());
+ EXPECT_EQ(150, diff[0]->min());
+ EXPECT_EQ(200, diff[0]->max());
+ STLDeleteElements(&diff);
+
+ EXPECT_TRUE(d.Difference(d7, &lo, &hi));
+ EXPECT_EQ(100, lo.min());
+ EXPECT_EQ(150, lo.max());
+ EXPECT_TRUE(hi.Empty());
+ EXPECT_TRUE(d.Difference(d7, &diff));
+ EXPECT_EQ(1, diff.size());
+ EXPECT_EQ(100, diff[0]->min());
+ EXPECT_EQ(150, diff[0]->max());
+ STLDeleteElements(&diff);
+
+ EXPECT_TRUE(d.Difference(d8, &lo, &hi));
+ EXPECT_TRUE(lo.Empty());
+ EXPECT_TRUE(hi.Empty());
+ EXPECT_TRUE(d.Difference(d8, &diff) && diff.empty());
+}
+
+TEST_F(IntervalTest, Length) {
+ const QuicInterval<int> empty1;
+ const QuicInterval<int> empty2(1, 1);
+ const QuicInterval<int> empty3(1, 0);
+ const QuicInterval<QuicTime> empty4(
+ QuicTime::Zero() + QuicTime::Delta::FromSeconds(1), QuicTime::Zero());
+ const QuicInterval<int> d1(1, 2);
+ const QuicInterval<int> d2(0, 50);
+ const QuicInterval<QuicTime> d3(
+ QuicTime::Zero(), QuicTime::Zero() + QuicTime::Delta::FromSeconds(1));
+ const QuicInterval<QuicTime> d4(
+ QuicTime::Zero() + QuicTime::Delta::FromSeconds(3600),
+ QuicTime::Zero() + QuicTime::Delta::FromSeconds(5400));
+
+ EXPECT_EQ(0, empty1.Length());
+ EXPECT_EQ(0, empty2.Length());
+ EXPECT_EQ(0, empty3.Length());
+ EXPECT_EQ(QuicTime::Delta::Zero(), empty4.Length());
+ EXPECT_EQ(1, d1.Length());
+ EXPECT_EQ(50, d2.Length());
+ EXPECT_EQ(QuicTime::Delta::FromSeconds(1), d3.Length());
+ EXPECT_EQ(QuicTime::Delta::FromSeconds(1800), d4.Length());
+}
+
+TEST_F(IntervalTest, IntervalOfTypeWithNoOperatorMinus) {
+ // QuicInterval<T> should work even if T does not support operator-(). We
+ // just can't call QuicInterval<T>::Length() for such types.
+ const QuicInterval<string> d1("a", "b");
+ const QuicInterval<std::pair<int, int>> d2({1, 2}, {4, 3});
+ EXPECT_EQ("a", d1.min());
+ EXPECT_EQ("b", d1.max());
+ EXPECT_EQ(std::make_pair(1, 2), d2.min());
+ EXPECT_EQ(std::make_pair(4, 3), d2.max());
+}
+
+struct NoEquals {
+ NoEquals(int v) : value(v) {} // NOLINT
+ int value;
+ bool operator<(const NoEquals& other) const { return value < other.value; }
+};
+
+TEST_F(IntervalTest, OrderedComparisonForTypeWithoutEquals) {
+ const QuicInterval<NoEquals> d1(0, 4);
+ const QuicInterval<NoEquals> d2(0, 3);
+ const QuicInterval<NoEquals> d3(1, 4);
+ const QuicInterval<NoEquals> d4(1, 5);
+ const QuicInterval<NoEquals> d6(0, 4);
+ EXPECT_TRUE(d1 < d2);
+ EXPECT_TRUE(d1 < d3);
+ EXPECT_TRUE(d1 < d4);
+ EXPECT_FALSE(d1 < d6);
+}
+
+TEST_F(IntervalTest, OutputReturnsOstreamRef) {
+ std::stringstream ss;
+ const QuicInterval<int> v(1, 2);
+ // If (ss << v) were to return a value, it wouldn't match the signature of
+ // return_type_is_a_ref() function.
+ auto return_type_is_a_ref = [](std::ostream&) {};
+ return_type_is_a_ref(ss << v);
+}
+
+struct NotOstreamable {
+ bool operator<(const NotOstreamable& other) const { return false; }
+ bool operator>=(const NotOstreamable& other) const { return true; }
+ bool operator==(const NotOstreamable& other) const { return true; }
+};
+
+TEST_F(IntervalTest, IntervalOfTypeWithNoOstreamSupport) {
+ const NotOstreamable v;
+ const QuicInterval<NotOstreamable> d(v, v);
+ // EXPECT_EQ builds a string representation of d. If d::operator<<() would be
+ // defined then this test would not compile because NotOstreamable objects
+ // lack the operator<<() support.
+ EXPECT_EQ(d, d);
+}
+
+} // namespace
+} // namespace test
+} // namespace quic
diff --git a/quic/core/quic_packet_creator.cc b/quic/core/quic_packet_creator.cc
index cc4f50e..6ad5351 100644
--- a/quic/core/quic_packet_creator.cc
+++ b/quic/core/quic_packet_creator.cc
@@ -21,8 +21,29 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
namespace quic {
+namespace {
+
+QuicLongHeaderType EncryptionlevelToLongHeaderType(EncryptionLevel level) {
+ switch (level) {
+ case ENCRYPTION_NONE:
+ return INITIAL;
+ case ENCRYPTION_ZERO_RTT:
+ return ZERO_RTT_PROTECTED;
+ case ENCRYPTION_FORWARD_SECURE:
+ QUIC_BUG
+ << "Try to derive long header type for packet with encryption level: "
+ << QuicUtils::EncryptionLevelToString(level);
+ return INVALID_PACKET_TYPE;
+ default:
+ QUIC_BUG << QuicUtils::EncryptionLevelToString(level);
+ return INVALID_PACKET_TYPE;
+ }
+}
+
+} // namespace
#define ENDPOINT \
(framer_->perspective() == Perspective::IS_SERVER ? "Server: " : "Client: ")
@@ -60,7 +81,9 @@
needs_full_padding_(false),
can_set_transmission_type_(false),
set_transmission_type_for_next_frame_(
- GetQuicReloadableFlag(quic_set_transmission_type_for_next_frame)) {
+ GetQuicReloadableFlag(quic_set_transmission_type_for_next_frame)),
+ encryption_level_driven_long_header_type_(
+ GetQuicReloadableFlag(quic_encryption_driven_header_type)) {
SetMaxPacketLength(kDefaultMaxPacketSize);
}
@@ -132,6 +155,25 @@
framer_->transport_version(), QuicPacketNumber(delta * 4));
}
+bool QuicPacketCreator::ConsumeCryptoData(EncryptionLevel level,
+ size_t write_length,
+ QuicStreamOffset offset,
+ TransmissionType transmission_type,
+ QuicFrame* frame) {
+ if (!CreateCryptoFrame(level, write_length, offset, frame)) {
+ return false;
+ }
+ // When crypto data was sent in stream frames, ConsumeData is called with
+ // |needs_full_padding = true|. Keep the same behavior here when sending
+ // crypto frames.
+ //
+ // TODO(nharper): Check what the IETF drafts say about padding out initial
+ // messages and change this as appropriate.
+ needs_full_padding_ = true;
+ return AddFrame(*frame, /*save_retransmittable_frames*/ true,
+ transmission_type);
+}
+
bool QuicPacketCreator::ConsumeData(QuicStreamId id,
size_t write_length,
size_t iov_offset,
@@ -190,7 +232,7 @@
// this information, leading to a cascade of changes and B) the
// higher-up software does not always loop, calling
// StreamFramePacketOverhead() once for every packet -- eg there is
-// a test in quic_connetion_test that calls it once and assumes that
+// a test in quic_connection_test that calls it once and assumes that
// the value is the same for all packets.
// static
@@ -201,13 +243,16 @@
bool include_version,
bool include_diversification_nonce,
QuicPacketNumberLength packet_number_length,
+ QuicVariableLengthIntegerLength retry_token_length_length,
+ QuicVariableLengthIntegerLength length_length,
QuicStreamOffset offset) {
return GetPacketHeaderSize(version, destination_connection_id_length,
source_connection_id_length, include_version,
include_diversification_nonce,
- packet_number_length) +
+ packet_number_length, retry_token_length_length, 0,
+ length_length) +
- // Assumes this is packet with a aingle stream frame in it. Since
+ // Assumes this is a packet with a single stream frame in it. Since
// last_frame_in_packet is set true, the size of the length field is
// not included in the calculation. This is OK because in other places
// in the code, the logic adds back 2 (the size of the Google QUIC
@@ -236,7 +281,8 @@
StreamFramePacketOverhead(
framer_->transport_version(), GetDestinationConnectionIdLength(),
GetSourceConnectionIdLength(), kIncludeVersion,
- IncludeNonceInPublicHeader(), PACKET_6BYTE_PACKET_NUMBER, offset));
+ IncludeNonceInPublicHeader(), PACKET_6BYTE_PACKET_NUMBER,
+ GetRetryTokenLengthLength(), GetLengthLength(), offset));
QUIC_BUG_IF(!HasRoomForStreamFrame(id, offset, data_size))
<< "No room for Stream frame, BytesFree: " << BytesFree()
@@ -261,6 +307,21 @@
*frame = QuicFrame(QuicStreamFrame(id, set_fin, offset, bytes_consumed));
}
+bool QuicPacketCreator::CreateCryptoFrame(EncryptionLevel level,
+ size_t write_length,
+ QuicStreamOffset offset,
+ QuicFrame* frame) {
+ size_t min_frame_size =
+ QuicFramer::GetMinCryptoFrameSize(write_length, offset);
+ if (BytesFree() <= min_frame_size) {
+ return false;
+ }
+ size_t max_write_length = BytesFree() - min_frame_size;
+ size_t bytes_consumed = std::min<size_t>(max_write_length, write_length);
+ *frame = QuicFrame(new QuicCryptoFrame(level, offset, bytes_consumed));
+ return true;
+}
+
void QuicPacketCreator::ReserializeAllFrames(
const QuicPendingRetransmission& retransmission,
char* buffer,
@@ -369,9 +430,9 @@
encrypted_buffer = stack_buffer;
}
- QuicDataWriter writer(kMaxPacketSize, encrypted_buffer,
- framer_->endianness());
- if (!framer_->AppendPacketHeader(header, &writer)) {
+ QuicDataWriter writer(kMaxPacketSize, encrypted_buffer);
+ size_t length_field_offset = 0;
+ if (!framer_->AppendPacketHeader(header, &writer, &length_field_offset)) {
QUIC_BUG << "AppendPacketHeader failed";
return;
}
@@ -405,6 +466,11 @@
return;
}
+ if (!framer_->WriteIetfLongHeaderLength(header, &writer, length_field_offset,
+ packet_.encryption_level)) {
+ return;
+ }
+
if (ShouldSetTransmissionTypeForNextFrame()) {
QUIC_RELOADABLE_FLAG_COUNT_N(quic_set_transmission_type_for_next_frame, 1,
2);
@@ -453,7 +519,7 @@
!queued_frames_.empty() && queued_frames_.back().type == MESSAGE_FRAME;
if (has_trailing_message_frame) {
return QuicDataWriter::GetVarInt62Len(
- queued_frames_.back().message_frame->message_data.length());
+ queued_frames_.back().message_frame->message_length);
}
// If the last frame in the packet is a stream frame, then it will expand to
// include the stream_length field when a new frame is added.
@@ -482,7 +548,8 @@
packet_size_ = GetPacketHeaderSize(
framer_->transport_version(), GetDestinationConnectionIdLength(),
GetSourceConnectionIdLength(), IncludeVersionInHeader(),
- IncludeNonceInPublicHeader(), GetPacketNumberLength());
+ IncludeNonceInPublicHeader(), GetPacketNumberLength(),
+ GetRetryTokenLengthLength(), GetRetryToken().length(), GetLengthLength());
return packet_size_;
}
@@ -517,8 +584,9 @@
DCHECK_GE(max_plaintext_size_, packet_size_);
// Use the packet_size_ instead of the buffer size to ensure smaller
// packet sizes are properly used.
- size_t length = framer_->BuildDataPacket(header, queued_frames_,
- encrypted_buffer, packet_size_);
+ size_t length =
+ framer_->BuildDataPacket(header, queued_frames_, encrypted_buffer,
+ packet_size_, packet_.encryption_level);
if (length == 0) {
QUIC_BUG << "Failed to serialize " << queued_frames_.size() << " frames.";
return;
@@ -573,8 +641,8 @@
FillPacketHeader(&header);
std::unique_ptr<char[]> buffer(new char[kMaxPacketSize]);
- size_t length = framer_->BuildConnectivityProbingPacket(header, buffer.get(),
- max_plaintext_size_);
+ size_t length = framer_->BuildConnectivityProbingPacket(
+ header, buffer.get(), max_plaintext_size_, packet_.encryption_level);
DCHECK(length);
const size_t encrypted_length = framer_->EncryptInPlace(
@@ -606,7 +674,8 @@
std::unique_ptr<char[]> buffer(new char[kMaxPacketSize]);
size_t length = framer_->BuildPaddedPathChallengePacket(
- header, buffer.get(), max_plaintext_size_, payload, random_);
+ header, buffer.get(), max_plaintext_size_, payload, random_,
+ packet_.encryption_level);
DCHECK(length);
const size_t encrypted_length = framer_->EncryptInPlace(
@@ -639,7 +708,8 @@
std::unique_ptr<char[]> buffer(new char[kMaxPacketSize]);
size_t length = framer_->BuildPathResponsePacket(
- header, buffer.get(), max_plaintext_size_, payloads, is_padded);
+ header, buffer.get(), max_plaintext_size_, payloads, is_padded,
+ packet_.encryption_level);
DCHECK(length);
const size_t encrypted_length = framer_->EncryptInPlace(
@@ -691,6 +761,41 @@
return packet_.packet_number_length;
}
+QuicLongHeaderType QuicPacketCreator::GetLongHeaderType() const {
+ return (encryption_level_driven_long_header_type_
+ ? EncryptionlevelToLongHeaderType(packet_.encryption_level)
+ : long_header_type_);
+}
+
+QuicVariableLengthIntegerLength QuicPacketCreator::GetRetryTokenLengthLength()
+ const {
+ if (QuicVersionHasLongHeaderLengths(framer_->transport_version()) &&
+ HasIetfLongHeader() && GetLongHeaderType() == INITIAL) {
+ return QuicDataWriter::GetVarInt62Len(GetRetryToken().length());
+ }
+ return VARIABLE_LENGTH_INTEGER_LENGTH_0;
+}
+
+QuicStringPiece QuicPacketCreator::GetRetryToken() const {
+ return retry_token_;
+}
+
+void QuicPacketCreator::SetRetryToken(QuicStringPiece retry_token) {
+ retry_token_ = QuicString(retry_token);
+}
+
+QuicVariableLengthIntegerLength QuicPacketCreator::GetLengthLength() const {
+ if (QuicVersionHasLongHeaderLengths(framer_->transport_version()) &&
+ HasIetfLongHeader()) {
+ QuicLongHeaderType long_header_type = GetLongHeaderType();
+ if (long_header_type == INITIAL || long_header_type == ZERO_RTT_PROTECTED ||
+ long_header_type == HANDSHAKE) {
+ return VARIABLE_LENGTH_INTEGER_LENGTH_2;
+ }
+ }
+ return VARIABLE_LENGTH_INTEGER_LENGTH_0;
+}
+
void QuicPacketCreator::FillPacketHeader(QuicPacketHeader* header) {
header->destination_connection_id = connection_id_;
header->destination_connection_id_length = GetDestinationConnectionIdLength();
@@ -711,10 +816,14 @@
}
header->packet_number = packet_.packet_number;
header->packet_number_length = GetPacketNumberLength();
+ header->retry_token_length_length = GetRetryTokenLengthLength();
+ header->retry_token = GetRetryToken();
+ header->length_length = GetLengthLength();
+ header->remaining_packet_length = 0;
if (!HasIetfLongHeader()) {
return;
}
- header->long_packet_type = long_header_type_;
+ header->long_packet_type = GetLongHeaderType();
}
bool QuicPacketCreator::AddFrame(const QuicFrame& frame,
@@ -753,9 +862,7 @@
}
packet_.retransmittable_frames.push_back(frame);
queued_frames_.push_back(frame);
- if (frame.type == STREAM_FRAME &&
- frame.stream_frame.stream_id ==
- QuicUtils::GetCryptoStreamId(framer_->transport_version())) {
+ if (QuicUtils::IsHandshakeFrame(frame, framer_->transport_version())) {
packet_.has_crypto_handshake = IS_HANDSHAKE;
}
} else {
@@ -819,7 +926,7 @@
bool QuicPacketCreator::IncludeNonceInPublicHeader() const {
return have_diversification_nonce_ &&
- packet_.encryption_level == ENCRYPTION_INITIAL;
+ packet_.encryption_level == ENCRYPTION_ZERO_RTT;
}
bool QuicPacketCreator::IncludeVersionInHeader() const {
@@ -873,7 +980,8 @@
const size_t packet_header_size = GetPacketHeaderSize(
framer_->transport_version(), GetDestinationConnectionIdLength(),
GetSourceConnectionIdLength(), IncludeVersionInHeader(),
- IncludeNonceInPublicHeader(), GetPacketNumberLength());
+ IncludeNonceInPublicHeader(), GetPacketNumberLength(),
+ GetRetryTokenLengthLength(), GetRetryToken().length(), GetLengthLength());
// This is the largest possible message payload when the length field is
// omitted.
return max_plaintext_size_ -
diff --git a/quic/core/quic_packet_creator.h b/quic/core/quic_packet_creator.h
index ef4fa37..c159026 100644
--- a/quic/core/quic_packet_creator.h
+++ b/quic/core/quic_packet_creator.h
@@ -88,6 +88,8 @@
bool include_version,
bool include_diversification_nonce,
QuicPacketNumberLength packet_number_length,
+ QuicVariableLengthIntegerLength retry_token_length_length,
+ QuicVariableLengthIntegerLength length_length,
QuicStreamOffset offset);
// Returns false and flushes all pending frames if current open packet is
@@ -103,13 +105,21 @@
TransmissionType transmission_type,
QuicFrame* frame);
+ // Creates a CRYPTO frame that fits into the current packet (which must be
+ // empty) and adds it to the packet.
+ bool ConsumeCryptoData(EncryptionLevel level,
+ size_t write_length,
+ QuicStreamOffset offset,
+ TransmissionType transmission_type,
+ QuicFrame* frame);
+
// Returns true if current open packet can accommodate more stream frames of
// stream |id| at |offset| and data length |data_size|, false otherwise.
bool HasRoomForStreamFrame(QuicStreamId id,
QuicStreamOffset offset,
size_t data_size);
- // Returns true if current open packet can accomoodate a message frame of
+ // Returns true if current open packet can accommodate a message frame of
// |length|.
bool HasRoomForMessageFrame(QuicByteCount length);
@@ -242,6 +252,9 @@
// Sets long header type of next constructed packets.
void SetLongHeaderType(QuicLongHeaderType type);
+ // Sets the retry token to be sent over the wire in v99 IETF Initial packets.
+ void SetRetryToken(QuicStringPiece retry_token);
+
// Returns the largest payload that will fit into a single MESSAGE frame.
QuicPacketLength GetLargestMessagePayload() const;
@@ -276,6 +289,14 @@
bool fin,
QuicFrame* frame);
+ // Creates a CRYPTO frame which fits into the current open packet. Returns
+ // false if there isn't enough room in the current open packet for a CRYPTO
+ // frame, and true if there is.
+ bool CreateCryptoFrame(EncryptionLevel level,
+ size_t write_length,
+ QuicStreamOffset offset,
+ QuicFrame* frame);
+
void FillPacketHeader(QuicPacketHeader* header);
// Adds a |frame| if there is space and returns false and flushes all pending
@@ -314,6 +335,21 @@
// function instead.
QuicPacketNumberLength GetPacketNumberLength() const;
+ // Returns long header type of packet to send over the wire.
+ QuicLongHeaderType GetLongHeaderType() const;
+
+ // Returns length of the retry token variable length integer to send over the
+ // wire. Is non-zero for v99 IETF Initial packets.
+ QuicVariableLengthIntegerLength GetRetryTokenLengthLength() const;
+
+ // Returns the retry token to send over the wire, only sent in
+ // v99 IETF Initial packets.
+ QuicStringPiece GetRetryToken() const;
+
+ // Returns length of the length variable length integer to send over the
+ // wire. Is non-zero for v99 IETF Initial, 0-RTT or Handshake packets.
+ QuicVariableLengthIntegerLength GetLengthLength() const;
+
// Returns true if |frame| starts with CHLO.
bool StreamFrameStartsWithChlo(const QuicStreamFrame& frame) const;
@@ -354,8 +390,13 @@
SerializedPacket packet_;
// Long header type of next constructed packets.
+ // TODO(fayang): remove this variable when deprecating
+ // quic_encryption_driven_header_type.
QuicLongHeaderType long_header_type_;
+ // Retry token to send over the wire in v99 IETF Initial packets.
+ QuicString retry_token_;
+
// Pending padding bytes to send. Pending padding bytes will be sent in next
// packet(s) (after all other frames) if current constructed packet does not
// have room to send all of them.
@@ -373,6 +414,9 @@
// Latched value of --quic_set_transmission_type_for_next_frame. Don't use
// this variable directly, use ShouldSetTransmissionTypeForNextFrame instead.
bool set_transmission_type_for_next_frame_;
+
+ // Latched value of gfe2_reloadable_flag_quic_encryption_driven_header_type.
+ const bool encryption_level_driven_long_header_type_;
};
} // namespace quic
diff --git a/quic/core/quic_packet_creator_test.cc b/quic/core/quic_packet_creator_test.cc
index 5dd4abb..cfc92ea 100644
--- a/quic/core/quic_packet_creator_test.cc
+++ b/quic/core/quic_packet_creator_test.cc
@@ -148,8 +148,8 @@
creator_(connection_id_, &client_framer_, &delegate_, &producer_),
serialized_packet_(creator_.NoPacket()) {
EXPECT_CALL(delegate_, GetPacketBuffer()).WillRepeatedly(Return(nullptr));
- creator_.SetEncrypter(ENCRYPTION_INITIAL, QuicMakeUnique<NullEncrypter>(
- Perspective::IS_CLIENT));
+ creator_.SetEncrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<NullEncrypter>(
+ Perspective::IS_CLIENT));
creator_.SetEncrypter(
ENCRYPTION_FORWARD_SECURE,
QuicMakeUnique<NullEncrypter>(Perspective::IS_CLIENT));
@@ -203,7 +203,9 @@
creator_.GetSourceConnectionIdLength(),
QuicPacketCreatorPeer::SendVersionInPacket(&creator_),
!kIncludeDiversificationNonce,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_),
+ QuicPacketCreatorPeer::GetRetryTokenLengthLength(&creator_), 0,
+ QuicPacketCreatorPeer::GetLengthLength(&creator_));
}
// Returns the number of bytes of overhead that will be added to a packet
@@ -256,14 +258,15 @@
TestPacketCreator creator_;
SerializedPacket serialized_packet_;
SimpleDataProducer producer_;
+ SimpleBufferAllocator allocator_;
};
// Run all packet creator tests with all supported versions of QUIC, and with
// and without version in the packet header, as well as doing a run for each
// length of truncated connection id.
-INSTANTIATE_TEST_CASE_P(QuicPacketCreatorTests,
- QuicPacketCreatorTest,
- ::testing::ValuesIn(GetTestParams()));
+INSTANTIATE_TEST_SUITE_P(QuicPacketCreatorTests,
+ QuicPacketCreatorTest,
+ ::testing::ValuesIn(GetTestParams()));
TEST_P(QuicPacketCreatorTest, SerializeFrames) {
for (int i = ENCRYPTION_NONE; i < NUM_ENCRYPTION_LEVELS; ++i) {
@@ -528,6 +531,15 @@
ProcessPacket(serialized);
}
+TEST_P(QuicPacketCreatorTest, ConsumeCryptoData) {
+ QuicString data = "crypto data";
+ QuicFrame frame;
+ ASSERT_TRUE(creator_.ConsumeCryptoData(ENCRYPTION_NONE, data.length(), 0,
+ NOT_RETRANSMISSION, &frame));
+ EXPECT_EQ(frame.crypto_frame->data_length, data.length());
+ EXPECT_TRUE(creator_.HasPendingFrames());
+}
+
TEST_P(QuicPacketCreatorTest, ConsumeData) {
QuicFrame frame;
MakeIOVector("test", &iov_);
@@ -1113,7 +1125,8 @@
creator_.GetDestinationConnectionIdLength(),
creator_.GetSourceConnectionIdLength(),
QuicPacketCreatorPeer::GetPacketNumberLength(&creator_),
- &payload_length));
+ QuicPacketCreatorPeer::GetRetryTokenLengthLength(&creator_),
+ QuicPacketCreatorPeer::GetLengthLength(&creator_), &payload_length));
QuicFrame frame;
const QuicString too_long_payload(payload_length * 2, 'a');
MakeIOVector(too_long_payload, &iov_);
@@ -1148,7 +1161,9 @@
creator_.GetSourceConnectionIdLength(),
QuicPacketCreatorPeer::SendVersionInPacket(&creator_),
!kIncludeDiversificationNonce,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_)),
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_),
+ QuicPacketCreatorPeer::GetRetryTokenLengthLength(&creator_),
+ 0, QuicPacketCreatorPeer::GetLengthLength(&creator_)),
creator_.BytesFree());
// Add a variety of frame types and then a padding frame.
@@ -1202,7 +1217,9 @@
creator_.GetSourceConnectionIdLength(),
QuicPacketCreatorPeer::SendVersionInPacket(&creator_),
!kIncludeDiversificationNonce,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_)),
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_),
+ QuicPacketCreatorPeer::GetRetryTokenLengthLength(&creator_),
+ 0, QuicPacketCreatorPeer::GetLengthLength(&creator_)),
creator_.BytesFree());
}
@@ -1489,22 +1506,29 @@
.Times(3)
.WillRepeatedly(
Invoke(this, &QuicPacketCreatorTest::ClearSerializedPacketForTests));
+ QuicMemSliceStorage storage(nullptr, 0, nullptr, 0);
// Verify that there is enough room for the largest message payload.
EXPECT_TRUE(
creator_.HasRoomForMessageFrame(creator_.GetLargestMessagePayload()));
QuicString message(creator_.GetLargestMessagePayload(), 'a');
- EXPECT_TRUE(creator_.AddSavedFrame(
- QuicFrame(new QuicMessageFrame(1, message)), NOT_RETRANSMISSION));
+ QuicMessageFrame* message_frame = new QuicMessageFrame(1);
+ MakeSpan(&allocator_, message, &storage)
+ .SaveMemSlicesAsMessageData(message_frame);
+ EXPECT_TRUE(
+ creator_.AddSavedFrame(QuicFrame(message_frame), NOT_RETRANSMISSION));
EXPECT_TRUE(creator_.HasPendingFrames());
creator_.Flush();
- EXPECT_TRUE(creator_.AddSavedFrame(
- QuicFrame(new QuicMessageFrame(2, "message")), NOT_RETRANSMISSION));
+ QuicMessageFrame* frame2 = new QuicMessageFrame(2);
+ MakeSpan(&allocator_, "message", &storage).SaveMemSlicesAsMessageData(frame2);
+ EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(frame2), NOT_RETRANSMISSION));
EXPECT_TRUE(creator_.HasPendingFrames());
// Verify if a new frame is added, 1 byte message length will be added.
EXPECT_EQ(1u, creator_.ExpansionOnNewFrame());
- EXPECT_TRUE(creator_.AddSavedFrame(
- QuicFrame(new QuicMessageFrame(3, "message2")), NOT_RETRANSMISSION));
+ QuicMessageFrame* frame3 = new QuicMessageFrame(3);
+ MakeSpan(&allocator_, "message2", &storage)
+ .SaveMemSlicesAsMessageData(frame3);
+ EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(frame3), NOT_RETRANSMISSION));
EXPECT_EQ(1u, creator_.ExpansionOnNewFrame());
creator_.Flush();
@@ -1513,16 +1537,17 @@
EXPECT_TRUE(creator_.ConsumeData(
QuicUtils::GetCryptoStreamId(client_framer_.transport_version()), &iov_,
1u, iov_.iov_len, 0u, 0u, false, false, NOT_RETRANSMISSION, &frame));
- EXPECT_TRUE(creator_.AddSavedFrame(
- QuicFrame(new QuicMessageFrame(1, "message")), NOT_RETRANSMISSION));
+ QuicMessageFrame* frame4 = new QuicMessageFrame(4);
+ MakeSpan(&allocator_, "message", &storage).SaveMemSlicesAsMessageData(frame4);
+ EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(frame4), NOT_RETRANSMISSION));
EXPECT_TRUE(creator_.HasPendingFrames());
// Verify there is not enough room for largest payload.
EXPECT_FALSE(
creator_.HasRoomForMessageFrame(creator_.GetLargestMessagePayload()));
// Add largest message will causes the flush of the stream frame.
- QuicMessageFrame message_frame(2, message);
- EXPECT_FALSE(
- creator_.AddSavedFrame(QuicFrame(&message_frame), NOT_RETRANSMISSION));
+ QuicMessageFrame frame5(5);
+ MakeSpan(&allocator_, message, &storage).SaveMemSlicesAsMessageData(&frame5);
+ EXPECT_FALSE(creator_.AddSavedFrame(QuicFrame(&frame5), NOT_RETRANSMISSION));
EXPECT_FALSE(creator_.HasPendingFrames());
}
@@ -1532,13 +1557,15 @@
}
QuicString message_data(kDefaultMaxPacketSize, 'a');
QuicStringPiece message_buffer(message_data);
+ QuicMemSliceStorage storage(nullptr, 0, nullptr, 0);
// Test all possible size of message frames.
for (size_t message_size = 0;
message_size <= creator_.GetLargestMessagePayload(); ++message_size) {
- EXPECT_TRUE(creator_.AddSavedFrame(
- QuicFrame(new QuicMessageFrame(
- 0, QuicStringPiece(message_buffer.data(), message_size))),
- NOT_RETRANSMISSION));
+ QuicMessageFrame* frame = new QuicMessageFrame(0);
+ MakeSpan(&allocator_, QuicStringPiece(message_buffer.data(), message_size),
+ &storage)
+ .SaveMemSlicesAsMessageData(frame);
+ EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(frame), NOT_RETRANSMISSION));
EXPECT_TRUE(creator_.HasPendingFrames());
size_t expansion_bytes = message_size >= 64 ? 2 : 1;
@@ -1598,6 +1625,44 @@
DeleteSerializedPacket();
}
+TEST_P(QuicPacketCreatorTest, RetryToken) {
+ if (!GetParam().version_serialization ||
+ !QuicVersionHasLongHeaderLengths(client_framer_.transport_version())) {
+ return;
+ }
+
+ char retry_token_bytes[] = {1, 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16};
+
+ creator_.SetRetryToken(
+ QuicString(retry_token_bytes, sizeof(retry_token_bytes)));
+
+ frames_.push_back(QuicFrame(QuicStreamFrame(
+ QuicUtils::GetCryptoStreamId(client_framer_.transport_version()), false,
+ 0u, QuicStringPiece())));
+ SerializedPacket serialized = SerializeAllFrames(frames_);
+
+ QuicPacketHeader header;
+ {
+ InSequence s;
+ EXPECT_CALL(framer_visitor_, OnPacket());
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
+ EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
+ EXPECT_CALL(framer_visitor_, OnPacketHeader(_))
+ .WillOnce(DoAll(SaveArg<0>(&header), Return(true)));
+ EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
+ EXPECT_CALL(framer_visitor_, OnPacketComplete());
+ }
+ ProcessPacket(serialized);
+ ASSERT_TRUE(header.version_flag);
+ ASSERT_EQ(header.long_packet_type, INITIAL);
+ ASSERT_EQ(header.retry_token.length(), sizeof(retry_token_bytes));
+ test::CompareCharArraysWithHexError(
+ "retry token", header.retry_token.data(), header.retry_token.length(),
+ retry_token_bytes, sizeof(retry_token_bytes));
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/quic/core/quic_packet_generator.cc b/quic/core/quic_packet_generator.cc
index 12978a3..0b83030 100644
--- a/quic/core/quic_packet_generator.cc
+++ b/quic/core/quic_packet_generator.cc
@@ -56,6 +56,44 @@
SendQueuedFrames(/*flush=*/false);
}
+size_t QuicPacketGenerator::ConsumeCryptoData(EncryptionLevel level,
+ size_t write_length,
+ QuicStreamOffset offset) {
+ QUIC_BUG_IF(!flusher_attached_) << "Packet flusher is not attached when "
+ "generator tries to write crypto data.";
+ // To make reasoning about crypto frames easier, we don't combine them with
+ // other retransmittable frames in a single packet.
+ // TODO(nharper): Once we have separate packet number spaces, everything
+ // should be driven by encryption level, and we should stop flushing in this
+ // spot.
+ const bool flush = packet_creator_.HasPendingRetransmittableFrames();
+ SendQueuedFrames(flush);
+
+ size_t total_bytes_consumed = 0;
+
+ while (total_bytes_consumed < write_length) {
+ QuicFrame frame;
+ if (!packet_creator_.ConsumeCryptoData(
+ level, write_length - total_bytes_consumed,
+ offset + total_bytes_consumed, next_transmission_type_, &frame)) {
+ // The only pending data in the packet is non-retransmittable frames. I'm
+ // assuming here that they won't occupy so much of the packet that a
+ // CRYPTO frame won't fit.
+ QUIC_BUG << "Failed to ConsumeCryptoData at level " << level;
+ return 0;
+ }
+ total_bytes_consumed += frame.crypto_frame->data_length;
+
+ // TODO(ianswett): Move to having the creator flush itself when it's full.
+ packet_creator_.Flush();
+ }
+
+ // Don't allow the handshake to be bundled with other retransmittable frames.
+ SendQueuedFrames(/*flush=*/true);
+
+ return total_bytes_consumed;
+}
+
QuicConsumedData QuicPacketGenerator::ConsumeData(QuicStreamId id,
size_t write_length,
QuicStreamOffset offset,
@@ -418,17 +456,19 @@
}
MessageStatus QuicPacketGenerator::AddMessageFrame(QuicMessageId message_id,
- QuicStringPiece message) {
+ QuicMemSliceSpan message) {
QUIC_BUG_IF(!flusher_attached_) << "Packet flusher is not attached when "
"generator tries to add message frame.";
- if (message.length() > GetLargestMessagePayload()) {
+ const QuicByteCount message_length = message.total_length();
+ if (message_length > GetLargestMessagePayload()) {
return MESSAGE_STATUS_TOO_LARGE;
}
SendQueuedFrames(/*flush=*/false);
- if (!packet_creator_.HasRoomForMessageFrame(message.length())) {
+ if (!packet_creator_.HasRoomForMessageFrame(message_length)) {
packet_creator_.Flush();
}
- QuicMessageFrame* frame = new QuicMessageFrame(message_id, message);
+ QuicMessageFrame* frame = new QuicMessageFrame(message_id);
+ message.SaveMemSlicesAsMessageData(frame);
const bool success =
packet_creator_.AddSavedFrame(QuicFrame(frame), next_transmission_type_);
if (!success) {
diff --git a/quic/core/quic_packet_generator.h b/quic/core/quic_packet_generator.h
index 572d170..d50f38e 100644
--- a/quic/core/quic_packet_generator.h
+++ b/quic/core/quic_packet_generator.h
@@ -50,6 +50,7 @@
#include "net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice_span.h"
namespace quic {
@@ -100,6 +101,14 @@
QuicStreamOffset offset,
StreamSendingState state);
+ // Consumes data for CRYPTO frames sent at |level| starting at |offset| for a
+ // total of |write_length| bytes, and returns the number of bytes consumed.
+ // The data is passed into the packet creator and serialized into one or more
+ // packets.
+ size_t ConsumeCryptoData(EncryptionLevel level,
+ size_t write_length,
+ QuicStreamOffset offset);
+
// Sends as many data only packets as allowed by the send algorithm and the
// available iov.
// This path does not support padding, or bundling pending frames.
@@ -210,7 +219,7 @@
// Tries to add a message frame containing |message| and returns the status.
MessageStatus AddMessageFrame(QuicMessageId message_id,
- QuicStringPiece message);
+ QuicMemSliceSpan message);
// Returns the largest payload that will fit into a single MESSAGE frame.
QuicPacketLength GetLargestMessagePayload() const;
diff --git a/quic/core/quic_packet_generator_test.cc b/quic/core/quic_packet_generator_test.cc
index b85a4f7..4a2dcc5 100644
--- a/quic/core/quic_packet_generator_test.cc
+++ b/quic/core/quic_packet_generator_test.cc
@@ -86,6 +86,7 @@
num_rst_stream_frames(0),
num_stop_waiting_frames(0),
num_stream_frames(0),
+ num_crypto_frames(0),
num_ping_frames(0),
num_mtu_discovery_frames(0),
num_padding_frames(0) {}
@@ -96,6 +97,7 @@
size_t num_rst_stream_frames;
size_t num_stop_waiting_frames;
size_t num_stream_frames;
+ size_t num_crypto_frames;
size_t num_ping_frames;
size_t num_mtu_discovery_frames;
size_t num_padding_frames;
@@ -140,6 +142,13 @@
return QuicPacketGenerator::ConsumeData(id, total_length, offset, state);
}
+ size_t ConsumeCryptoData(EncryptionLevel level,
+ QuicStringPiece data,
+ QuicStreamOffset offset) {
+ producer_->SaveCryptoData(level, offset, data);
+ return QuicPacketGenerator::ConsumeCryptoData(level, data.length(), offset);
+ }
+
SimpleDataProducer* producer_;
};
@@ -195,7 +204,7 @@
size_t num_retransmittable_frames =
contents.num_connection_close_frames + contents.num_goaway_frames +
contents.num_rst_stream_frames + contents.num_stream_frames +
- contents.num_ping_frames;
+ contents.num_crypto_frames + contents.num_ping_frames;
size_t num_frames =
contents.num_ack_frames + contents.num_stop_waiting_frames +
contents.num_mtu_discovery_frames + contents.num_padding_frames +
@@ -222,6 +231,8 @@
simple_framer_.rst_stream_frames().size());
EXPECT_EQ(contents.num_stream_frames,
simple_framer_.stream_frames().size());
+ EXPECT_EQ(contents.num_crypto_frames,
+ simple_framer_.crypto_frames().size());
EXPECT_EQ(contents.num_stop_waiting_frames,
simple_framer_.stop_waiting_frames().size());
EXPECT_EQ(contents.num_padding_frames,
@@ -266,6 +277,7 @@
std::vector<SerializedPacket> packets_;
QuicAckFrame ack_frame_;
struct iovec iov_;
+ SimpleBufferAllocator allocator_;
private:
std::unique_ptr<char[]> data_array_;
@@ -399,6 +411,23 @@
CheckPacketContains(contents, 0);
}
+TEST_F(QuicPacketGeneratorTest, ConsumeCryptoData) {
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ QuicString data = "crypto data";
+ size_t consumed_bytes =
+ generator_.ConsumeCryptoData(ENCRYPTION_NONE, data, 0);
+ generator_.Flush();
+ EXPECT_EQ(data.length(), consumed_bytes);
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+ EXPECT_FALSE(generator_.HasRetransmittableFrames());
+
+ PacketContents contents;
+ contents.num_crypto_frames = 1;
+ contents.num_padding_frames = 1;
+ CheckPacketContains(contents, 0);
+}
+
TEST_F(QuicPacketGeneratorTest, ConsumeData_NotWritable) {
delegate_.SetCanNotWrite();
@@ -555,22 +584,25 @@
TEST_F(QuicPacketGeneratorTest, ConsumeData_FramesPreviouslyQueued) {
// Set the packet size be enough for two stream frames with 0 stream offset,
// but not enough for a stream frame of 0 offset and one with non-zero offset.
- size_t length = NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) +
- GetPacketHeaderSize(
- framer_.transport_version(),
- creator_->GetDestinationConnectionIdLength(),
- creator_->GetSourceConnectionIdLength(),
- QuicPacketCreatorPeer::SendVersionInPacket(creator_),
- !kIncludeDiversificationNonce,
- QuicPacketCreatorPeer::GetPacketNumberLength(creator_)) +
- // Add an extra 3 bytes for the payload and 1 byte so
- // BytesFree is larger than the GetMinStreamFrameSize.
- QuicFramer::GetMinStreamFrameSize(framer_.transport_version(),
- 1, 0, false, 3) +
- 3 +
- QuicFramer::GetMinStreamFrameSize(framer_.transport_version(),
- 1, 0, true, 1) +
- 1;
+ size_t length =
+ NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) +
+ GetPacketHeaderSize(
+ framer_.transport_version(),
+ creator_->GetDestinationConnectionIdLength(),
+ creator_->GetSourceConnectionIdLength(),
+ QuicPacketCreatorPeer::SendVersionInPacket(creator_),
+ !kIncludeDiversificationNonce,
+ QuicPacketCreatorPeer::GetPacketNumberLength(creator_),
+ QuicPacketCreatorPeer::GetRetryTokenLengthLength(creator_), 0,
+ QuicPacketCreatorPeer::GetLengthLength(creator_)) +
+ // Add an extra 3 bytes for the payload and 1 byte so
+ // BytesFree is larger than the GetMinStreamFrameSize.
+ QuicFramer::GetMinStreamFrameSize(framer_.transport_version(), 1, 0,
+ false, 3) +
+ 3 +
+ QuicFramer::GetMinStreamFrameSize(framer_.transport_version(), 1, 0, true,
+ 1) +
+ 1;
generator_.SetMaxPacketLength(length);
delegate_.SetCanWriteAnything();
{
@@ -1227,19 +1259,22 @@
const QuicStreamId kDataStreamId = 5;
// Set the packet size be enough for one stream frame with 0 stream offset and
// max size of random padding.
- size_t length = NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) +
- GetPacketHeaderSize(
- framer_.transport_version(),
- creator_->GetDestinationConnectionIdLength(),
- creator_->GetSourceConnectionIdLength(),
- QuicPacketCreatorPeer::SendVersionInPacket(creator_),
- !kIncludeDiversificationNonce,
- QuicPacketCreatorPeer::GetPacketNumberLength(creator_)) +
- QuicFramer::GetMinStreamFrameSize(
- framer_.transport_version(), kDataStreamId, 0,
- /*last_frame_in_packet=*/false,
- kStreamFramePayloadSize + kMaxNumRandomPaddingBytes) +
- kStreamFramePayloadSize + kMaxNumRandomPaddingBytes;
+ size_t length =
+ NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) +
+ GetPacketHeaderSize(
+ framer_.transport_version(),
+ creator_->GetDestinationConnectionIdLength(),
+ creator_->GetSourceConnectionIdLength(),
+ QuicPacketCreatorPeer::SendVersionInPacket(creator_),
+ !kIncludeDiversificationNonce,
+ QuicPacketCreatorPeer::GetPacketNumberLength(creator_),
+ QuicPacketCreatorPeer::GetRetryTokenLengthLength(creator_), 0,
+ QuicPacketCreatorPeer::GetLengthLength(creator_)) +
+ QuicFramer::GetMinStreamFrameSize(
+ framer_.transport_version(), kDataStreamId, 0,
+ /*last_frame_in_packet=*/false,
+ kStreamFramePayloadSize + kMaxNumRandomPaddingBytes) +
+ kStreamFramePayloadSize + kMaxNumRandomPaddingBytes;
generator_.SetMaxPacketLength(length);
delegate_.SetCanWriteAnything();
EXPECT_CALL(delegate_, OnSerializedPacket(_))
@@ -1275,7 +1310,9 @@
creator_->GetSourceConnectionIdLength(),
QuicPacketCreatorPeer::SendVersionInPacket(creator_),
!kIncludeDiversificationNonce,
- QuicPacketCreatorPeer::GetPacketNumberLength(creator_)) +
+ QuicPacketCreatorPeer::GetPacketNumberLength(creator_),
+ QuicPacketCreatorPeer::GetRetryTokenLengthLength(creator_), 0,
+ QuicPacketCreatorPeer::GetLengthLength(creator_)) +
QuicFramer::GetMinStreamFrameSize(
framer_.transport_version(), kDataStreamId, 0,
/*last_frame_in_packet=*/false, kStreamFramePayloadSize + 1) +
@@ -1315,22 +1352,25 @@
const QuicStreamId kDataStreamId2 = 6;
// Set the packet size be enough for first frame with 0 stream offset + second
// frame + 1 byte payload. two or more packets will accommodate.
- size_t length = NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) +
- GetPacketHeaderSize(
- framer_.transport_version(),
- creator_->GetDestinationConnectionIdLength(),
- creator_->GetSourceConnectionIdLength(),
- QuicPacketCreatorPeer::SendVersionInPacket(creator_),
- !kIncludeDiversificationNonce,
- QuicPacketCreatorPeer::GetPacketNumberLength(creator_)) +
- QuicFramer::GetMinStreamFrameSize(
- framer_.transport_version(), kDataStreamId1, 0,
- /*last_frame_in_packet=*/false, kStreamFramePayloadSize) +
- kStreamFramePayloadSize +
- QuicFramer::GetMinStreamFrameSize(
- framer_.transport_version(), kDataStreamId1, 0,
- /*last_frame_in_packet=*/false, 1) +
- 1;
+ size_t length =
+ NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) +
+ GetPacketHeaderSize(
+ framer_.transport_version(),
+ creator_->GetDestinationConnectionIdLength(),
+ creator_->GetSourceConnectionIdLength(),
+ QuicPacketCreatorPeer::SendVersionInPacket(creator_),
+ !kIncludeDiversificationNonce,
+ QuicPacketCreatorPeer::GetPacketNumberLength(creator_),
+ QuicPacketCreatorPeer::GetRetryTokenLengthLength(creator_), 0,
+ QuicPacketCreatorPeer::GetLengthLength(creator_)) +
+ QuicFramer::GetMinStreamFrameSize(
+ framer_.transport_version(), kDataStreamId1, 0,
+ /*last_frame_in_packet=*/false, kStreamFramePayloadSize) +
+ kStreamFramePayloadSize +
+ QuicFramer::GetMinStreamFrameSize(framer_.transport_version(),
+ kDataStreamId1, 0,
+ /*last_frame_in_packet=*/false, 1) +
+ 1;
generator_.SetMaxPacketLength(length);
delegate_.SetCanWriteAnything();
EXPECT_CALL(delegate_, OnSerializedPacket(_))
@@ -1370,6 +1410,7 @@
if (framer_.transport_version() <= QUIC_VERSION_44) {
return;
}
+ quic::QuicMemSliceStorage storage(nullptr, 0, nullptr, 0);
delegate_.SetCanWriteAnything();
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
@@ -1378,21 +1419,29 @@
generator_.ConsumeData(
QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u,
iov_.iov_len, 0, FIN);
- EXPECT_EQ(MESSAGE_STATUS_SUCCESS, generator_.AddMessageFrame(1, "message"));
+ EXPECT_EQ(MESSAGE_STATUS_SUCCESS,
+ generator_.AddMessageFrame(
+ 1, MakeSpan(&allocator_, "message", &storage)));
EXPECT_TRUE(generator_.HasQueuedFrames());
EXPECT_TRUE(generator_.HasRetransmittableFrames());
// Add a message which causes the flush of current packet.
- EXPECT_EQ(MESSAGE_STATUS_SUCCESS,
- generator_.AddMessageFrame(
- 2, QuicString(generator_.GetLargestMessagePayload(), 'a')));
+ EXPECT_EQ(
+ MESSAGE_STATUS_SUCCESS,
+ generator_.AddMessageFrame(
+ 2, MakeSpan(&allocator_,
+ QuicString(generator_.GetLargestMessagePayload(), 'a'),
+ &storage)));
EXPECT_TRUE(generator_.HasRetransmittableFrames());
// Failed to send messages which cannot fit into one packet.
EXPECT_EQ(
MESSAGE_STATUS_TOO_LARGE,
generator_.AddMessageFrame(
- 3, QuicString(generator_.GetLargestMessagePayload() + 10, 'a')));
+ 3,
+ MakeSpan(&allocator_,
+ QuicString(generator_.GetLargestMessagePayload() + 10, 'a'),
+ &storage)));
}
} // namespace test
diff --git a/quic/core/quic_packet_number.cc b/quic/core/quic_packet_number.cc
index f0a497f..8a799c1 100644
--- a/quic/core/quic_packet_number.cc
+++ b/quic/core/quic_packet_number.cc
@@ -64,9 +64,9 @@
#ifndef NDEBUG
DCHECK(IsInitialized());
if (GetQuicRestartFlag(quic_uint64max_uninitialized_pn)) {
- DCHECK_GE(ToUint64(), 1);
+ DCHECK_GE(ToUint64(), 1UL);
} else {
- DCHECK_GT(ToUint64(), 1);
+ DCHECK_GT(ToUint64(), 1UL);
}
#endif
packet_number_--;
@@ -77,9 +77,9 @@
#ifndef NDEBUG
DCHECK(IsInitialized());
if (GetQuicRestartFlag(quic_uint64max_uninitialized_pn)) {
- DCHECK_GE(ToUint64(), 1);
+ DCHECK_GE(ToUint64(), 1UL);
} else {
- DCHECK_GT(ToUint64(), 1);
+ DCHECK_GT(ToUint64(), 1UL);
}
#endif
QuicPacketNumber previous(*this);
diff --git a/quic/core/quic_packet_reader.cc b/quic/core/quic_packet_reader.cc
index fc2ac15..2763b34 100644
--- a/quic/core/quic_packet_reader.cc
+++ b/quic/core/quic_packet_reader.cc
@@ -20,6 +20,7 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_server_stats.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
#include "net/quic/platform/impl/quic_socket_utils.h"
@@ -115,9 +116,12 @@
}
if (QUIC_PREDICT_FALSE(mmsg_hdr_[i].msg_hdr.msg_flags & MSG_TRUNC)) {
- QUIC_LOG_FIRST_N(ERROR, 10)
+ QUIC_LOG_FIRST_N(WARNING, 100)
<< "Dropping truncated QUIC packet: buffer size:"
<< packets_[i].iov.iov_len << " packet size:" << mmsg_hdr_[i].msg_len;
+ QUIC_SERVER_HISTOGRAM_COUNTS(
+ "QuicPacketReader.DroppedPacketSize", mmsg_hdr_[i].msg_len, 1, 10000,
+ 20, "In QuicPacketReader, the size of big packets that are dropped.");
continue;
}
diff --git a/quic/core/quic_packet_writer.h b/quic/core/quic_packet_writer.h
index 3314701..c33e9b7 100644
--- a/quic/core/quic_packet_writer.h
+++ b/quic/core/quic_packet_writer.h
@@ -84,11 +84,6 @@
const QuicSocketAddress& peer_address,
PerPacketOptions* options) = 0;
- // Returns true if the writer buffers and subsequently rewrites data
- // when an attempt to write results in the underlying socket becoming
- // write blocked.
- virtual bool IsWriteBlockedDataBuffered() const = 0;
-
// Returns true if the network socket is not writable.
virtual bool IsWriteBlocked() const = 0;
diff --git a/quic/core/quic_packet_writer_wrapper.cc b/quic/core/quic_packet_writer_wrapper.cc
index 248bf82..f1f25d8 100644
--- a/quic/core/quic_packet_writer_wrapper.cc
+++ b/quic/core/quic_packet_writer_wrapper.cc
@@ -24,10 +24,6 @@
options);
}
-bool QuicPacketWriterWrapper::IsWriteBlockedDataBuffered() const {
- return writer_->IsWriteBlockedDataBuffered();
-}
-
bool QuicPacketWriterWrapper::IsWriteBlocked() const {
return writer_->IsWriteBlocked();
}
diff --git a/quic/core/quic_packet_writer_wrapper.h b/quic/core/quic_packet_writer_wrapper.h
index b731064..64b10f5 100644
--- a/quic/core/quic_packet_writer_wrapper.h
+++ b/quic/core/quic_packet_writer_wrapper.h
@@ -30,7 +30,6 @@
const QuicIpAddress& self_address,
const QuicSocketAddress& peer_address,
PerPacketOptions* options) override;
- bool IsWriteBlockedDataBuffered() const override;
bool IsWriteBlocked() const override;
void SetWritable() override;
QuicByteCount GetMaxPacketSize(
diff --git a/quic/core/quic_packets.cc b/quic/core/quic_packets.cc
index 5e3ba76..31cdb7d 100644
--- a/quic/core/quic_packets.cc
+++ b/quic/core/quic_packets.cc
@@ -4,11 +4,13 @@
#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/core/quic_versions.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
namespace quic {
@@ -18,7 +20,9 @@
return GetPacketHeaderSize(version, header.destination_connection_id_length,
header.source_connection_id_length,
header.version_flag, header.nonce != nullptr,
- header.packet_number_length);
+ header.packet_number_length,
+ header.retry_token_length_length,
+ header.retry_token.length(), header.length_length);
}
size_t GetPacketHeaderSize(
@@ -27,16 +31,20 @@
QuicConnectionIdLength source_connection_id_length,
bool include_version,
bool include_diversification_nonce,
- QuicPacketNumberLength packet_number_length) {
+ QuicPacketNumberLength packet_number_length,
+ QuicVariableLengthIntegerLength retry_token_length_length,
+ QuicByteCount retry_token_length,
+ QuicVariableLengthIntegerLength length_length) {
if (version > QUIC_VERSION_43) {
if (include_version) {
// Long header.
return kPacketHeaderTypeSize + kConnectionIdLengthSize +
destination_connection_id_length + source_connection_id_length +
- (version > QUIC_VERSION_46 ? packet_number_length
+ (version > QUIC_VERSION_44 ? packet_number_length
: PACKET_4BYTE_PACKET_NUMBER) +
kQuicVersionSize +
- (include_diversification_nonce ? kDiversificationNonceSize : 0);
+ (include_diversification_nonce ? kDiversificationNonceSize : 0) +
+ retry_token_length_length + retry_token_length + length_length;
}
// Short header.
return kPacketHeaderTypeSize + destination_connection_id_length +
@@ -58,11 +66,15 @@
QuicConnectionIdLength source_connection_id_length,
bool include_version,
bool include_diversification_nonce,
- QuicPacketNumberLength packet_number_length) {
+ QuicPacketNumberLength packet_number_length,
+ QuicVariableLengthIntegerLength retry_token_length_length,
+ QuicByteCount retry_token_length,
+ QuicVariableLengthIntegerLength length_length) {
// Encryption starts before private flags.
return GetPacketHeaderSize(
version, destination_connection_id_length, source_connection_id_length,
- include_version, include_diversification_nonce, packet_number_length);
+ include_version, include_diversification_nonce, packet_number_length,
+ retry_token_length_length, retry_token_length, length_length);
}
QuicPacketHeader::QuicPacketHeader()
@@ -78,7 +90,11 @@
nonce(nullptr),
form(GOOGLE_QUIC_PACKET),
long_packet_type(INITIAL),
- possible_stateless_reset_token(0) {}
+ possible_stateless_reset_token(0),
+ retry_token_length_length(VARIABLE_LENGTH_INTEGER_LENGTH_0),
+ retry_token(QuicStringPiece()),
+ length_length(VARIABLE_LENGTH_INTEGER_LENGTH_0),
+ remaining_packet_length(0) {}
QuicPacketHeader::QuicPacketHeader(const QuicPacketHeader& other) = default;
@@ -126,6 +142,23 @@
<< ", version_flag: " << header.version_flag;
if (header.version_flag) {
os << ", version: " << ParsedQuicVersionToString(header.version);
+ if (header.long_packet_type != INVALID_PACKET_TYPE) {
+ os << ", long_packet_type: "
+ << QuicUtils::QuicLongHeaderTypetoString(header.long_packet_type);
+ }
+ if (header.retry_token_length_length != VARIABLE_LENGTH_INTEGER_LENGTH_0) {
+ os << ", retry_token_length_length: "
+ << static_cast<int>(header.retry_token_length_length);
+ }
+ if (header.retry_token.length() != 0) {
+ os << ", retry_token_length: " << header.retry_token.length();
+ }
+ if (header.length_length != VARIABLE_LENGTH_INTEGER_LENGTH_0) {
+ os << ", length_length: " << static_cast<int>(header.length_length);
+ }
+ if (header.remaining_packet_length != 0) {
+ os << ", remaining_packet_length: " << header.remaining_packet_length;
+ }
}
if (header.nonce != nullptr) {
os << ", diversification_nonce: "
@@ -148,21 +181,44 @@
}
}
-QuicPacket::QuicPacket(char* buffer,
- size_t length,
- bool owns_buffer,
- QuicConnectionIdLength destination_connection_id_length,
- QuicConnectionIdLength source_connection_id_length,
- bool includes_version,
- bool includes_diversification_nonce,
- QuicPacketNumberLength packet_number_length)
+QuicPacket::QuicPacket(
+ char* buffer,
+ size_t length,
+ bool owns_buffer,
+ QuicConnectionIdLength destination_connection_id_length,
+ QuicConnectionIdLength source_connection_id_length,
+ bool includes_version,
+ bool includes_diversification_nonce,
+ QuicPacketNumberLength packet_number_length,
+ QuicVariableLengthIntegerLength retry_token_length_length,
+ QuicByteCount retry_token_length,
+ QuicVariableLengthIntegerLength length_length)
: QuicData(buffer, length, owns_buffer),
buffer_(buffer),
destination_connection_id_length_(destination_connection_id_length),
source_connection_id_length_(source_connection_id_length),
includes_version_(includes_version),
includes_diversification_nonce_(includes_diversification_nonce),
- packet_number_length_(packet_number_length) {}
+ packet_number_length_(packet_number_length),
+ retry_token_length_length_(retry_token_length_length),
+ retry_token_length_(retry_token_length),
+ length_length_(length_length) {}
+
+QuicPacket::QuicPacket(char* buffer,
+ size_t length,
+ bool owns_buffer,
+ const QuicPacketHeader& header)
+ : QuicPacket(buffer,
+ length,
+ owns_buffer,
+ header.destination_connection_id_length,
+ header.source_connection_id_length,
+ header.version_flag,
+ header.nonce != nullptr,
+ header.packet_number_length,
+ header.retry_token_length_length,
+ header.retry_token.length(),
+ header.length_length) {}
QuicEncryptedPacket::QuicEncryptedPacket(const char* buffer, size_t length)
: QuicData(buffer, length) {}
@@ -262,17 +318,19 @@
QuicStringPiece QuicPacket::AssociatedData(QuicTransportVersion version) const {
return QuicStringPiece(
- data(), GetStartOfEncryptedData(
- version, destination_connection_id_length_,
- source_connection_id_length_, includes_version_,
- includes_diversification_nonce_, packet_number_length_));
+ data(),
+ GetStartOfEncryptedData(version, destination_connection_id_length_,
+ source_connection_id_length_, includes_version_,
+ includes_diversification_nonce_,
+ packet_number_length_, retry_token_length_length_,
+ retry_token_length_, length_length_));
}
QuicStringPiece QuicPacket::Plaintext(QuicTransportVersion version) const {
const size_t start_of_encrypted_data = GetStartOfEncryptedData(
version, destination_connection_id_length_, source_connection_id_length_,
- includes_version_, includes_diversification_nonce_,
- packet_number_length_);
+ includes_version_, includes_diversification_nonce_, packet_number_length_,
+ retry_token_length_length_, retry_token_length_, length_length_);
return QuicStringPiece(data() + start_of_encrypted_data,
length() - start_of_encrypted_data);
}
diff --git a/quic/core/quic_packets.h b/quic/core/quic_packets.h
index a89ddbb..8808ad2 100644
--- a/quic/core/quic_packets.h
+++ b/quic/core/quic_packets.h
@@ -5,6 +5,7 @@
#ifndef QUICHE_QUIC_CORE_QUIC_PACKETS_H_
#define QUICHE_QUIC_CORE_QUIC_PACKETS_H_
+#include <cstddef>
#include <cstdint>
#include <limits>
#include <list>
@@ -42,20 +43,26 @@
QuicConnectionIdLength source_connection_id_length,
bool include_version,
bool include_diversification_nonce,
- QuicPacketNumberLength packet_number_length);
+ QuicPacketNumberLength packet_number_length,
+ QuicVariableLengthIntegerLength retry_token_length_length,
+ QuicByteCount retry_token_length,
+ QuicVariableLengthIntegerLength length_length);
// Index of the first byte in a QUIC packet of encrypted data.
QUIC_EXPORT_PRIVATE size_t
GetStartOfEncryptedData(QuicTransportVersion version,
const QuicPacketHeader& header);
-QUIC_EXPORT_PRIVATE size_t
-GetStartOfEncryptedData(QuicTransportVersion version,
- QuicConnectionIdLength destination_connection_id_length,
- QuicConnectionIdLength source_connection_id_length,
- bool include_version,
- bool include_diversification_nonce,
- QuicPacketNumberLength packet_number_length);
+QUIC_EXPORT_PRIVATE size_t GetStartOfEncryptedData(
+ QuicTransportVersion version,
+ QuicConnectionIdLength destination_connection_id_length,
+ QuicConnectionIdLength source_connection_id_length,
+ bool include_version,
+ bool include_diversification_nonce,
+ QuicPacketNumberLength packet_number_length,
+ QuicVariableLengthIntegerLength retry_token_length_length,
+ QuicByteCount retry_token_length,
+ QuicVariableLengthIntegerLength length_length);
struct QUIC_EXPORT_PRIVATE QuicPacketHeader {
QuicPacketHeader();
@@ -94,6 +101,18 @@
// Stores last 16 bytes of a this packet, used to check whether this packet is
// a stateless reset packet on decryption failure.
QuicUint128 possible_stateless_reset_token;
+ // Length of the retry token length variable length integer field,
+ // carried only by v99 IETF Initial packets.
+ QuicVariableLengthIntegerLength retry_token_length_length;
+ // Retry token, carried only by v99 IETF Initial packets.
+ QuicStringPiece retry_token;
+ // Length of the length variable length integer field,
+ // carried only by v99 IETF Initial, 0-RTT and Handshake packets.
+ QuicVariableLengthIntegerLength length_length;
+ // Length of the packet number and payload, carried only by v99 IETF Initial,
+ // 0-RTT and Handshake packets. Also includes the length of the
+ // diversification nonce in server to client 0-RTT packets.
+ QuicByteCount remaining_packet_length;
};
struct QUIC_EXPORT_PRIVATE QuicPublicResetPacket {
@@ -153,9 +172,6 @@
class QUIC_EXPORT_PRIVATE QuicPacket : public QuicData {
public:
- // TODO(fayang): 3 fields from header are passed in as arguments.
- // Consider to add a convenience method which directly accepts the entire
- // header.
QuicPacket(char* buffer,
size_t length,
bool owns_buffer,
@@ -163,7 +179,14 @@
QuicConnectionIdLength source_connection_id_length,
bool includes_version,
bool includes_diversification_nonce,
- QuicPacketNumberLength packet_number_length);
+ QuicPacketNumberLength packet_number_length,
+ QuicVariableLengthIntegerLength retry_token_length_length,
+ QuicByteCount retry_token_length,
+ QuicVariableLengthIntegerLength length_length);
+ QuicPacket(char* buffer,
+ size_t length,
+ bool owns_buffer,
+ const QuicPacketHeader& header);
QuicPacket(const QuicPacket&) = delete;
QuicPacket& operator=(const QuicPacket&) = delete;
@@ -179,6 +202,9 @@
const bool includes_version_;
const bool includes_diversification_nonce_;
const QuicPacketNumberLength packet_number_length_;
+ const QuicVariableLengthIntegerLength retry_token_length_length_;
+ const QuicByteCount retry_token_length_;
+ const QuicVariableLengthIntegerLength length_length_;
};
class QUIC_EXPORT_PRIVATE QuicEncryptedPacket : public QuicData {
diff --git a/quic/core/quic_received_packet_manager.cc b/quic/core/quic_received_packet_manager.cc
index 8189ff8..a9e422f 100644
--- a/quic/core/quic_received_packet_manager.cc
+++ b/quic/core/quic_received_packet_manager.cc
@@ -4,6 +4,7 @@
#include "net/third_party/quiche/src/quic/core/quic_received_packet_manager.h"
+#include <algorithm>
#include <limits>
#include <utility>
@@ -75,6 +76,13 @@
std::make_pair(packet_number, receipt_time));
}
}
+
+ if (least_received_packet_number_.IsInitialized()) {
+ least_received_packet_number_ =
+ std::min(least_received_packet_number_, packet_number);
+ } else {
+ least_received_packet_number_ = packet_number;
+ }
}
bool QuicReceivedPacketManager::IsMissing(QuicPacketNumber packet_number) {
@@ -150,12 +158,14 @@
if (ack_frame_.packets.NumIntervals() > 1) {
return true;
}
- // TODO(fayang): Fix this as this check assumes first sent packet by peer
- // is 1.
- return ack_frame_.packets.Min() >
- (peer_least_packet_awaiting_ack_.IsInitialized()
- ? peer_least_packet_awaiting_ack_
- : QuicPacketNumber(1));
+ if (!GetQuicRestartFlag(quic_enable_accept_random_ipn)) {
+ return ack_frame_.packets.Min() >
+ (peer_least_packet_awaiting_ack_.IsInitialized()
+ ? peer_least_packet_awaiting_ack_
+ : QuicPacketNumber(1));
+ }
+ return peer_least_packet_awaiting_ack_.IsInitialized() &&
+ ack_frame_.packets.Min() > peer_least_packet_awaiting_ack_;
}
bool QuicReceivedPacketManager::HasNewMissingPackets() const {
@@ -171,4 +181,16 @@
return LargestAcked(ack_frame_);
}
+QuicPacketNumber QuicReceivedPacketManager::PeerFirstSendingPacketNumber()
+ const {
+ if (!GetQuicRestartFlag(quic_enable_accept_random_ipn)) {
+ return QuicPacketNumber(1);
+ }
+ if (!least_received_packet_number_.IsInitialized()) {
+ QUIC_BUG << "No packets have been received yet";
+ return QuicPacketNumber(1);
+ }
+ return least_received_packet_number_;
+}
+
} // namespace quic
diff --git a/quic/core/quic_received_packet_manager.h b/quic/core/quic_received_packet_manager.h
index c720a01..12d1f9c 100644
--- a/quic/core/quic_received_packet_manager.h
+++ b/quic/core/quic_received_packet_manager.h
@@ -65,6 +65,13 @@
QuicPacketNumber GetLargestObserved() const;
+ // Returns peer first sending packet number to our best knowledge. If
+ // GetQuicRestartFlag(quic_enable_accept_random_ipn) is false, returns 1.
+ // Otherwise considers least_received_packet_number_ as peer first sending
+ // packet number. Please note, this function should only be called when at
+ // least one packet has been received.
+ QuicPacketNumber PeerFirstSendingPacketNumber() const;
+
// For logging purposes.
const QuicAckFrame& ack_frame() const { return ack_frame_; }
@@ -101,6 +108,9 @@
// If true, save timestamps in the ack_frame_.
bool save_timestamps_;
+ // Least packet number received from peer.
+ QuicPacketNumber least_received_packet_number_;
+
QuicConnectionStats* stats_;
};
diff --git a/quic/core/quic_received_packet_manager_test.cc b/quic/core/quic_received_packet_manager_test.cc
index b8264a5..9cbc6e7 100644
--- a/quic/core/quic_received_packet_manager_test.cc
+++ b/quic/core/quic_received_packet_manager_test.cc
@@ -9,6 +9,7 @@
#include <vector>
#include "net/third_party/quiche/src/quic/core/quic_connection_stats.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"
namespace quic {
@@ -56,9 +57,9 @@
QuicReceivedPacketManager received_manager_;
};
-INSTANTIATE_TEST_CASE_P(QuicReceivedPacketManagerTest,
- QuicReceivedPacketManagerTest,
- ::testing::ValuesIn(GetTestParams()));
+INSTANTIATE_TEST_SUITE_P(QuicReceivedPacketManagerTest,
+ QuicReceivedPacketManagerTest,
+ ::testing::ValuesIn(GetTestParams()));
TEST_P(QuicReceivedPacketManagerTest, DontWaitForPacketsBefore) {
QuicPacketHeader header;
@@ -159,6 +160,44 @@
EXPECT_EQ(2u, received_manager_.ack_frame().received_packet_times.size());
}
+TEST_P(QuicReceivedPacketManagerTest, HasMissingPackets) {
+ if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) {
+ EXPECT_QUIC_BUG(received_manager_.PeerFirstSendingPacketNumber(),
+ "No packets have been received yet");
+ } else {
+ EXPECT_EQ(QuicPacketNumber(1),
+ received_manager_.PeerFirstSendingPacketNumber());
+ }
+ RecordPacketReceipt(4, QuicTime::Zero());
+ if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) {
+ EXPECT_EQ(QuicPacketNumber(4),
+ received_manager_.PeerFirstSendingPacketNumber());
+ EXPECT_FALSE(received_manager_.HasMissingPackets());
+ } else {
+ EXPECT_TRUE(received_manager_.HasMissingPackets());
+ EXPECT_EQ(QuicPacketNumber(1),
+ received_manager_.PeerFirstSendingPacketNumber());
+ }
+ RecordPacketReceipt(3, QuicTime::Zero());
+ if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) {
+ EXPECT_FALSE(received_manager_.HasMissingPackets());
+ EXPECT_EQ(QuicPacketNumber(3),
+ received_manager_.PeerFirstSendingPacketNumber());
+ } else {
+ EXPECT_TRUE(received_manager_.HasMissingPackets());
+ EXPECT_EQ(QuicPacketNumber(1),
+ received_manager_.PeerFirstSendingPacketNumber());
+ }
+ RecordPacketReceipt(1, QuicTime::Zero());
+ EXPECT_EQ(QuicPacketNumber(1),
+ received_manager_.PeerFirstSendingPacketNumber());
+ EXPECT_TRUE(received_manager_.HasMissingPackets());
+ RecordPacketReceipt(2, QuicTime::Zero());
+ EXPECT_EQ(QuicPacketNumber(1),
+ received_manager_.PeerFirstSendingPacketNumber());
+ EXPECT_FALSE(received_manager_.HasMissingPackets());
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/quic/core/quic_sent_packet_manager.cc b/quic/core/quic_sent_packet_manager.cc
index 4bbe070..49c5e08 100644
--- a/quic/core/quic_sent_packet_manager.cc
+++ b/quic/core/quic_sent_packet_manager.cc
@@ -67,8 +67,9 @@
} // namespace
-#define ENDPOINT \
- (perspective_ == Perspective::IS_SERVER ? "Server: " : "Client: ")
+#define ENDPOINT \
+ (unacked_packets_.perspective() == Perspective::IS_SERVER ? "Server: " \
+ : "Client: ")
QuicSentPacketManager::QuicSentPacketManager(
Perspective perspective,
@@ -76,15 +77,19 @@
QuicConnectionStats* stats,
CongestionControlType congestion_control_type,
LossDetectionType loss_type)
- : unacked_packets_(),
- perspective_(perspective),
+ : unacked_packets_(perspective),
clock_(clock),
stats_(stats),
debug_delegate_(nullptr),
network_change_visitor_(nullptr),
initial_congestion_window_(kInitialCongestionWindow),
- loss_algorithm_(&general_loss_algorithm_),
+ loss_algorithm_(
+ unacked_packets_.use_uber_loss_algorithm()
+ ? dynamic_cast<LossDetectionInterface*>(&uber_loss_algorithm_)
+ : dynamic_cast<LossDetectionInterface*>(
+ &general_loss_algorithm_)),
general_loss_algorithm_(loss_type),
+ uber_loss_algorithm_(loss_type),
n_connection_simulation_(false),
consecutive_rto_count_(0),
consecutive_tlp_count_(0),
@@ -107,20 +112,17 @@
delayed_ack_time_(
QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs)),
rtt_updated_(false),
- acked_packets_iter_(last_ack_frame_.packets.rbegin()),
- aggregate_acked_stream_frames_(
- GetQuicReloadableFlag(quic_aggregate_acked_stream_frames_2)),
- fix_mark_for_loss_retransmission_(
- GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) {
+ acked_packets_iter_(last_ack_frame_.packets.rbegin()) {
SetSendAlgorithm(congestion_control_type);
}
QuicSentPacketManager::~QuicSentPacketManager() {}
void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) {
+ const Perspective perspective = unacked_packets_.perspective();
if (config.HasReceivedInitialRoundTripTimeUs() &&
config.ReceivedInitialRoundTripTimeUs() > 0) {
- if (!config.HasClientSentConnectionOption(kNRTT, perspective_)) {
+ if (!config.HasClientSentConnectionOption(kNRTT, perspective)) {
SetInitialRtt(QuicTime::Delta::FromMicroseconds(
config.ReceivedInitialRoundTripTimeUs()));
}
@@ -129,55 +131,54 @@
SetInitialRtt(QuicTime::Delta::FromMicroseconds(
config.GetInitialRoundTripTimeUsToSend()));
}
- if (config.HasClientSentConnectionOption(kMAD0, perspective_)) {
+ if (config.HasClientSentConnectionOption(kMAD0, perspective)) {
rtt_stats_.set_ignore_max_ack_delay(true);
}
- if (config.HasClientSentConnectionOption(kMAD1, perspective_)) {
+ if (config.HasClientSentConnectionOption(kMAD1, perspective)) {
rtt_stats_.set_initial_max_ack_delay(delayed_ack_time_);
}
- if (config.HasClientSentConnectionOption(kMAD2, perspective_)) {
+ if (config.HasClientSentConnectionOption(kMAD2, perspective)) {
min_tlp_timeout_ = QuicTime::Delta::Zero();
}
- if (config.HasClientSentConnectionOption(kMAD3, perspective_)) {
+ if (config.HasClientSentConnectionOption(kMAD3, perspective)) {
min_rto_timeout_ = QuicTime::Delta::Zero();
}
- if (config.HasClientSentConnectionOption(kMAD4, perspective_)) {
+ if (config.HasClientSentConnectionOption(kMAD4, perspective)) {
ietf_style_tlp_ = true;
}
- if (config.HasClientSentConnectionOption(kMAD5, perspective_)) {
+ if (config.HasClientSentConnectionOption(kMAD5, perspective)) {
ietf_style_2x_tlp_ = true;
}
// Configure congestion control.
- if (config.HasClientRequestedIndependentOption(kTBBR, perspective_)) {
+ if (config.HasClientRequestedIndependentOption(kTBBR, perspective)) {
SetSendAlgorithm(kBBR);
}
- if (config.HasClientRequestedIndependentOption(kRENO, perspective_)) {
+ if (config.HasClientRequestedIndependentOption(kRENO, perspective)) {
SetSendAlgorithm(kRenoBytes);
- } else if (config.HasClientRequestedIndependentOption(kBYTE, perspective_) ||
+ } else if (config.HasClientRequestedIndependentOption(kBYTE, perspective) ||
(GetQuicReloadableFlag(quic_default_to_bbr) &&
- config.HasClientRequestedIndependentOption(kQBIC,
- perspective_))) {
+ config.HasClientRequestedIndependentOption(kQBIC, perspective))) {
SetSendAlgorithm(kCubicBytes);
} else if (GetQuicReloadableFlag(quic_enable_pcc3) &&
- config.HasClientRequestedIndependentOption(kTPCC, perspective_)) {
+ config.HasClientRequestedIndependentOption(kTPCC, perspective)) {
SetSendAlgorithm(kPCC);
}
// Initial window.
if (GetQuicReloadableFlag(quic_unified_iw_options)) {
- if (config.HasClientRequestedIndependentOption(kIW03, perspective_)) {
+ if (config.HasClientRequestedIndependentOption(kIW03, perspective)) {
initial_congestion_window_ = 3;
send_algorithm_->SetInitialCongestionWindowInPackets(3);
}
- if (config.HasClientRequestedIndependentOption(kIW10, perspective_)) {
+ if (config.HasClientRequestedIndependentOption(kIW10, perspective)) {
initial_congestion_window_ = 10;
send_algorithm_->SetInitialCongestionWindowInPackets(10);
}
- if (config.HasClientRequestedIndependentOption(kIW20, perspective_)) {
+ if (config.HasClientRequestedIndependentOption(kIW20, perspective)) {
initial_congestion_window_ = 20;
send_algorithm_->SetInitialCongestionWindowInPackets(20);
}
- if (config.HasClientRequestedIndependentOption(kIW50, perspective_)) {
+ if (config.HasClientRequestedIndependentOption(kIW50, perspective)) {
initial_congestion_window_ = 50;
send_algorithm_->SetInitialCongestionWindowInPackets(50);
}
@@ -185,41 +186,53 @@
using_pacing_ = !FLAGS_quic_disable_pacing_for_perf_tests;
- if (config.HasClientSentConnectionOption(k1CON, perspective_)) {
+ if (config.HasClientSentConnectionOption(k1CON, perspective)) {
send_algorithm_->SetNumEmulatedConnections(1);
}
- if (config.HasClientSentConnectionOption(kNCON, perspective_)) {
+ if (config.HasClientSentConnectionOption(kNCON, perspective)) {
n_connection_simulation_ = true;
}
- if (config.HasClientSentConnectionOption(kNTLP, perspective_)) {
+ if (config.HasClientSentConnectionOption(kNTLP, perspective)) {
max_tail_loss_probes_ = 0;
}
- if (config.HasClientSentConnectionOption(k1TLP, perspective_)) {
+ if (config.HasClientSentConnectionOption(k1TLP, perspective)) {
max_tail_loss_probes_ = 1;
}
- if (config.HasClientSentConnectionOption(k1RTO, perspective_)) {
+ if (config.HasClientSentConnectionOption(k1RTO, perspective)) {
max_rto_packets_ = 1;
}
- if (config.HasClientSentConnectionOption(kTLPR, perspective_)) {
+ if (config.HasClientSentConnectionOption(kTLPR, perspective)) {
enable_half_rtt_tail_loss_probe_ = true;
}
- if (config.HasClientSentConnectionOption(kNRTO, perspective_)) {
+ if (config.HasClientSentConnectionOption(kNRTO, perspective)) {
use_new_rto_ = true;
}
// Configure loss detection.
- if (config.HasClientRequestedIndependentOption(kTIME, perspective_)) {
- general_loss_algorithm_.SetLossDetectionType(kTime);
+ if (config.HasClientRequestedIndependentOption(kTIME, perspective)) {
+ if (unacked_packets_.use_uber_loss_algorithm()) {
+ uber_loss_algorithm_.SetLossDetectionType(kTime);
+ } else {
+ general_loss_algorithm_.SetLossDetectionType(kTime);
+ }
}
- if (config.HasClientRequestedIndependentOption(kATIM, perspective_)) {
- general_loss_algorithm_.SetLossDetectionType(kAdaptiveTime);
+ if (config.HasClientRequestedIndependentOption(kATIM, perspective)) {
+ if (unacked_packets_.use_uber_loss_algorithm()) {
+ uber_loss_algorithm_.SetLossDetectionType(kAdaptiveTime);
+ } else {
+ general_loss_algorithm_.SetLossDetectionType(kAdaptiveTime);
+ }
}
- if (config.HasClientRequestedIndependentOption(kLFAK, perspective_)) {
- general_loss_algorithm_.SetLossDetectionType(kLazyFack);
+ if (config.HasClientRequestedIndependentOption(kLFAK, perspective)) {
+ if (unacked_packets_.use_uber_loss_algorithm()) {
+ uber_loss_algorithm_.SetLossDetectionType(kLazyFack);
+ } else {
+ general_loss_algorithm_.SetLossDetectionType(kLazyFack);
+ }
}
- if (config.HasClientSentConnectionOption(kCONH, perspective_)) {
+ if (config.HasClientSentConnectionOption(kCONH, perspective)) {
conservative_handshake_retransmits_ = true;
}
- send_algorithm_->SetFromConfig(config, perspective_);
+ send_algorithm_->SetFromConfig(config, perspective);
if (network_change_visitor_ != nullptr) {
network_change_visitor_->OnCongestionChange();
@@ -257,13 +270,19 @@
}
}
+void QuicSentPacketManager::SetHandshakeConfirmed() {
+ handshake_confirmed_ = true;
+ if (unacked_packets_.use_uber_loss_algorithm()) {
+ NeuterHandshakePackets();
+ }
+}
+
void QuicSentPacketManager::PostProcessAfterMarkingPacketHandled(
const QuicAckFrame& ack_frame,
QuicTime ack_receive_time,
bool rtt_updated,
QuicByteCount prior_bytes_in_flight) {
- if (aggregate_acked_stream_frames_ && session_decides_what_to_write()) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_aggregate_acked_stream_frames_2, 1, 2);
+ if (session_decides_what_to_write()) {
unacked_packets_.NotifyAggregatedStreamFrameAcked(
last_ack_frame_.ack_delay_time);
}
@@ -305,8 +324,8 @@
if (debug_delegate_ != nullptr) {
debug_delegate_->OnIncomingAck(ack_frame, ack_receive_time,
- unacked_packets_.largest_acked(),
- rtt_updated, GetLeastUnacked());
+ LargestAcked(ack_frame), rtt_updated,
+ GetLeastUnacked());
}
// Remove packets below least unacked from all_packets_acked_ and
// last_ack_frame_.
@@ -343,7 +362,7 @@
for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
it != unacked_packets_.end(); ++it, ++packet_number) {
if ((retransmission_type == ALL_UNACKED_RETRANSMISSION ||
- it->encryption_level == ENCRYPTION_INITIAL) &&
+ it->encryption_level == ENCRYPTION_ZERO_RTT) &&
unacked_packets_.HasRetransmittableFrames(*it)) {
MarkForRetransmission(packet_number, retransmission_type);
}
@@ -380,6 +399,29 @@
}
}
+void QuicSentPacketManager::NeuterHandshakePackets() {
+ DCHECK(unacked_packets_.use_uber_loss_algorithm());
+ QuicPacketNumber packet_number = unacked_packets_.GetLeastUnacked();
+ for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
+ it != unacked_packets_.end(); ++it, ++packet_number) {
+ if (session_decides_what_to_write()) {
+ if (!it->retransmittable_frames.empty() &&
+ unacked_packets_.GetPacketNumberSpace(it->encryption_level) ==
+ HANDSHAKE_DATA) {
+ unacked_packets_.RemoveFromInFlight(packet_number);
+ }
+ continue;
+ }
+ if (unacked_packets_.GetPacketNumberSpace(it->encryption_level) ==
+ HANDSHAKE_DATA &&
+ unacked_packets_.HasRetransmittableFrames(*it)) {
+ pending_retransmissions_.erase(packet_number);
+ unacked_packets_.RemoveFromInFlight(packet_number);
+ unacked_packets_.RemoveRetransmittability(packet_number);
+ }
+ }
+}
+
void QuicSentPacketManager::MarkForRetransmission(
QuicPacketNumber packet_number,
TransmissionType transmission_type) {
@@ -402,8 +444,7 @@
}
if (!session_decides_what_to_write()) {
- if (fix_mark_for_loss_retransmission_ &&
- !unacked_packets_.HasRetransmittableFrames(*transmission_info)) {
+ if (!unacked_packets_.HasRetransmittableFrames(*transmission_info)) {
return;
}
if (!QuicContainsKey(pending_retransmissions_, packet_number)) {
@@ -545,15 +586,12 @@
if (newest_transmission == packet_number) {
// Try to aggregate acked stream frames if acked packet is not a
// retransmission.
- const bool fast_path = aggregate_acked_stream_frames_ &&
- session_decides_what_to_write() &&
+ const bool fast_path = session_decides_what_to_write() &&
info->transmission_type == NOT_RETRANSMISSION;
if (fast_path) {
unacked_packets_.MaybeAggregateAckedStreamFrame(*info, ack_delay_time);
} else {
- if (aggregate_acked_stream_frames_ && session_decides_what_to_write()) {
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_aggregate_acked_stream_frames_2, 2,
- 2);
+ if (session_decides_what_to_write()) {
unacked_packets_.NotifyAggregatedStreamFrameAcked(ack_delay_time);
}
const bool new_data_acked =
@@ -818,19 +856,7 @@
time);
}
- if (fix_mark_for_loss_retransmission_ ||
- unacked_packets_.HasRetransmittableFrames(packet.packet_number)) {
- if (fix_mark_for_loss_retransmission_) {
- QUIC_RELOADABLE_FLAG_COUNT(quic_fix_mark_for_loss_retransmission);
- }
- MarkForRetransmission(packet.packet_number, LOSS_RETRANSMISSION);
- } else {
- // Since we will not retransmit this, we need to remove it from
- // unacked_packets_. This is either the current transmission of
- // a packet whose previous transmission has been acked or a packet that
- // has been TLP retransmitted.
- unacked_packets_.RemoveFromInFlight(packet.packet_number);
- }
+ MarkForRetransmission(packet.packet_number, LOSS_RETRANSMISSION);
}
}
@@ -1143,6 +1169,10 @@
// Unackable packets are skipped earlier.
largest_newly_acked_ = acked_packet.packet_number;
}
+ if (unacked_packets_.use_uber_loss_algorithm()) {
+ unacked_packets_.MaybeUpdateLargestAckedOfPacketNumberSpace(
+ info->encryption_level, acked_packet.packet_number);
+ }
MarkPacketHandled(acked_packet.packet_number, info,
last_ack_frame_.ack_delay_time);
}
diff --git a/quic/core/quic_sent_packet_manager.h b/quic/core/quic_sent_packet_manager.h
index aad16e2..4799e1f 100644
--- a/quic/core/quic_sent_packet_manager.h
+++ b/quic/core/quic_sent_packet_manager.h
@@ -13,11 +13,10 @@
#include <vector>
#include "base/macros.h"
-#include "net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.h"
-#include "net/third_party/quiche/src/quic/core/congestion_control/loss_detection_interface.h"
#include "net/third_party/quiche/src/quic/core/congestion_control/pacing_sender.h"
#include "net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h"
#include "net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h"
+#include "net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.h"
#include "net/third_party/quiche/src/quic/core/proto/cached_network_parameters.proto.h"
#include "net/third_party/quiche/src/quic/core/quic_packets.h"
#include "net/third_party/quiche/src/quic/core/quic_pending_retransmission.h"
@@ -115,7 +114,9 @@
return pacing_sender_.max_pacing_rate();
}
- void SetHandshakeConfirmed() { handshake_confirmed_ = true; }
+ // Set handshake_confirmed_ to true and neuter packets in HANDSHAKE packet
+ // number space.
+ void SetHandshakeConfirmed();
// Requests retransmission of all unacked packets of |retransmission_type|.
// The behavior of this method depends on the value of |retransmission_type|:
@@ -140,6 +141,8 @@
// Removes the retransmittable frames from all unencrypted packets to ensure
// they don't get retransmitted.
+ // TODO(fayang): Consider remove this function when deprecating
+ // quic_use_uber_loss_algorithm.
void NeuterUnencryptedPackets();
// Returns true if there are pending retransmissions.
@@ -473,6 +476,14 @@
// Sets the initial RTT of the connection.
void SetInitialRtt(QuicTime::Delta rtt);
+ // 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.
+ // Only used when quic_use_uber_loss_algorithm is true. Please note, this only
+ // applies to QUIC Crypto and needs to be changed when switches to IETF QUIC
+ // with QUIC TLS.
+ void NeuterHandshakePackets();
+
// Newly serialized retransmittable packets are added to this map, which
// contains owning pointers to any contained frames. If a packet is
// retransmitted, this map will contain entries for both the old and the new
@@ -486,9 +497,6 @@
// Pending retransmissions which have not been packetized and sent yet.
PendingRetransmissionMap pending_retransmissions_;
- // Tracks if the connection was created by the server or the client.
- Perspective perspective_;
-
const QuicClock* clock_;
QuicConnectionStats* stats_;
@@ -499,7 +507,10 @@
std::unique_ptr<SendAlgorithmInterface> send_algorithm_;
// Not owned. Always points to |general_loss_algorithm_| outside of tests.
LossDetectionInterface* loss_algorithm_;
+ // TODO(fayang): Remove general_loss_algorithm_ when deprecating
+ // quic_use_uber_loss_algorithm.
GeneralLossAlgorithm general_loss_algorithm_;
+ UberLossAlgorithm uber_loss_algorithm_;
bool n_connection_simulation_;
// Tracks the first RTO packet. If any packet before that packet gets acked,
@@ -572,12 +583,6 @@
// A reverse iterator of last_ack_frame_.packets. This is reset in
// OnAckRangeStart, and gradually moves in OnAckRange..
PacketNumberQueue::const_reverse_iterator acked_packets_iter_;
-
- // Latched value of quic_aggregate_acked_stream_frames_2 flag.
- const bool aggregate_acked_stream_frames_;
-
- // Latched value of quic_fix_mark_for_loss_retransmission flag.
- const bool fix_mark_for_loss_retransmission_;
};
} // namespace quic
diff --git a/quic/core/quic_sent_packet_manager_test.cc b/quic/core/quic_sent_packet_manager_test.cc
index 97e1697..6ed2078 100644
--- a/quic/core/quic_sent_packet_manager_test.cc
+++ b/quic/core/quic_sent_packet_manager_test.cc
@@ -322,7 +322,7 @@
StrictMock<MockSessionNotifier> notifier_;
};
-INSTANTIATE_TEST_CASE_P(Tests, QuicSentPacketManagerTest, testing::Bool());
+INSTANTIATE_TEST_SUITE_P(Tests, QuicSentPacketManagerTest, testing::Bool());
TEST_P(QuicSentPacketManagerTest, IsUnacked) {
VerifyUnackedPackets(nullptr, 0);
@@ -504,11 +504,9 @@
if (manager_.session_decides_what_to_write()) {
// Frames in all packets are acked.
EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false));
- if (GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) {
- // Notify session that stream frame in packet 2 gets lost although it is
- // not outstanding.
- EXPECT_CALL(notifier_, OnFrameLost(_)).Times(1);
- }
+ // Notify session that stream frame in packet 2 gets lost although it is
+ // not outstanding.
+ EXPECT_CALL(notifier_, OnFrameLost(_)).Times(1);
}
manager_.OnAckFrameStart(QuicPacketNumber(5), QuicTime::Delta::Infinite(),
clock_.Now());
@@ -516,8 +514,7 @@
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
- if (manager_.session_decides_what_to_write() &&
- GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) {
+ if (manager_.session_decides_what_to_write()) {
uint64_t unacked[] = {2};
VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
} else {
@@ -629,11 +626,9 @@
if (manager_.session_decides_what_to_write()) {
// Frames in all packets are acked.
EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false));
- if (GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) {
- // Notify session that stream frame in packet 2 gets lost although it is
- // not outstanding.
- EXPECT_CALL(notifier_, OnFrameLost(_)).Times(1);
- }
+ // Notify session that stream frame in packet 2 gets lost although it is
+ // not outstanding.
+ EXPECT_CALL(notifier_, OnFrameLost(_)).Times(1);
}
manager_.OnAckFrameStart(QuicPacketNumber(5), QuicTime::Delta::Infinite(),
clock_.Now());
@@ -641,8 +636,7 @@
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
- if (manager_.session_decides_what_to_write() &&
- GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) {
+ if (manager_.session_decides_what_to_write()) {
uint64_t unacked[] = {2};
VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
} else {
@@ -873,11 +867,9 @@
if (manager_.session_decides_what_to_write()) {
// Frames in all packets are acked.
EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false));
- if (GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) {
- // Notify session that stream frame in packets 1 and 2 get lost although
- // they are not outstanding.
- EXPECT_CALL(notifier_, OnFrameLost(_)).Times(2);
- }
+ // Notify session that stream frame in packets 1 and 2 get lost although
+ // they are not outstanding.
+ EXPECT_CALL(notifier_, OnFrameLost(_)).Times(2);
}
manager_.OnAckFrameStart(QuicPacketNumber(5), QuicTime::Delta::Infinite(),
clock_.Now());
@@ -980,27 +972,12 @@
true, _, _, Pointwise(PacketNumberEq(), {largest_acked}), _));
EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
if (manager_.session_decides_what_to_write()) {
- if (GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) {
- // Although frames in packet 3 gets acked, it would be kept for another
- // RTT.
- EXPECT_CALL(notifier_, IsFrameOutstanding(_))
- .WillRepeatedly(Return(true));
- } else {
- // Frames in packet 3 gets acked as packet 103 gets acked.
- EXPECT_CALL(notifier_, IsFrameOutstanding(_))
- .WillOnce(Return(true))
- .WillOnce(Return(true))
- .WillOnce(Return(false))
- .WillRepeatedly(Return(true));
- }
- if (GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) {
- // Packets [1, 102] are lost, although stream frame in packet 3 is not
- // outstanding.
- EXPECT_CALL(notifier_, OnFrameLost(_)).Times(102);
- } else {
- // Packets 1, 2 and [4, 102] are lost.
- EXPECT_CALL(notifier_, OnFrameLost(_)).Times(101);
- }
+ // Although frames in packet 3 gets acked, it would be kept for another
+ // RTT.
+ EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(true));
+ // Packets [1, 102] are lost, although stream frame in packet 3 is not
+ // outstanding.
+ EXPECT_CALL(notifier_, OnFrameLost(_)).Times(102);
}
manager_.OnAckFrameStart(QuicPacketNumber(103), QuicTime::Delta::Infinite(),
clock_.Now());
@@ -1363,27 +1340,10 @@
OnPacketLoss(QuicPacketNumber(i), LOSS_RETRANSMISSION, _));
}
if (manager_.session_decides_what_to_write()) {
- if (GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) {
- EXPECT_CALL(notifier_, IsFrameOutstanding(_))
- .WillRepeatedly(Return(true));
- } else {
- EXPECT_CALL(notifier_, IsFrameOutstanding(_))
- .WillOnce(Return(true))
- // This is used for QUIC_BUG_IF in MarkForRetransmission, which is not
- // ideal.
- .WillOnce(Return(true))
- .WillOnce(Return(false))
- .WillRepeatedly(Return(true));
- }
- if (GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) {
- // Packets [1, 99] are considered as lost, although stream frame in packet
- // 2 is not outstanding.
- EXPECT_CALL(notifier_, OnFrameLost(_)).Times(99);
- } else {
- // Packets [1, 99] are considered as lost, but packets 2 does not have
- // retransmittable frames as packet 102 is acked.
- EXPECT_CALL(notifier_, OnFrameLost(_)).Times(98);
- }
+ EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(true));
+ // Packets [1, 99] are considered as lost, although stream frame in packet
+ // 2 is not outstanding.
+ EXPECT_CALL(notifier_, OnFrameLost(_)).Times(99);
}
manager_.OnAckFrameStart(QuicPacketNumber(102), QuicTime::Delta::Zero(),
clock_.Now());
@@ -1492,27 +1452,10 @@
/*lost_packets=*/Not(IsEmpty())));
EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
if (manager_.session_decides_what_to_write()) {
- if (GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) {
- EXPECT_CALL(notifier_, IsFrameOutstanding(_))
- .WillRepeatedly(Return(true));
- } else {
- EXPECT_CALL(notifier_, IsFrameOutstanding(_))
- .WillOnce(Return(true))
- // This is used for QUIC_BUG_IF in MarkForRetransmission, which is not
- // ideal.
- .WillOnce(Return(true))
- .WillOnce(Return(false))
- .WillRepeatedly(Return(true));
- }
- if (GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) {
- // Packets [1, 99] are considered as lost, although stream frame in packet
- // 2 is not outstanding.
- EXPECT_CALL(notifier_, OnFrameLost(_)).Times(99);
- } else {
- // Packets [1, 99] are considered as lost, but packets 2 does not have
- // retransmittable frames as packet 102 is acked.
- EXPECT_CALL(notifier_, OnFrameLost(_)).Times(98);
- }
+ EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(true));
+ // Packets [1, 99] are considered as lost, although stream frame in packet
+ // 2 is not outstanding.
+ EXPECT_CALL(notifier_, OnFrameLost(_)).Times(99);
}
manager_.OnAckFrameStart(QuicPacketNumber(102), QuicTime::Delta::Zero(),
clock_.Now());
diff --git a/quic/core/quic_session.cc b/quic/core/quic_session.cc
index b5e88ff..2eb67e7 100644
--- a/quic/core/quic_session.cc
+++ b/quic/core/quic_session.cc
@@ -151,6 +151,10 @@
handler.stream->OnStreamFrame(frame);
}
+void QuicSession::OnCryptoFrame(const QuicCryptoFrame& frame) {
+ GetMutableCryptoStream()->OnCryptoFrame(frame);
+}
+
bool QuicSession::OnStopSendingFrame(const QuicStopSendingFrame& frame) {
// We are not version 99. In theory, if not in version 99 then the framer
// could not call OnStopSending... This is just a check that is good when
@@ -231,7 +235,6 @@
static_cast<quic::QuicRstStreamErrorCode>(frame.application_error_code),
stream->stream_bytes_written(),
/*close_write_side_only=*/true);
- stream->set_rst_sent(true);
return true;
}
@@ -585,16 +588,13 @@
// Send a RST_STREAM frame plus, if version 99, an IETF
// QUIC STOP_SENDING frame. Both sre sent to emulate
// the two-way close that Google QUIC's RST_STREAM does.
- QuicConnection::ScopedPacketFlusher* flusher =
- (connection_->transport_version() == QUIC_VERSION_99)
- ? new QuicConnection::ScopedPacketFlusher(
- connection(), QuicConnection::SEND_ACK_IF_QUEUED)
- : nullptr;
- control_frame_manager_.WriteOrBufferRstStreamStopSending(id, error,
- bytes_written);
- if (flusher) {
- delete flusher;
- flusher = nullptr;
+ if (connection_->transport_version() == QUIC_VERSION_99) {
+ QuicConnection::ScopedPacketFlusher flusher(
+ connection(), QuicConnection::SEND_ACK_IF_QUEUED);
+ control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written);
+ control_frame_manager_.WriteOrBufferStopSending(error, id);
+ } else {
+ control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written);
}
}
connection_->OnStreamReset(id, error);
@@ -603,17 +603,20 @@
OnStreamDoneWaitingForAcks(id);
return;
}
- if (close_write_side_only) {
- DCHECK_EQ(QUIC_VERSION_99, connection_->transport_version());
- DynamicStreamMap::iterator it = dynamic_stream_map_.find(id);
- if (it != dynamic_stream_map_.end()) {
- QuicStream* stream = it->second.get();
- if (stream) {
- stream->CloseWriteSide();
- }
- }
- } else {
+
+ if (!close_write_side_only) {
CloseStreamInner(id, true);
+ return;
+ }
+ DCHECK_EQ(QUIC_VERSION_99, connection_->transport_version());
+
+ DynamicStreamMap::iterator it = dynamic_stream_map_.find(id);
+ if (it != dynamic_stream_map_.end()) {
+ QuicStream* stream = it->second.get();
+ if (stream) {
+ stream->set_rst_sent(true);
+ stream->CloseWriteSide();
+ }
}
}
@@ -1366,6 +1369,10 @@
OnMessageAcked(frame.message_frame->message_id);
return true;
}
+ if (frame.type == CRYPTO_FRAME) {
+ return GetMutableCryptoStream()->OnCryptoFrameAcked(*frame.crypto_frame,
+ ack_delay_time);
+ }
if (frame.type != STREAM_FRAME) {
return control_frame_manager_.OnControlFrameAcked(frame);
}
@@ -1373,9 +1380,10 @@
QuicStream* stream = GetStream(frame.stream_frame.stream_id);
// Stream can already be reset when sent frame gets acked.
if (stream != nullptr) {
+ QuicByteCount newly_acked_length = 0;
new_stream_data_acked = stream->OnStreamFrameAcked(
frame.stream_frame.offset, frame.stream_frame.data_length,
- frame.stream_frame.fin, ack_delay_time);
+ frame.stream_frame.fin, ack_delay_time, &newly_acked_length);
if (!stream->HasPendingRetransmission()) {
streams_with_pending_retransmission_.erase(stream->id());
}
@@ -1402,6 +1410,10 @@
OnMessageLost(frame.message_frame->message_id);
return;
}
+ if (frame.type == CRYPTO_FRAME) {
+ GetMutableCryptoStream()->OnCryptoFrameLost(frame.crypto_frame);
+ return;
+ }
if (frame.type != STREAM_FRAME) {
control_frame_manager_.OnControlFrameLost(frame);
return;
@@ -1431,6 +1443,10 @@
// Do not retransmit MESSAGE frames.
continue;
}
+ if (frame.type == CRYPTO_FRAME) {
+ GetMutableCryptoStream()->RetransmitData(frame.crypto_frame);
+ continue;
+ }
if (frame.type != STREAM_FRAME) {
if (!control_frame_manager_.RetransmitControlFrame(frame)) {
break;
@@ -1451,6 +1467,11 @@
if (frame.type == MESSAGE_FRAME) {
return false;
}
+ if (frame.type == CRYPTO_FRAME) {
+ return GetCryptoStream()->IsFrameOutstanding(
+ frame.crypto_frame->level, frame.crypto_frame->offset,
+ frame.crypto_frame->data_length);
+ }
if (frame.type != STREAM_FRAME) {
return control_frame_manager_.IsControlFrameOutstanding(frame);
}
@@ -1495,21 +1516,27 @@
QuicStreamOffset offset,
QuicByteCount data_length,
QuicDataWriter* writer) {
- QUIC_BUG << "QuicSession::WriteCryptoData is unimplemented";
- return false;
+ return GetMutableCryptoStream()->WriteCryptoFrame(level, offset, data_length,
+ writer);
}
QuicUint128 QuicSession::GetStatelessResetToken() const {
- if (!QuicConnectionIdSupportsVariableLength(perspective())) {
- return QuicConnectionIdToUInt64(connection_->connection_id());
- }
return QuicUtils::GenerateStatelessResetToken(connection_->connection_id());
}
bool QuicSession::RetransmitLostData() {
QuicConnection::ScopedPacketFlusher retransmission_flusher(
connection_, QuicConnection::SEND_ACK_IF_QUEUED);
- if (QuicContainsKey(
+ // Retransmit crypto data first.
+ bool uses_crypto_frames = connection_->transport_version() >= QUIC_VERSION_47;
+ QuicCryptoStream* crypto_stream = GetMutableCryptoStream();
+ if (uses_crypto_frames && crypto_stream->HasPendingCryptoRetransmission()) {
+ 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(connection_->transport_version()))) {
SetTransmissionType(HANDSHAKE_RETRANSMISSION);
@@ -1579,7 +1606,7 @@
connection_->SetTransmissionType(type);
}
-MessageResult QuicSession::SendMessage(QuicStringPiece message) {
+MessageResult QuicSession::SendMessage(QuicMemSliceSpan message) {
if (!IsEncryptionEstablished()) {
return {MESSAGE_STATUS_ENCRYPTION_NOT_ESTABLISHED, 0};
}
diff --git a/quic/core/quic_session.h b/quic/core/quic_session.h
index 23778e7..cb0f0a7 100644
--- a/quic/core/quic_session.h
+++ b/quic/core/quic_session.h
@@ -77,7 +77,7 @@
// ENCRYPTION_REESTABLISHED indicates that a client hello was rejected by
// the server and thus the encryption key has been updated. Therefore the
// connection should resend any packets that were sent under
- // ENCRYPTION_INITIAL. (Client only.)
+ // ENCRYPTION_ZERO_RTT. (Client only.)
ENCRYPTION_REESTABLISHED,
// HANDSHAKE_CONFIRMED, in a client, indicates the server has accepted
// our handshake. In a server it indicates that a full, valid client hello
@@ -99,6 +99,7 @@
// QuicConnectionVisitorInterface methods:
void OnStreamFrame(const QuicStreamFrame& frame) override;
+ void OnCryptoFrame(const QuicCryptoFrame& frame) override;
void OnRstStream(const QuicRstStreamFrame& frame) override;
void OnGoAway(const QuicGoAwayFrame& frame) override;
void OnMessageReceived(QuicStringPiece message) override;
@@ -165,11 +166,17 @@
QuicStreamOffset offset,
StreamSendingState state);
- // Called by application to send |message|. Returns the message result which
- // includes the message status and message ID (valid if the write succeeds).
- // SendMessage flushes a message packet even it is not full. If the
- // application wants to bundle other data in the same packet, please consider
- // adding a packet flusher around the SendMessage and/or WritevData calls.
+ // Called by application to send |message|. Data copy can be avoided if
+ // |message| is provided in reference counted memory.
+ // Please note, |message| provided in reference counted memory would be moved
+ // internally when message is successfully sent. Thereafter, it would be
+ // undefined behavior if callers try to access the slices through their own
+ // copy of the span object.
+ // Returns the message result which includes the message status and message ID
+ // (valid if the write succeeds). SendMessage flushes a message packet even it
+ // is not full. If the application wants to bundle other data in the same
+ // packet, please consider adding a packet flusher around the SendMessage
+ // and/or WritevData calls.
//
// OnMessageAcked and OnMessageLost are called when a particular message gets
// acked or lost.
@@ -179,7 +186,7 @@
// blocked. In this case the caller can retry sending message again when
// connection becomes available, for example after getting OnCanWrite()
// callback.
- MessageResult SendMessage(QuicStringPiece message);
+ MessageResult SendMessage(QuicMemSliceSpan message);
// Called when message with |message_id| gets acked.
virtual void OnMessageAcked(QuicMessageId message_id);
@@ -381,6 +388,17 @@
return num_locally_closed_incoming_streams_highest_offset_;
}
+ // Does actual work of sending reset-stream or reset-stream&stop-sending
+ // If the connection is not version 99/IETF QUIC, will always send a
+ // RESET_STREAM and close_write_side_only is ignored. If the connection is
+ // IETF QUIC/Version 99 then will send a RESET_STREAM and STOP_SENDING if
+ // close_write_side_only is false, just a RESET_STREAM if
+ // close_write_side_only is true.
+ virtual void SendRstStreamInner(QuicStreamId id,
+ QuicRstStreamErrorCode error,
+ QuicStreamOffset bytes_written,
+ bool close_write_side_only);
+
protected:
using StaticStreamMap = QuicSmallMap<QuicStreamId, QuicStream*, 2>;
@@ -571,17 +589,6 @@
// Closes the pending stream |stream_id| before it has been created.
void ClosePendingStream(QuicStreamId stream_id);
- // Does actual work of sending reset-stream or reset-stream&stop-sending
- // If the connection is not version 99/IETF QUIC, will always send a
- // RESET_STREAM and close_write_side_only is ignored. If the connection is
- // IETF QUIC/Version 99 then will send a RESET_STREAM and STOP_SENDING if
- // close_write_side_only is false, just a RESET_STREAM if
- // close_write_side_only is true.
- void SendRstStreamInner(QuicStreamId id,
- QuicRstStreamErrorCode error,
- QuicStreamOffset bytes_written,
- bool close_write_side_only);
-
// Keep track of highest received byte offset of locally closed streams, while
// waiting for a definitive final highest offset from the peer.
std::map<QuicStreamId, QuicStreamOffset>
diff --git a/quic/core/quic_session_test.cc b/quic/core/quic_session_test.cc
index 6bf26ab..ddd5a2b 100644
--- a/quic/core/quic_session_test.cc
+++ b/quic/core/quic_session_test.cc
@@ -98,6 +98,7 @@
}
MOCK_METHOD0(OnCanWrite, void());
+ bool HasPendingCryptoRetransmission() override { return false; }
MOCK_CONST_METHOD0(HasPendingRetransmission, bool());
@@ -191,10 +192,11 @@
return nullptr;
}
- TestStream* stream = new TestStream(
- id, this,
- DetermineStreamType(id, connection()->transport_version(),
- /*is_incoming=*/true, BIDIRECTIONAL));
+ TestStream* stream =
+ new TestStream(id, this,
+ DetermineStreamType(
+ id, connection()->transport_version(), perspective(),
+ /*is_incoming=*/true, BIDIRECTIONAL));
ActivateStream(QuicWrapUnique(stream));
++num_incoming_streams_created_;
return stream;
@@ -202,10 +204,11 @@
TestStream* CreateIncomingStream(PendingStream pending) override {
QuicStreamId id = pending.id();
- TestStream* stream = new TestStream(
- std::move(pending),
- DetermineStreamType(id, connection()->transport_version(),
- /*is_incoming=*/true, BIDIRECTIONAL));
+ TestStream* stream =
+ new TestStream(std::move(pending),
+ DetermineStreamType(
+ id, connection()->transport_version(), perspective(),
+ /*is_incoming=*/true, BIDIRECTIONAL));
ActivateStream(QuicWrapUnique(stream));
++num_incoming_streams_created_;
return stream;
@@ -335,7 +338,8 @@
void CloseStream(QuicStreamId id) {
if (session_.connection()->transport_version() == QUIC_VERSION_99 &&
- QuicUtils::GetStreamType(id, session_.IsIncomingStream(id)) ==
+ QuicUtils::GetStreamType(id, session_.perspective(),
+ session_.IsIncomingStream(id)) ==
READ_UNIDIRECTIONAL) {
// Verify reset is not sent for READ_UNIDIRECTIONAL streams.
EXPECT_CALL(*connection_, SendControlFrame(_)).Times(0);
@@ -446,9 +450,9 @@
QuicFramer client_framer_;
};
-INSTANTIATE_TEST_CASE_P(Tests,
- QuicSessionTestServer,
- ::testing::ValuesIn(AllSupportedVersions()));
+INSTANTIATE_TEST_SUITE_P(Tests,
+ QuicSessionTestServer,
+ ::testing::ValuesIn(AllSupportedVersions()));
TEST_P(QuicSessionTestServer, PeerAddress) {
EXPECT_EQ(QuicSocketAddress(QuicIpAddress::Loopback4(), kTestPort),
@@ -456,7 +460,7 @@
}
TEST_P(QuicSessionTestServer, SelfAddress) {
- EXPECT_EQ(QuicSocketAddress(), session_.self_address());
+ EXPECT_TRUE(session_.self_address().IsInitialized());
}
TEST_P(QuicSessionTestServer, DontCallOnWriteBlockedForDisconnectedConnection) {
@@ -913,8 +917,6 @@
MockPacketWriter* writer = static_cast<MockPacketWriter*>(
QuicConnectionPeer::GetWriter(session_.connection()));
EXPECT_CALL(*writer, IsWriteBlocked()).WillRepeatedly(Return(true));
- EXPECT_CALL(*writer, IsWriteBlockedDataBuffered())
- .WillRepeatedly(Return(true));
EXPECT_CALL(*writer, WritePacket(_, _, _, _, _)).Times(0);
TestStream* stream2 = session_.CreateOutgoingBidirectionalStream();
@@ -1237,6 +1239,12 @@
}
TEST_P(QuicSessionTestServer, HandshakeUnblocksFlowControlBlockedCryptoStream) {
+ if (GetParam().transport_version >= QUIC_VERSION_46) {
+ // QUIC version 46 onwards uses CRYPTO frames for the handshake, so this
+ // test doesn't make sense for those versions since CRYPTO frames aren't
+ // flow controlled.
+ return;
+ }
// Test that if the crypto stream is flow control blocked, then if the SHLO
// contains a larger send window offset, the stream becomes unblocked.
session_.set_writev_consumes_all_data(true);
@@ -1290,19 +1298,11 @@
const QuicStreamOffset kByteOffset =
1 + kInitialSessionFlowControlWindowForTest / 2;
- if (transport_version() == QUIC_VERSION_99) {
- // Two more control frames than in Google QUIC, one is the STOP_SENDING
- // frame, the other is the RST_STREAM generated in response.
- EXPECT_CALL(*connection_, SendControlFrame(_))
- .Times(4)
- .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame));
- EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _)).Times(2);
- } else {
- EXPECT_CALL(*connection_, SendControlFrame(_))
- .Times(2)
- .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame));
- EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _));
- }
+ EXPECT_CALL(*connection_, SendControlFrame(_))
+ .Times(2)
+ .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame));
+ EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _));
+
QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream->id(),
QUIC_STREAM_CANCELLED, kByteOffset);
session_.OnRstStream(rst_frame);
@@ -1624,9 +1624,9 @@
QuicSessionTestClient() : QuicSessionTestBase(Perspective::IS_CLIENT) {}
};
-INSTANTIATE_TEST_CASE_P(Tests,
- QuicSessionTestClient,
- ::testing::ValuesIn(AllSupportedVersions()));
+INSTANTIATE_TEST_SUITE_P(Tests,
+ QuicSessionTestClient,
+ ::testing::ValuesIn(AllSupportedVersions()));
TEST_P(QuicSessionTestClient, AvailableBidirectionalStreamsClient) {
ASSERT_TRUE(session_.GetOrCreateDynamicStream(
@@ -1741,20 +1741,18 @@
QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream2->id(),
QUIC_STREAM_CANCELLED, 1234);
+ // Just for the RST_STREAM
+ EXPECT_CALL(*connection_, SendControlFrame(_))
+ .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame));
if (transport_version() == QUIC_VERSION_99) {
- // Once for the RST_STREAM, once for the STOP_SENDING
- EXPECT_CALL(*connection_, SendControlFrame(_))
- .Times(3)
- .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame));
- EXPECT_CALL(*connection_, OnStreamReset(stream2->id(), _)).Times(2);
+ EXPECT_CALL(*connection_,
+ OnStreamReset(stream2->id(), QUIC_STREAM_CANCELLED));
} else {
- // Just for the RST_STREAM
- EXPECT_CALL(*connection_, SendControlFrame(_))
- .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame));
EXPECT_CALL(*connection_,
OnStreamReset(stream2->id(), QUIC_RST_ACKNOWLEDGEMENT));
}
stream2->OnStreamReset(rst_frame);
+
if (transport_version() == QUIC_VERSION_99) {
// The test is predicated on the stream being fully closed. For V99, the
// RST_STREAM only does one side (the read side from the perspective of the
@@ -1810,11 +1808,18 @@
// Lost data on cryption stream, streams 2 and 4.
EXPECT_CALL(*stream4, HasPendingRetransmission()).WillOnce(Return(true));
- EXPECT_CALL(*crypto_stream, HasPendingRetransmission())
- .WillOnce(Return(true));
+ if (connection_->transport_version() < QUIC_VERSION_47) {
+ EXPECT_CALL(*crypto_stream, HasPendingRetransmission())
+ .WillOnce(Return(true));
+ }
EXPECT_CALL(*stream2, HasPendingRetransmission()).WillOnce(Return(true));
session_.OnFrameLost(QuicFrame(frame3));
- session_.OnFrameLost(QuicFrame(frame1));
+ if (connection_->transport_version() < QUIC_VERSION_47) {
+ session_.OnFrameLost(QuicFrame(frame1));
+ } else {
+ QuicCryptoFrame crypto_frame(ENCRYPTION_NONE, 0, 1300);
+ session_.OnFrameLost(QuicFrame(&crypto_frame));
+ }
session_.OnFrameLost(QuicFrame(frame2));
EXPECT_TRUE(session_.WillingAndAbleToWrite());
@@ -1826,9 +1831,11 @@
// stream go first.
// Do not check congestion window when crypto stream has lost data.
EXPECT_CALL(*send_algorithm, CanSend(_)).Times(0);
- EXPECT_CALL(*crypto_stream, OnCanWrite());
- EXPECT_CALL(*crypto_stream, HasPendingRetransmission())
- .WillOnce(Return(false));
+ if (connection_->transport_version() < QUIC_VERSION_47) {
+ EXPECT_CALL(*crypto_stream, OnCanWrite());
+ EXPECT_CALL(*crypto_stream, HasPendingRetransmission())
+ .WillOnce(Return(false));
+ }
// Check congestion window for non crypto streams.
EXPECT_CALL(*send_algorithm, CanSend(_)).WillOnce(Return(true));
EXPECT_CALL(*stream4, OnCanWrite());
@@ -1962,8 +1969,11 @@
TEST_P(QuicSessionTestServer, SendMessage) {
// Cannot send message when encryption is not established.
EXPECT_FALSE(session_.IsCryptoHandshakeConfirmed());
+ quic::QuicMemSliceStorage storage(nullptr, 0, nullptr, 0);
EXPECT_EQ(MessageResult(MESSAGE_STATUS_ENCRYPTION_NOT_ESTABLISHED, 0),
- session_.SendMessage(""));
+ session_.SendMessage(
+ MakeSpan(connection_->helper()->GetStreamSendBufferAllocator(),
+ "", &storage)));
// Finish handshake.
CryptoHandshakeMessage handshake_message;
@@ -1971,23 +1981,29 @@
EXPECT_TRUE(session_.IsCryptoHandshakeConfirmed());
QuicStringPiece message;
- QuicMessageFrame frame(1, message);
EXPECT_CALL(*connection_, SendMessage(1, _))
.WillOnce(Return(MESSAGE_STATUS_SUCCESS));
EXPECT_EQ(MessageResult(MESSAGE_STATUS_SUCCESS, 1),
- session_.SendMessage(message));
+ session_.SendMessage(
+ MakeSpan(connection_->helper()->GetStreamSendBufferAllocator(),
+ message, &storage)));
// Verify message_id increases.
EXPECT_CALL(*connection_, SendMessage(2, _))
.WillOnce(Return(MESSAGE_STATUS_TOO_LARGE));
EXPECT_EQ(MessageResult(MESSAGE_STATUS_TOO_LARGE, 0),
- session_.SendMessage(message));
+ session_.SendMessage(
+ MakeSpan(connection_->helper()->GetStreamSendBufferAllocator(),
+ message, &storage)));
// Verify unsent message does not consume a message_id.
EXPECT_CALL(*connection_, SendMessage(2, _))
.WillOnce(Return(MESSAGE_STATUS_SUCCESS));
- QuicMessageFrame frame2(2, message);
EXPECT_EQ(MessageResult(MESSAGE_STATUS_SUCCESS, 2),
- session_.SendMessage(message));
+ session_.SendMessage(
+ MakeSpan(connection_->helper()->GetStreamSendBufferAllocator(),
+ message, &storage)));
+ QuicMessageFrame frame(1);
+ QuicMessageFrame frame2(2);
EXPECT_FALSE(session_.IsFrameOutstanding(QuicFrame(&frame)));
EXPECT_FALSE(session_.IsFrameOutstanding(QuicFrame(&frame2)));
@@ -2313,7 +2329,7 @@
QuicStreamId stream_id = stream->id();
QuicStopSendingFrame frame(1, stream_id, 123);
EXPECT_CALL(*stream, OnStopSending(123));
- // Expect a reset to come back out.xxxxx
+ // Expect a reset to come back out.
EXPECT_CALL(*connection_, SendControlFrame(_));
EXPECT_CALL(
*connection_,
diff --git a/quic/core/quic_stream.cc b/quic/core/quic_stream.cc
index 6c8ea8d..70af656 100644
--- a/quic/core/quic_stream.cc
+++ b/quic/core/quic_stream.cc
@@ -23,12 +23,6 @@
namespace {
-struct iovec MakeIovec(QuicStringPiece data) {
- struct iovec iov = {const_cast<char*>(data.data()),
- static_cast<size_t>(data.size())};
- return iov;
-}
-
size_t GetInitialStreamFlowControlWindowToSend(QuicSession* session) {
return session->config()->GetInitialStreamFlowControlWindowToSend();
}
@@ -236,20 +230,16 @@
stream_contributes_to_connection_flow_control_(true),
busy_counter_(0),
add_random_padding_after_fin_(false),
- ack_listener_(nullptr),
send_buffer_(
session->connection()->helper()->GetStreamSendBufferAllocator()),
buffered_data_threshold_(GetQuicFlag(FLAGS_quic_buffered_data_threshold)),
is_static_(is_static),
deadline_(QuicTime::Zero()),
type_(session->connection()->transport_version() == QUIC_VERSION_99
- ? QuicUtils::GetStreamType(id_, session->IsIncomingStream(id_))
+ ? QuicUtils::GetStreamType(id_,
+ perspective_,
+ session->IsIncomingStream(id_))
: type) {
- if (session->connection()->transport_version() == QUIC_VERSION_99) {
- DCHECK_EQ(type,
- QuicUtils::GetStreamType(id_, session->IsIncomingStream(id_)))
- << id_;
- }
if (type_ == WRITE_UNIDIRECTIONAL) {
set_fin_received(true);
CloseReadSide();
@@ -453,7 +443,7 @@
// Do not respect buffered data upper limit as WriteOrBufferData guarantees
// all data to be consumed.
if (data.length() > 0) {
- struct iovec iov(MakeIovec(data));
+ struct iovec iov(QuicUtils::MakeIovec(data));
QuicStreamOffset offset = send_buffer_.stream_offset();
if (kMaxStreamLength - offset < data.length()) {
QUIC_BUG << "Write too many data via stream " << id_;
@@ -783,13 +773,14 @@
bool QuicStream::OnStreamFrameAcked(QuicStreamOffset offset,
QuicByteCount data_length,
bool fin_acked,
- QuicTime::Delta ack_delay_time) {
+ QuicTime::Delta ack_delay_time,
+ QuicByteCount* newly_acked_length) {
QUIC_DVLOG(1) << ENDPOINT << "stream " << id_ << " Acking "
<< "[" << offset << ", " << offset + data_length << "]"
<< " fin = " << fin_acked;
- QuicByteCount newly_acked_length = 0;
+ *newly_acked_length = 0;
if (!send_buffer_.OnStreamDataAcked(offset, data_length,
- &newly_acked_length)) {
+ newly_acked_length)) {
CloseConnectionWithDetails(QUIC_INTERNAL_ERROR,
"Trying to ack unsent data.");
return false;
@@ -801,7 +792,7 @@
}
// Indicates whether ack listener's OnPacketAcked should be called.
const bool new_data_acked =
- newly_acked_length > 0 || (fin_acked && fin_outstanding_);
+ *newly_acked_length > 0 || (fin_acked && fin_outstanding_);
if (fin_acked) {
fin_outstanding_ = false;
fin_lost_ = false;
@@ -809,9 +800,6 @@
if (!IsWaitingForAcks()) {
session_->OnStreamDoneWaitingForAcks(id_);
}
- if (ack_listener_ != nullptr && new_data_acked) {
- ack_listener_->OnPacketAcked(newly_acked_length, ack_delay_time);
- }
return new_data_acked;
}
@@ -822,9 +810,6 @@
if (fin_retransmitted) {
fin_lost_ = false;
}
- if (ack_listener_ != nullptr) {
- ack_listener_->OnPacketRetransmitted(data_length);
- }
}
void QuicStream::OnStreamFrameLost(QuicStreamOffset offset,
diff --git a/quic/core/quic_stream.h b/quic/core/quic_stream.h
index 13a6b2c..fe0a794 100644
--- a/quic/core/quic_stream.h
+++ b/quic/core/quic_stream.h
@@ -286,12 +286,13 @@
QuicDataWriter* writer);
// Called when data [offset, offset + data_length) is acked. |fin_acked|
- // indicates whether the fin is acked. Returns true if any new stream data
- // (including fin) gets acked.
+ // indicates whether the fin is acked. Returns true and updates
+ // |newly_acked_length| if any new stream data (including fin) gets acked.
virtual bool OnStreamFrameAcked(QuicStreamOffset offset,
QuicByteCount data_length,
bool fin_acked,
- QuicTime::Delta ack_delay_time);
+ QuicTime::Delta ack_delay_time,
+ QuicByteCount* newly_acked_length);
// Called when data [offset, offset + data_length) was retransmitted.
// |fin_retransmitted| indicates whether fin was retransmitted.
@@ -413,11 +414,6 @@
stream_contributes_to_connection_flow_control_ = false;
}
- void set_ack_listener(
- QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
- ack_listener_ = std::move(ack_listener);
- }
-
const QuicIntervalSet<QuicStreamOffset>& bytes_acked() const;
const QuicStreamSendBuffer& send_buffer() const { return send_buffer_; }
@@ -521,10 +517,6 @@
// stream.
bool add_random_padding_after_fin_;
- // Ack listener of this stream, and it is notified when any of written bytes
- // are acked.
- QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener_;
-
// Send buffer of this stream. Send buffer is cleaned up when data gets acked
// or discarded.
QuicStreamSendBuffer send_buffer_;
diff --git a/quic/core/quic_stream_id_manager_test.cc b/quic/core/quic_stream_id_manager_test.cc
index 5647d75..51799e2 100644
--- a/quic/core/quic_stream_id_manager_test.cc
+++ b/quic/core/quic_stream_id_manager_test.cc
@@ -63,6 +63,7 @@
TestQuicStream* stream = new TestQuicStream(
id, this,
DetermineStreamType(id, connection()->transport_version(),
+ perspective(),
/*is_incoming=*/true, BIDIRECTIONAL));
ActivateStream(QuicWrapUnique(stream));
return stream;
@@ -170,7 +171,7 @@
: QuicStreamIdManagerTestBase(Perspective::IS_CLIENT) {}
};
-INSTANTIATE_TEST_CASE_P(Tests, QuicStreamIdManagerTestClient, testing::Bool());
+INSTANTIATE_TEST_SUITE_P(Tests, QuicStreamIdManagerTestClient, testing::Bool());
// Check that the parameters used by the stream ID manager are properly
// initialized.
@@ -618,7 +619,7 @@
: QuicStreamIdManagerTestBase(Perspective::IS_SERVER) {}
};
-INSTANTIATE_TEST_CASE_P(Tests, QuicStreamIdManagerTestServer, testing::Bool());
+INSTANTIATE_TEST_SUITE_P(Tests, QuicStreamIdManagerTestServer, testing::Bool());
// This test checks that the initialization for the maximum allowed outgoing
// stream id is correct.
diff --git a/quic/core/quic_stream_send_buffer.cc b/quic/core/quic_stream_send_buffer.cc
index 628439a..efe6240 100644
--- a/quic/core/quic_stream_send_buffer.cc
+++ b/quic/core/quic_stream_send_buffer.cc
@@ -6,12 +6,12 @@
#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/core/quic_interval.h"
#include "net/third_party/quiche/src/quic/core/quic_stream_send_buffer.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
#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_interval.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
namespace quic {
diff --git a/quic/core/quic_stream_send_buffer.h b/quic/core/quic_stream_send_buffer.h
index 7b6a9c9..4bcac34 100644
--- a/quic/core/quic_stream_send_buffer.h
+++ b/quic/core/quic_stream_send_buffer.h
@@ -6,6 +6,7 @@
#define QUICHE_QUIC_CORE_QUIC_STREAM_SEND_BUFFER_H_
#include "net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h"
+#include "net/third_party/quiche/src/quic/core/quic_interval_set.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_iovec.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice.h"
diff --git a/quic/core/quic_stream_sequencer.cc b/quic/core/quic_stream_sequencer.cc
index cfd288d..6311dcf 100644
--- a/quic/core/quic_stream_sequencer.cc
+++ b/quic/core/quic_stream_sequencer.cc
@@ -47,12 +47,23 @@
return;
}
}
+ OnFrameData(byte_offset, data_len, frame.data_buffer);
+}
+
+void QuicStreamSequencer::OnCryptoFrame(const QuicCryptoFrame& frame) {
+ ++num_frames_received_;
+ OnFrameData(frame.offset, frame.data_length, frame.data_buffer);
+}
+
+void QuicStreamSequencer::OnFrameData(QuicStreamOffset byte_offset,
+ size_t data_len,
+ const char* data_buffer) {
const size_t previous_readable_bytes = buffered_frames_.ReadableBytes();
size_t bytes_written;
QuicString error_details;
QuicErrorCode result = buffered_frames_.OnStreamData(
- byte_offset, QuicStringPiece(frame.data_buffer, frame.data_length),
- &bytes_written, &error_details);
+ byte_offset, QuicStringPiece(data_buffer, data_len), &bytes_written,
+ &error_details);
if (result != QUIC_NO_ERROR) {
QuicString details = QuicStrCat(
"Stream ", stream_->id(), ": ", QuicErrorCodeToString(result), ": ",
diff --git a/quic/core/quic_stream_sequencer.h b/quic/core/quic_stream_sequencer.h
index dfe5e7d..3feee5e 100644
--- a/quic/core/quic_stream_sequencer.h
+++ b/quic/core/quic_stream_sequencer.h
@@ -64,6 +64,13 @@
// buffered.
void OnStreamFrame(const QuicStreamFrame& frame);
+ // If the frame is the next one we need in order to process in-order data,
+ // ProcessData will be immediately called on the crypto stream until all
+ // buffered data is processed or the crypto stream fails to consume data. Any
+ // unconsumed data will be buffered. If the frame is not the next in line, it
+ // will be buffered.
+ void OnCryptoFrame(const QuicCryptoFrame& frame);
+
// Once data is buffered, it's up to the stream to read it when the stream
// can handle more data. The following three functions make that possible.
@@ -162,6 +169,11 @@
// the stream of FIN, and clear buffers.
bool MaybeCloseStream();
+ // Shared implementation between OnStreamFrame and OnCryptoFrame.
+ void OnFrameData(QuicStreamOffset byte_offset,
+ size_t data_len,
+ const char* data_buffer);
+
// The stream which owns this sequencer.
StreamInterface* stream_;
diff --git a/quic/core/quic_stream_sequencer_buffer.cc b/quic/core/quic_stream_sequencer_buffer.cc
index b96a89a..2f09095 100644
--- a/quic/core/quic_stream_sequencer_buffer.cc
+++ b/quic/core/quic_stream_sequencer_buffer.cc
@@ -4,10 +4,11 @@
#include "net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.h"
+#include "net/third_party/quiche/src/quic/core/quic_constants.h"
+#include "net/third_party/quiche/src/quic/core/quic_interval.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_interval.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
diff --git a/quic/core/quic_stream_sequencer_buffer.h b/quic/core/quic_stream_sequencer_buffer.h
index 900fad0..09646b9 100644
--- a/quic/core/quic_stream_sequencer_buffer.h
+++ b/quic/core/quic_stream_sequencer_buffer.h
@@ -64,6 +64,7 @@
#include <memory>
#include "base/macros.h"
+#include "net/third_party/quiche/src/quic/core/quic_interval_set.h"
#include "net/third_party/quiche/src/quic/core/quic_packets.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
diff --git a/quic/core/quic_stream_test.cc b/quic/core/quic_stream_test.cc
index e8338b3..d019f71 100644
--- a/quic/core/quic_stream_test.cc
+++ b/quic/core/quic_stream_test.cc
@@ -61,7 +61,6 @@
using QuicStream::CloseWriteSide;
using QuicStream::fin_buffered;
using QuicStream::OnClose;
- using QuicStream::set_ack_listener;
using QuicStream::WriteMemSlices;
using QuicStream::WriteOrBufferData;
using QuicStream::WritevData;
@@ -160,17 +159,16 @@
// Index value of 1 has the test run with supported-version[1], which is some
// version OTHER than 99.
-INSTANTIATE_TEST_CASE_P(
- QuicStreamTests,
- QuicStreamTest,
+INSTANTIATE_TEST_SUITE_P(
+ QuicStreamTests, QuicStreamTest,
::testing::ValuesIn(ParsedVersionOfIndex(AllSupportedVersions(), 1)));
// Make a parameterized version of the QuicStreamTest for those tests
// that need to differentiate based on version number.
class QuicParameterizedStreamTest : public QuicStreamTestBase {};
-INSTANTIATE_TEST_CASE_P(QuicParameterizedStreamTests,
- QuicParameterizedStreamTest,
- ::testing::ValuesIn(AllSupportedVersions()));
+INSTANTIATE_TEST_SUITE_P(QuicParameterizedStreamTests,
+ QuicParameterizedStreamTest,
+ ::testing::ValuesIn(AllSupportedVersions()));
TEST_P(QuicStreamTest, PendingStreamTooMuchData) {
Initialize();
@@ -271,7 +269,9 @@
1 + QuicPacketCreator::StreamFramePacketOverhead(
connection_->transport_version(), PACKET_8BYTE_CONNECTION_ID,
PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion,
- !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER, 0u);
+ !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER,
+ VARIABLE_LENGTH_INTEGER_LENGTH_0,
+ VARIABLE_LENGTH_INTEGER_LENGTH_0, 0u);
connection_->SetMaxPacketLength(length);
EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _))
@@ -352,7 +352,9 @@
1 + QuicPacketCreator::StreamFramePacketOverhead(
connection_->transport_version(), PACKET_8BYTE_CONNECTION_ID,
PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion,
- !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER, 0u);
+ !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER,
+ VARIABLE_LENGTH_INTEGER_LENGTH_0,
+ VARIABLE_LENGTH_INTEGER_LENGTH_0, 0u);
connection_->SetMaxPacketLength(length);
EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
@@ -788,9 +790,6 @@
TEST_P(QuicStreamTest, StreamWaitsForAcks) {
Initialize();
- QuicReferenceCountedPointer<MockAckListener> mock_ack_listener(
- new StrictMock<MockAckListener>);
- stream_->set_ack_listener(mock_ack_listener);
EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
.WillRepeatedly(Invoke(MockQuicSession::ConsumeData));
// Stream is not waiting for acks initially.
@@ -801,9 +800,10 @@
stream_->WriteOrBufferData(kData1, false, nullptr);
EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size());
EXPECT_TRUE(stream_->IsWaitingForAcks());
- EXPECT_CALL(*mock_ack_listener, OnPacketAcked(9, _));
- EXPECT_TRUE(
- stream_->OnStreamFrameAcked(0, 9, false, QuicTime::Delta::Zero()));
+ QuicByteCount newly_acked_length = 0;
+ EXPECT_TRUE(stream_->OnStreamFrameAcked(0, 9, false, QuicTime::Delta::Zero(),
+ &newly_acked_length));
+ EXPECT_EQ(9u, newly_acked_length);
// Stream is not waiting for acks as all sent data is acked.
EXPECT_FALSE(stream_->IsWaitingForAcks());
EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
@@ -818,21 +818,20 @@
EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size());
// kData2 is retransmitted.
- EXPECT_CALL(*mock_ack_listener, OnPacketRetransmitted(9));
stream_->OnStreamFrameRetransmitted(9, 9, false);
// kData2 is acked.
- EXPECT_CALL(*mock_ack_listener, OnPacketAcked(9, _));
- EXPECT_TRUE(
- stream_->OnStreamFrameAcked(9, 9, false, QuicTime::Delta::Zero()));
+ EXPECT_TRUE(stream_->OnStreamFrameAcked(9, 9, false, QuicTime::Delta::Zero(),
+ &newly_acked_length));
+ EXPECT_EQ(9u, newly_acked_length);
// Stream is waiting for acks as FIN is not acked.
EXPECT_TRUE(stream_->IsWaitingForAcks());
EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
// FIN is acked.
- EXPECT_CALL(*mock_ack_listener, OnPacketAcked(0, _));
- EXPECT_TRUE(
- stream_->OnStreamFrameAcked(18, 0, true, QuicTime::Delta::Zero()));
+ EXPECT_TRUE(stream_->OnStreamFrameAcked(18, 0, true, QuicTime::Delta::Zero(),
+ &newly_acked_length));
+ EXPECT_EQ(0u, newly_acked_length);
EXPECT_FALSE(stream_->IsWaitingForAcks());
EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
}
@@ -849,19 +848,24 @@
EXPECT_EQ(3u, QuicStreamPeer::SendBuffer(stream_).size());
EXPECT_TRUE(stream_->IsWaitingForAcks());
- EXPECT_TRUE(
- stream_->OnStreamFrameAcked(9, 9, false, QuicTime::Delta::Zero()));
+ QuicByteCount newly_acked_length = 0;
+ EXPECT_TRUE(stream_->OnStreamFrameAcked(9, 9, false, QuicTime::Delta::Zero(),
+ &newly_acked_length));
+ EXPECT_EQ(9u, newly_acked_length);
EXPECT_EQ(3u, QuicStreamPeer::SendBuffer(stream_).size());
- EXPECT_TRUE(
- stream_->OnStreamFrameAcked(18, 9, false, QuicTime::Delta::Zero()));
+ EXPECT_TRUE(stream_->OnStreamFrameAcked(18, 9, false, QuicTime::Delta::Zero(),
+ &newly_acked_length));
+ EXPECT_EQ(9u, newly_acked_length);
EXPECT_EQ(3u, QuicStreamPeer::SendBuffer(stream_).size());
- EXPECT_TRUE(
- stream_->OnStreamFrameAcked(0, 9, false, QuicTime::Delta::Zero()));
+ EXPECT_TRUE(stream_->OnStreamFrameAcked(0, 9, false, QuicTime::Delta::Zero(),
+ &newly_acked_length));
+ EXPECT_EQ(9u, newly_acked_length);
EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
// FIN is not acked yet.
EXPECT_TRUE(stream_->IsWaitingForAcks());
- EXPECT_TRUE(
- stream_->OnStreamFrameAcked(27, 0, true, QuicTime::Delta::Zero()));
+ EXPECT_TRUE(stream_->OnStreamFrameAcked(27, 0, true, QuicTime::Delta::Zero(),
+ &newly_acked_length));
+ EXPECT_EQ(0u, newly_acked_length);
EXPECT_FALSE(stream_->IsWaitingForAcks());
}
@@ -1183,9 +1187,6 @@
TEST_P(QuicStreamTest, StreamDataGetAckedMultipleTimes) {
Initialize();
- QuicReferenceCountedPointer<MockAckListener> mock_ack_listener(
- new StrictMock<MockAckListener>);
- stream_->set_ack_listener(mock_ack_listener);
EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
.WillRepeatedly(Invoke(MockQuicSession::ConsumeData));
// Send [0, 27) and fin.
@@ -1197,42 +1198,41 @@
// Ack [0, 9), [5, 22) and [18, 26)
// Verify [0, 9) 9 bytes are acked.
- EXPECT_CALL(*mock_ack_listener, OnPacketAcked(9, _));
- EXPECT_TRUE(
- stream_->OnStreamFrameAcked(0, 9, false, QuicTime::Delta::Zero()));
+ QuicByteCount newly_acked_length = 0;
+ EXPECT_TRUE(stream_->OnStreamFrameAcked(0, 9, false, QuicTime::Delta::Zero(),
+ &newly_acked_length));
+ EXPECT_EQ(9u, newly_acked_length);
EXPECT_EQ(2u, QuicStreamPeer::SendBuffer(stream_).size());
// Verify [9, 22) 13 bytes are acked.
- EXPECT_CALL(*mock_ack_listener, OnPacketAcked(13, _));
- EXPECT_TRUE(
- stream_->OnStreamFrameAcked(5, 17, false, QuicTime::Delta::Zero()));
+ EXPECT_TRUE(stream_->OnStreamFrameAcked(5, 17, false, QuicTime::Delta::Zero(),
+ &newly_acked_length));
+ EXPECT_EQ(13u, newly_acked_length);
EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size());
// Verify [22, 26) 4 bytes are acked.
- EXPECT_CALL(*mock_ack_listener, OnPacketAcked(4, _));
- EXPECT_TRUE(
- stream_->OnStreamFrameAcked(18, 8, false, QuicTime::Delta::Zero()));
+ EXPECT_TRUE(stream_->OnStreamFrameAcked(18, 8, false, QuicTime::Delta::Zero(),
+ &newly_acked_length));
+ EXPECT_EQ(4u, newly_acked_length);
EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size());
EXPECT_TRUE(stream_->IsWaitingForAcks());
- // Ack [0, 27).
- // Verify [26, 27) 1 byte is acked.
- EXPECT_CALL(*mock_ack_listener, OnPacketAcked(1, _));
- EXPECT_TRUE(
- stream_->OnStreamFrameAcked(26, 1, false, QuicTime::Delta::Zero()));
+ // Ack [0, 27). Verify [26, 27) 1 byte is acked.
+ EXPECT_TRUE(stream_->OnStreamFrameAcked(26, 1, false, QuicTime::Delta::Zero(),
+ &newly_acked_length));
+ EXPECT_EQ(1u, newly_acked_length);
EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
EXPECT_TRUE(stream_->IsWaitingForAcks());
- // Ack Fin. Verify OnPacketAcked is called.
- EXPECT_CALL(*mock_ack_listener, OnPacketAcked(0, _));
- EXPECT_TRUE(
- stream_->OnStreamFrameAcked(27, 0, true, QuicTime::Delta::Zero()));
+ // Ack Fin.
+ EXPECT_TRUE(stream_->OnStreamFrameAcked(27, 0, true, QuicTime::Delta::Zero(),
+ &newly_acked_length));
+ EXPECT_EQ(0u, newly_acked_length);
EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
EXPECT_FALSE(stream_->IsWaitingForAcks());
- // Ack [10, 27) and fin.
- // No new data is acked, verify OnPacketAcked is not called.
- EXPECT_CALL(*mock_ack_listener, OnPacketAcked(_, _)).Times(0);
- EXPECT_FALSE(
- stream_->OnStreamFrameAcked(10, 17, true, QuicTime::Delta::Zero()));
+ // Ack [10, 27) and fin. No new data is acked.
+ EXPECT_FALSE(stream_->OnStreamFrameAcked(
+ 10, 17, true, QuicTime::Delta::Zero(), &newly_acked_length));
+ EXPECT_EQ(0u, newly_acked_length);
EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
EXPECT_FALSE(stream_->IsWaitingForAcks());
}
@@ -1282,8 +1282,10 @@
EXPECT_TRUE(stream_->HasPendingRetransmission());
// Ack [9, 18).
- EXPECT_TRUE(
- stream_->OnStreamFrameAcked(9, 9, false, QuicTime::Delta::Zero()));
+ QuicByteCount newly_acked_length = 0;
+ EXPECT_TRUE(stream_->OnStreamFrameAcked(9, 9, false, QuicTime::Delta::Zero(),
+ &newly_acked_length));
+ EXPECT_EQ(9u, newly_acked_length);
EXPECT_FALSE(stream_->IsStreamFrameOutstanding(9, 3, false));
EXPECT_TRUE(stream_->HasPendingRetransmission());
// This OnCanWrite causes [18, 27) and fin to be retransmitted. Verify fin can
@@ -1385,8 +1387,10 @@
stream_->WriteOrBufferData(kData1, false, nullptr);
stream_->WriteOrBufferData(kData1, true, nullptr);
// Ack [10, 13).
- stream_->OnStreamFrameAcked(10, 3, false, QuicTime::Delta::Zero());
-
+ QuicByteCount newly_acked_length = 0;
+ stream_->OnStreamFrameAcked(10, 3, false, QuicTime::Delta::Zero(),
+ &newly_acked_length);
+ EXPECT_EQ(3u, newly_acked_length);
// Retransmit [0, 18) with fin, and only [0, 8) is consumed.
EXPECT_CALL(*session_, WritevData(_, stream_->id(), 10, 0, NO_FIN))
.WillOnce(InvokeWithoutArgs([this]() {
diff --git a/quic/core/quic_time_wait_list_manager.cc b/quic/core/quic_time_wait_list_manager.cc
index 731df3e..5335455 100644
--- a/quic/core/quic_time_wait_list_manager.cc
+++ b/quic/core/quic_time_wait_list_manager.cc
@@ -336,9 +336,6 @@
QuicUint128 QuicTimeWaitListManager::GetStatelessResetToken(
QuicConnectionId connection_id) const {
- if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_SERVER)) {
- return QuicConnectionIdToUInt64(connection_id);
- }
return QuicUtils::GenerateStatelessResetToken(connection_id);
}
diff --git a/quic/core/quic_time_wait_list_manager_test.cc b/quic/core/quic_time_wait_list_manager_test.cc
index 0d3244b..263702a 100644
--- a/quic/core/quic_time_wait_list_manager_test.cc
+++ b/quic/core/quic_time_wait_list_manager_test.cc
@@ -55,9 +55,6 @@
}
bool IsValidStatelessResetToken(QuicUint128 token) const override {
- if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_SERVER)) {
- return token == QuicConnectionIdToUInt64(connection_id_);
- }
return token == QuicUtils::GenerateStatelessResetToken(connection_id_);
}
@@ -144,8 +141,6 @@
void SetUp() override {
EXPECT_CALL(writer_, IsWriteBlocked())
.WillRepeatedly(ReturnPointee(&writer_is_blocked_));
- EXPECT_CALL(writer_, IsWriteBlockedDataBuffered())
- .WillRepeatedly(Return(false));
}
void AddConnectionId(QuicConnectionId connection_id,
@@ -221,14 +216,8 @@
QuicIetfStatelessResetPacket stateless_reset =
visitor.stateless_reset_packet();
- QuicUint128 expected_stateless_reset_token;
- if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_SERVER)) {
- expected_stateless_reset_token =
- QuicConnectionIdToUInt64(expected_connection_id);
- } else {
- expected_stateless_reset_token =
- QuicUtils::GenerateStatelessResetToken(expected_connection_id);
- }
+ QuicUint128 expected_stateless_reset_token =
+ QuicUtils::GenerateStatelessResetToken(expected_connection_id);
bool stateless_reset_is_valid =
stateless_reset.stateless_reset_token == expected_stateless_reset_token;
diff --git a/quic/core/quic_trace_visitor.cc b/quic/core/quic_trace_visitor.cc
index b0fc8ae..ba2ed7f 100644
--- a/quic/core/quic_trace_visitor.cc
+++ b/quic/core/quic_trace_visitor.cc
@@ -13,7 +13,7 @@
switch (level) {
case ENCRYPTION_NONE:
return quic_trace::ENCRYPTION_INITIAL;
- case ENCRYPTION_INITIAL:
+ case ENCRYPTION_ZERO_RTT:
return quic_trace::ENCRYPTION_0RTT;
case ENCRYPTION_FORWARD_SECURE:
return quic_trace::ENCRYPTION_1RTT;
@@ -26,20 +26,8 @@
QuicTraceVisitor::QuicTraceVisitor(const QuicConnection* connection)
: connection_(connection),
start_time_(connection_->clock()->ApproximateNow()) {
- QuicString binary_connection_id;
- if (!QuicConnectionIdSupportsVariableLength(connection->perspective())) {
- // QUIC CIDs are currently represented in memory as a converted
- // representation of the on-wire ID. Convert it back to wire format before
- // recording, since the standard treats it as an opaque blob.
- uint64_t connection_id = QuicEndian::HostToNet64(
- QuicConnectionIdToUInt64(connection->connection_id()));
- binary_connection_id = QuicString(
- reinterpret_cast<const char*>(&connection_id), sizeof(connection_id));
- } else {
- binary_connection_id.assign(connection->connection_id().data(),
- connection->connection_id().length());
- }
-
+ QuicString binary_connection_id(connection->connection_id().data(),
+ connection->connection_id().length());
// We assume that the connection ID in gQUIC is equivalent to the
// server-chosen client-selected ID.
switch (connection->perspective()) {
@@ -338,4 +326,4 @@
}
}
-}; // namespace quic
+} // namespace quic
diff --git a/quic/core/quic_trace_visitor.h b/quic/core/quic_trace_visitor.h
index efbbee3..a3e7dda 100644
--- a/quic/core/quic_trace_visitor.h
+++ b/quic/core/quic_trace_visitor.h
@@ -65,6 +65,6 @@
const QuicTime start_time_;
};
-}; // namespace quic
+} // namespace quic
#endif // QUICHE_QUIC_CORE_QUIC_TRACE_VISITOR_H_
diff --git a/quic/core/quic_types.h b/quic/core/quic_types.h
index 7718468..bf7943d 100644
--- a/quic/core/quic_types.h
+++ b/quic/core/quic_types.h
@@ -177,6 +177,7 @@
BLOCKED_FRAME = 5,
STOP_WAITING_FRAME = 6,
PING_FRAME = 7,
+ CRYPTO_FRAME = 8,
// STREAM and ACK frames are special frames. They are encoded differently on
// the wire and their values do not need to be stable.
@@ -197,7 +198,6 @@
PATH_CHALLENGE_FRAME,
STOP_SENDING_FRAME,
MESSAGE_FRAME,
- CRYPTO_FRAME,
NEW_TOKEN_FRAME,
RETIRE_CONNECTION_ID_FRAME,
@@ -234,15 +234,14 @@
// 0x09 through 0x0f are various flag settings of the IETF_STREAM frame.
IETF_MAX_DATA = 0x10,
IETF_MAX_STREAM_DATA = 0x11,
- IETF_MAX_STREAM_ID = 0x12, // TODO(fkastenholz): Will become IETF_MAX_STREAMS
- // 0x13 reserved, a flag setting for IETF_MAX_STREAMS.
+ IETF_MAX_STREAMS_BIDIRECTIONAL = 0x12,
+ IETF_MAX_STREAMS_UNIDIRECTIONAL = 0x13,
IETF_BLOCKED = 0x14, // TODO(fkastenholz): Should, eventually, be renamed to
// IETF_DATA_BLOCKED
IETF_STREAM_BLOCKED = 0x15, // TODO(fkastenholz): Should, eventually, be
// renamed to IETF_STREAM_DATA_BLOCKED
- IETF_STREAM_ID_BLOCKED =
- 0x16, // TODO(fkastenholz): Will become IETF_STREAMS_BLOCKED
- // 0x17 reserved, a flag setting for IETF_STREAMS_BLOCKED
+ IETF_STREAMS_BLOCKED_BIDIRECTIONAL = 0x16,
+ IETF_STREAMS_BLOCKED_UNIDIRECTIONAL = 0x17,
IETF_NEW_CONNECTION_ID = 0x18,
IETF_RETIRE_CONNECTION_ID = 0x19,
IETF_PATH_CHALLENGE = 0x1a,
@@ -271,10 +270,25 @@
#define IETF_STREAM_FRAME_LEN_BIT 0x02
#define IETF_STREAM_FRAME_OFF_BIT 0x04
+enum QuicVariableLengthIntegerLength : uint8_t {
+ // Length zero means the variable length integer is not present.
+ VARIABLE_LENGTH_INTEGER_LENGTH_0 = 0,
+ VARIABLE_LENGTH_INTEGER_LENGTH_1 = 1,
+ 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;
+
enum QuicPacketNumberLength : uint8_t {
PACKET_1BYTE_PACKET_NUMBER = 1,
PACKET_2BYTE_PACKET_NUMBER = 2,
- PACKET_3BYTE_PACKET_NUMBER = 3, // Used in version > QUIC_VERSION_46.
+ PACKET_3BYTE_PACKET_NUMBER = 3, // Used in version > QUIC_VERSION_44.
PACKET_4BYTE_PACKET_NUMBER = 4,
// TODO(rch): Remove this when we remove QUIC_VERSION_39.
PACKET_6BYTE_PACKET_NUMBER = 6,
@@ -359,7 +373,7 @@
// understand.
enum EncryptionLevel : int8_t {
ENCRYPTION_NONE = 0,
- ENCRYPTION_INITIAL = 1,
+ ENCRYPTION_ZERO_RTT = 1,
ENCRYPTION_FORWARD_SECURE = 2,
NUM_ENCRYPTION_LEVELS,
@@ -551,6 +565,16 @@
READ_UNIDIRECTIONAL,
};
+// A packet number space is the context in which a packet can be processed and
+// acknowledged.
+enum PacketNumberSpace : uint8_t {
+ INITIAL_DATA = 0, // Only used in IETF QUIC.
+ HANDSHAKE_DATA = 1,
+ APPLICATION_DATA = 2,
+
+ NUM_PACKET_NUMBER_SPACES,
+};
+
} // namespace quic
#endif // QUICHE_QUIC_CORE_QUIC_TYPES_H_
diff --git a/quic/core/quic_unacked_packet_map.cc b/quic/core/quic_unacked_packet_map.cc
index 32fd272..859bf39 100644
--- a/quic/core/quic_unacked_packet_map.cc
+++ b/quic/core/quic_unacked_packet_map.cc
@@ -24,13 +24,20 @@
}
} // namespace
-QuicUnackedPacketMap::QuicUnackedPacketMap()
- : least_unacked_(FirstSendingPacketNumber()),
+QuicUnackedPacketMap::QuicUnackedPacketMap(Perspective perspective)
+ : perspective_(perspective),
+ least_unacked_(FirstSendingPacketNumber()),
bytes_in_flight_(0),
pending_crypto_packet_count_(0),
last_crypto_packet_sent_time_(QuicTime::Zero()),
session_notifier_(nullptr),
- session_decides_what_to_write_(false) {}
+ session_decides_what_to_write_(false),
+ use_uber_loss_algorithm_(
+ GetQuicReloadableFlag(quic_use_uber_loss_algorithm)) {
+ if (use_uber_loss_algorithm_) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_use_uber_loss_algorithm);
+ }
+}
QuicUnackedPacketMap::~QuicUnackedPacketMap() {
for (QuicTransmissionInfo& transmission_info : unacked_packets_) {
@@ -76,7 +83,12 @@
if (set_in_flight) {
bytes_in_flight_ += bytes_sent;
info.in_flight = true;
- largest_sent_retransmittable_packet_ = packet_number;
+ if (use_uber_loss_algorithm_) {
+ largest_sent_retransmittable_packets_[GetPacketNumberSpace(
+ info.encryption_level)] = packet_number;
+ } else {
+ largest_sent_retransmittable_packet_ = packet_number;
+ }
}
unacked_packets_.push_back(info);
// Swap the retransmittable frames to avoid allocations.
@@ -216,6 +228,20 @@
largest_acked_ = largest_acked;
}
+void QuicUnackedPacketMap::MaybeUpdateLargestAckedOfPacketNumberSpace(
+ EncryptionLevel encryption_level,
+ QuicPacketNumber packet_number) {
+ DCHECK(use_uber_loss_algorithm_);
+ const PacketNumberSpace packet_number_space =
+ GetPacketNumberSpace(encryption_level);
+ if (!largest_acked_packets_[packet_number_space].IsInitialized()) {
+ largest_acked_packets_[packet_number_space] = packet_number;
+ } else {
+ largest_acked_packets_[packet_number_space] =
+ std::max(largest_acked_packets_[packet_number_space], packet_number);
+ }
+}
+
bool QuicUnackedPacketMap::IsPacketUsefulForMeasuringRtt(
QuicPacketNumber packet_number,
const QuicTransmissionInfo& info) const {
@@ -475,6 +501,45 @@
aggregated_stream_frame_.stream_id = -1;
}
+PacketNumberSpace QuicUnackedPacketMap::GetPacketNumberSpace(
+ QuicPacketNumber packet_number) const {
+ DCHECK(use_uber_loss_algorithm_);
+ return GetPacketNumberSpace(
+ GetTransmissionInfo(packet_number).encryption_level);
+}
+
+PacketNumberSpace QuicUnackedPacketMap::GetPacketNumberSpace(
+ EncryptionLevel encryption_level) const {
+ DCHECK(use_uber_loss_algorithm_);
+ if (perspective_ == Perspective::IS_CLIENT) {
+ return encryption_level == ENCRYPTION_NONE ? HANDSHAKE_DATA
+ : APPLICATION_DATA;
+ }
+ return encryption_level == ENCRYPTION_FORWARD_SECURE ? APPLICATION_DATA
+ : HANDSHAKE_DATA;
+}
+
+QuicPacketNumber QuicUnackedPacketMap::GetLargestAckedOfPacketNumberSpace(
+ PacketNumberSpace packet_number_space) const {
+ DCHECK(use_uber_loss_algorithm_);
+ if (packet_number_space >= NUM_PACKET_NUMBER_SPACES) {
+ QUIC_BUG << "Invalid packet number space: " << packet_number_space;
+ return QuicPacketNumber();
+ }
+ return largest_acked_packets_[packet_number_space];
+}
+
+QuicPacketNumber
+QuicUnackedPacketMap::GetLargestSentRetransmittableOfPacketNumberSpace(
+ PacketNumberSpace packet_number_space) const {
+ DCHECK(use_uber_loss_algorithm_);
+ if (packet_number_space >= NUM_PACKET_NUMBER_SPACES) {
+ QUIC_BUG << "Invalid packet number space: " << packet_number_space;
+ return QuicPacketNumber();
+ }
+ return largest_sent_retransmittable_packets_[packet_number_space];
+}
+
void QuicUnackedPacketMap::SetSessionDecideWhatToWrite(
bool session_decides_what_to_write) {
if (largest_sent_packet_.IsInitialized()) {
diff --git a/quic/core/quic_unacked_packet_map.h b/quic/core/quic_unacked_packet_map.h
index b4d13c5..b6f7af5 100644
--- a/quic/core/quic_unacked_packet_map.h
+++ b/quic/core/quic_unacked_packet_map.h
@@ -26,7 +26,7 @@
// 3) Track sent time of packets to provide RTT measurements from acks.
class QUIC_EXPORT_PRIVATE QuicUnackedPacketMap {
public:
- QuicUnackedPacketMap();
+ QuicUnackedPacketMap(Perspective perspective);
QuicUnackedPacketMap(const QuicUnackedPacketMap&) = delete;
QuicUnackedPacketMap& operator=(const QuicUnackedPacketMap&) = delete;
~QuicUnackedPacketMap();
@@ -93,6 +93,7 @@
// Returns the largest retransmittable packet number that has been sent.
QuicPacketNumber largest_sent_retransmittable_packet() const {
+ DCHECK(!use_uber_loss_algorithm_);
return largest_sent_retransmittable_packet_;
}
@@ -165,6 +166,12 @@
// |largest_acked| are discarded if they are only for the RTT purposes.
void IncreaseLargestAcked(QuicPacketNumber largest_acked);
+ // Called when |packet_number| gets acked. Maybe increase the largest acked of
+ // corresponding packet number space of |encryption_level|.
+ void MaybeUpdateLargestAckedOfPacketNumberSpace(
+ EncryptionLevel encryption_level,
+ QuicPacketNumber packet_number);
+
// Remove any packets no longer needed for retransmission, congestion, or
// RTT measurement purposes.
void RemoveObsoletePackets();
@@ -180,6 +187,24 @@
// stream id.
void NotifyAggregatedStreamFrameAcked(QuicTime::Delta ack_delay);
+ // Returns packet number space that |packet_number| belongs to. Please use
+ // GetPacketNumberSpace(EncryptionLevel) whenever encryption level is
+ // available.
+ PacketNumberSpace GetPacketNumberSpace(QuicPacketNumber packet_number) const;
+
+ // Returns packet number space of |encryption_level|.
+ PacketNumberSpace GetPacketNumberSpace(
+ EncryptionLevel encryption_level) const;
+
+ // Returns largest acked packet number of |packet_number_space|.
+ QuicPacketNumber GetLargestAckedOfPacketNumberSpace(
+ PacketNumberSpace packet_number_space) const;
+
+ // Returns largest sent retransmittable packet number of
+ // |packet_number_space|.
+ QuicPacketNumber GetLargestSentRetransmittableOfPacketNumberSpace(
+ PacketNumberSpace packet_number_space) const;
+
// Called to start/stop letting session decide what to write.
void SetSessionDecideWhatToWrite(bool session_decides_what_to_write);
@@ -189,6 +214,10 @@
return session_decides_what_to_write_;
}
+ bool use_uber_loss_algorithm() const { return use_uber_loss_algorithm_; }
+
+ Perspective perspective() const { return perspective_; }
+
private:
friend class test::QuicUnackedPacketMapPeer;
@@ -218,13 +247,24 @@
bool IsPacketUseless(QuicPacketNumber packet_number,
const QuicTransmissionInfo& info) const;
+ const Perspective perspective_;
+
QuicPacketNumber largest_sent_packet_;
// The largest sent packet we expect to receive an ack for.
+ // TODO(fayang): Remove largest_sent_retransmittable_packet_ when deprecating
+ // quic_use_uber_loss_algorithm.
QuicPacketNumber largest_sent_retransmittable_packet_;
+ // The largest sent packet we expect to receive an ack for per packet number
+ // space. Only used if use_uber_loss_algorithm_ is true.
+ QuicPacketNumber
+ largest_sent_retransmittable_packets_[NUM_PACKET_NUMBER_SPACES];
// The largest sent largest_acked in an ACK frame.
QuicPacketNumber largest_sent_largest_acked_;
// The largest received largest_acked from an ACK frame.
QuicPacketNumber largest_acked_;
+ // The largest received largest_acked from ACK frame per packet number space.
+ // Only used if use_uber_loss_algorithm_ is true.
+ QuicPacketNumber largest_acked_packets_[NUM_PACKET_NUMBER_SPACES];
// Newly serialized retransmittable packets are added to this map, which
// contains owning pointers to any contained frames. If a packet is
@@ -254,6 +294,9 @@
// If true, let session decides what to write.
bool session_decides_what_to_write_;
+
+ // Latched value of quic_use_uber_loss_algorithm.
+ const bool use_uber_loss_algorithm_;
};
} // namespace quic
diff --git a/quic/core/quic_unacked_packet_map_test.cc b/quic/core/quic_unacked_packet_map_test.cc
index df14321..cf725fa 100644
--- a/quic/core/quic_unacked_packet_map_test.cc
+++ b/quic/core/quic_unacked_packet_map_test.cc
@@ -11,6 +11,7 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_unacked_packet_map_peer.h"
using testing::_;
using testing::Return;
@@ -18,27 +19,46 @@
namespace quic {
namespace test {
-
-class QuicUnackedPacketMapPeer {
- public:
- static const QuicStreamFrame& GetAggregatedStreamFrame(
- const QuicUnackedPacketMap& unacked_packets) {
- return unacked_packets.aggregated_stream_frame_;
- }
-};
-
namespace {
// Default packet length.
const uint32_t kDefaultLength = 1000;
-class QuicUnackedPacketMapTest : public QuicTestWithParam<bool> {
+struct TestParams {
+ TestParams(Perspective perspective, bool session_decides_what_to_write)
+ : perspective(perspective),
+ session_decides_what_to_write(session_decides_what_to_write) {}
+
+ friend std::ostream& operator<<(std::ostream& os, const TestParams& p) {
+ os << "{ Perspective: " << p.perspective
+ << " session_decides_what_to_write: " << p.session_decides_what_to_write
+ << " }";
+ return os;
+ }
+
+ Perspective perspective;
+ bool session_decides_what_to_write;
+};
+
+std::vector<TestParams> GetTestParams() {
+ std::vector<TestParams> params;
+ for (Perspective perspective :
+ {Perspective::IS_CLIENT, Perspective::IS_SERVER}) {
+ for (bool session_decides_what_to_write : {true, false}) {
+ params.push_back(TestParams(perspective, session_decides_what_to_write));
+ }
+ }
+ return params;
+}
+
+class QuicUnackedPacketMapTest : public QuicTestWithParam<TestParams> {
protected:
QuicUnackedPacketMapTest()
- : unacked_packets_(),
+ : unacked_packets_(GetParam().perspective),
now_(QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(1000)) {
unacked_packets_.SetSessionNotifier(¬ifier_);
- unacked_packets_.SetSessionDecideWhatToWrite(GetParam());
+ unacked_packets_.SetSessionDecideWhatToWrite(
+ GetParam().session_decides_what_to_write);
EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(true));
EXPECT_CALL(notifier_, OnStreamFrameRetransmitted(_))
.Times(testing::AnyNumber());
@@ -178,7 +198,9 @@
StrictMock<MockSessionNotifier> notifier_;
};
-INSTANTIATE_TEST_CASE_P(Tests, QuicUnackedPacketMapTest, testing::Bool());
+INSTANTIATE_TEST_SUITE_P(Tests,
+ QuicUnackedPacketMapTest,
+ ::testing::ValuesIn(GetTestParams()));
TEST_P(QuicUnackedPacketMapTest, RttOnly) {
// Acks are only tracked for RTT measurement purposes.
diff --git a/quic/core/quic_utils.cc b/quic/core/quic_utils.cc
index be6eeea..0801f41 100644
--- a/quic/core/quic_utils.cc
+++ b/quic/core/quic_utils.cc
@@ -143,7 +143,7 @@
const char* QuicUtils::EncryptionLevelToString(EncryptionLevel level) {
switch (level) {
RETURN_STRING_LITERAL(ENCRYPTION_NONE);
- RETURN_STRING_LITERAL(ENCRYPTION_INITIAL);
+ RETURN_STRING_LITERAL(ENCRYPTION_ZERO_RTT);
RETURN_STRING_LITERAL(ENCRYPTION_FORWARD_SECURE);
RETURN_STRING_LITERAL(NUM_ENCRYPTION_LEVELS);
}
@@ -290,6 +290,13 @@
}
// static
+struct iovec QuicUtils::MakeIovec(QuicStringPiece data) {
+ struct iovec iov = {const_cast<char*>(data.data()),
+ static_cast<size_t>(data.size())};
+ return iov;
+}
+
+// static
bool QuicUtils::IsAckable(SentPacketState state) {
return state != NEVER_SENT && state != ACKED && state != UNACKABLE;
}
@@ -308,6 +315,17 @@
}
// static
+bool QuicUtils::IsHandshakeFrame(const QuicFrame& frame,
+ QuicTransportVersion transport_version) {
+ if (transport_version < QUIC_VERSION_47) {
+ return frame.type == STREAM_FRAME &&
+ frame.stream_frame.stream_id == GetCryptoStreamId(transport_version);
+ } else {
+ return frame.type == CRYPTO_FRAME;
+ }
+}
+
+// static
SentPacketState QuicUtils::RetransmissionTypeToPacketState(
TransmissionType retransmission_type) {
switch (retransmission_type) {
@@ -347,11 +365,14 @@
// static
QuicStreamId QuicUtils::GetInvalidStreamId(QuicTransportVersion version) {
- return version == QUIC_VERSION_99 ? -1 : 0;
+ return version == QUIC_VERSION_99 ? std::numeric_limits<QuicStreamId>::max()
+ : 0;
}
// static
QuicStreamId QuicUtils::GetCryptoStreamId(QuicTransportVersion version) {
+ // TODO(nharper): Change this to return GetInvalidStreamId for version 47 or
+ // greater. Currently, too many things break with that change.
return version == QUIC_VERSION_99 ? 0 : 1;
}
@@ -384,11 +405,30 @@
}
// static
-StreamType QuicUtils::GetStreamType(QuicStreamId id, bool peer_initiated) {
+StreamType QuicUtils::GetStreamType(QuicStreamId id,
+ Perspective perspective,
+ bool peer_initiated) {
if (IsBidirectionalStreamId(id)) {
return BIDIRECTIONAL;
}
- return peer_initiated ? READ_UNIDIRECTIONAL : WRITE_UNIDIRECTIONAL;
+
+ if (peer_initiated) {
+ if (perspective == Perspective::IS_SERVER) {
+ DCHECK_EQ(2, id % 4);
+ } else {
+ DCHECK_EQ(Perspective::IS_CLIENT, perspective);
+ DCHECK_EQ(3, id % 4);
+ }
+ return READ_UNIDIRECTIONAL;
+ }
+
+ if (perspective == Perspective::IS_SERVER) {
+ DCHECK_EQ(3, id % 4);
+ } else {
+ DCHECK_EQ(Perspective::IS_CLIENT, perspective);
+ DCHECK_EQ(2, id % 4);
+ }
+ return WRITE_UNIDIRECTIONAL;
}
// static
@@ -422,21 +462,7 @@
}
// static
-QuicConnectionId QuicUtils::CreateRandomConnectionId(Perspective perspective) {
- return CreateRandomConnectionId(QuicRandom::GetInstance(), perspective);
-}
-
-// static
QuicConnectionId QuicUtils::CreateRandomConnectionId(QuicRandom* random) {
- return CreateRandomConnectionId(random, Perspective::IS_SERVER);
-}
-
-// static
-QuicConnectionId QuicUtils::CreateRandomConnectionId(QuicRandom* random,
- Perspective perspective) {
- if (!QuicConnectionIdSupportsVariableLength(perspective)) {
- return QuicConnectionIdFromUInt64(random->RandUint64());
- }
char connection_id_bytes[kQuicDefaultConnectionIdLength];
random->RandBytes(connection_id_bytes, QUIC_ARRAYSIZE(connection_id_bytes));
return QuicConnectionId(static_cast<char*>(connection_id_bytes),
@@ -453,10 +479,6 @@
// static
QuicConnectionId QuicUtils::CreateZeroConnectionId(
QuicTransportVersion version) {
- if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_SERVER) ||
- !QuicConnectionIdSupportsVariableLength(Perspective::IS_CLIENT)) {
- return QuicConnectionIdFromUInt64(0);
- }
if (!VariableLengthConnectionIdAllowedForVersion(version)) {
char connection_id_bytes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
return QuicConnectionId(static_cast<char*>(connection_id_bytes),
@@ -476,9 +498,6 @@
QuicUint128 QuicUtils::GenerateStatelessResetToken(
QuicConnectionId connection_id) {
- if (!QuicConnectionIdUseNetworkByteOrder()) {
- return QuicConnectionIdToUInt64(connection_id);
- }
uint64_t data_bytes[3] = {0, 0, 0};
static_assert(sizeof(data_bytes) >= kQuicMaxConnectionIdLength,
"kQuicMaxConnectionIdLength changed");
diff --git a/quic/core/quic_utils.h b/quic/core/quic_utils.h
index 111080a..28ea15b 100644
--- a/quic/core/quic_utils.h
+++ b/quic/core/quic_utils.h
@@ -10,6 +10,7 @@
#include "base/macros.h"
#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_frame.h"
#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/core/quic_versions.h"
@@ -79,6 +80,9 @@
size_t buffer_length,
char* buffer);
+ // Creates an iovec pointing to the same data as |data|.
+ static struct iovec MakeIovec(QuicStringPiece data);
+
// Returns true if a packet is ackable. A packet is unackable if it can never
// be acked. Occurs when a packet is never sent, after it is acknowledged
// once, or if it's a crypto packet we never expect to receive an ack for.
@@ -88,6 +92,10 @@
// frame should be retransmitted if it is detected as lost.
static bool IsRetransmittableFrame(QuicFrameType type);
+ // Returns true if |frame| is a handshake frame in version |version|.
+ static bool IsHandshakeFrame(const QuicFrame& frame,
+ QuicTransportVersion transport_version);
+
// Returns packet state corresponding to |retransmission_type|.
static SentPacketState RetransmissionTypeToPacketState(
TransmissionType retransmission_type);
@@ -121,9 +129,12 @@
// v99.
static bool IsBidirectionalStreamId(QuicStreamId id);
- // Returns stream type according to |id| and |peer_initiated|. Only used in
- // v99.
- static StreamType GetStreamType(QuicStreamId id, bool peer_initiated);
+ // Returns stream type. Either |perspective| or |peer_initiated| would be
+ // enough together with |id|. This method enforces that the three parameters
+ // are consistent. Only used in v99.
+ static StreamType GetStreamType(QuicStreamId id,
+ Perspective perspective,
+ bool peer_initiated);
// Returns the delta between consecutive stream IDs of the same type.
static QuicStreamId StreamIdDelta(QuicTransportVersion version);
@@ -141,16 +152,9 @@
// Generates a random 64bit connection ID.
static QuicConnectionId CreateRandomConnectionId();
- // Generates a random 64bit connection ID.
- static QuicConnectionId CreateRandomConnectionId(Perspective perspective);
-
// Generates a random 64bit connection ID using the provided QuicRandom.
static QuicConnectionId CreateRandomConnectionId(QuicRandom* random);
- // Generates a random 64bit connection ID using the provided QuicRandom.
- static QuicConnectionId CreateRandomConnectionId(QuicRandom* random,
- Perspective perspective);
-
// Returns true if the QUIC version allows variable length connection IDs.
static bool VariableLengthConnectionIdAllowedForVersion(
QuicTransportVersion version);
diff --git a/quic/core/quic_utils_test.cc b/quic/core/quic_utils_test.cc
index d1b5268..de4c76b 100644
--- a/quic/core/quic_utils_test.cc
+++ b/quic/core/quic_utils_test.cc
@@ -168,16 +168,11 @@
MockRandom random(33);
QuicConnectionId connection_id = QuicUtils::CreateRandomConnectionId(&random);
EXPECT_EQ(connection_id.length(), sizeof(uint64_t));
- if (!QuicConnectionIdSupportsVariableLength(quic::Perspective::IS_SERVER) ||
- !QuicConnectionIdSupportsVariableLength(quic::Perspective::IS_CLIENT)) {
- EXPECT_EQ(connection_id, QuicConnectionIdFromUInt64(random.RandUint64()));
- } else {
char connection_id_bytes[sizeof(uint64_t)];
random.RandBytes(connection_id_bytes, QUIC_ARRAYSIZE(connection_id_bytes));
EXPECT_EQ(connection_id,
QuicConnectionId(static_cast<char*>(connection_id_bytes),
QUIC_ARRAYSIZE(connection_id_bytes)));
- }
EXPECT_NE(connection_id, EmptyQuicConnectionId());
EXPECT_NE(connection_id, TestConnectionId());
EXPECT_NE(connection_id, TestConnectionId(1));
@@ -185,19 +180,15 @@
TEST_F(QuicUtilsTest, VariableLengthConnectionId) {
EXPECT_FALSE(
- QuicUtils::VariableLengthConnectionIdAllowedForVersion(QUIC_VERSION_35));
+ QuicUtils::VariableLengthConnectionIdAllowedForVersion(QUIC_VERSION_39));
EXPECT_TRUE(QuicUtils::IsConnectionIdValidForVersion(
- QuicUtils::CreateZeroConnectionId(QUIC_VERSION_35), QUIC_VERSION_35));
+ QuicUtils::CreateZeroConnectionId(QUIC_VERSION_39), QUIC_VERSION_39));
EXPECT_TRUE(QuicUtils::IsConnectionIdValidForVersion(
QuicUtils::CreateZeroConnectionId(QUIC_VERSION_99), QUIC_VERSION_99));
- if (!QuicConnectionIdSupportsVariableLength(quic::Perspective::IS_SERVER) ||
- !QuicConnectionIdSupportsVariableLength(quic::Perspective::IS_CLIENT)) {
- return;
- }
- EXPECT_NE(QuicUtils::CreateZeroConnectionId(QUIC_VERSION_35),
+ EXPECT_NE(QuicUtils::CreateZeroConnectionId(QUIC_VERSION_39),
EmptyQuicConnectionId());
EXPECT_FALSE(QuicUtils::IsConnectionIdValidForVersion(EmptyQuicConnectionId(),
- QUIC_VERSION_35));
+ QUIC_VERSION_39));
}
TEST_F(QuicUtilsTest, StatelessResetToken) {
diff --git a/quic/core/quic_version_manager.cc b/quic/core/quic_version_manager.cc
index 064e932..62b2e44 100644
--- a/quic/core/quic_version_manager.cc
+++ b/quic/core/quic_version_manager.cc
@@ -17,10 +17,9 @@
: enable_version_99_(GetQuicReloadableFlag(quic_enable_version_99)),
enable_version_47_(GetQuicReloadableFlag(quic_enable_version_47)),
enable_version_46_(GetQuicReloadableFlag(quic_enable_version_46)),
- enable_version_45_(GetQuicReloadableFlag(quic_enable_version_45)),
enable_version_44_(GetQuicReloadableFlag(quic_enable_version_44)),
enable_version_43_(GetQuicReloadableFlag(quic_enable_version_43)),
- disable_version_35_(GetQuicReloadableFlag(quic_disable_version_35)),
+ disable_version_39_(GetQuicReloadableFlag(quic_disable_version_39)),
allowed_supported_versions_(std::move(supported_versions)) {
RefilterSupportedVersions();
}
@@ -42,17 +41,15 @@
if (enable_version_99_ != GetQuicReloadableFlag(quic_enable_version_99) ||
enable_version_47_ != GetQuicReloadableFlag(quic_enable_version_47) ||
enable_version_46_ != GetQuicReloadableFlag(quic_enable_version_46) ||
- enable_version_45_ != GetQuicReloadableFlag(quic_enable_version_45) ||
enable_version_44_ != GetQuicReloadableFlag(quic_enable_version_44) ||
enable_version_43_ != GetQuicReloadableFlag(quic_enable_version_43) ||
- disable_version_35_ != GetQuicReloadableFlag(quic_disable_version_35)) {
+ disable_version_39_ != GetQuicReloadableFlag(quic_disable_version_39)) {
enable_version_99_ = GetQuicReloadableFlag(quic_enable_version_99);
enable_version_47_ = GetQuicReloadableFlag(quic_enable_version_47);
enable_version_46_ = GetQuicReloadableFlag(quic_enable_version_46);
- enable_version_45_ = GetQuicReloadableFlag(quic_enable_version_45);
enable_version_44_ = GetQuicReloadableFlag(quic_enable_version_44);
enable_version_43_ = GetQuicReloadableFlag(quic_enable_version_43);
- disable_version_35_ = GetQuicReloadableFlag(quic_disable_version_35);
+ disable_version_39_ = GetQuicReloadableFlag(quic_disable_version_39);
RefilterSupportedVersions();
}
}
diff --git a/quic/core/quic_version_manager.h b/quic/core/quic_version_manager.h
index 1196c31..ab06868 100644
--- a/quic/core/quic_version_manager.h
+++ b/quic/core/quic_version_manager.h
@@ -41,14 +41,12 @@
bool enable_version_47_;
// quic_enable_version_46 flag
bool enable_version_46_;
- // quic_enable_version_45 flag
- bool enable_version_45_;
// quic_enable_version_44 flag
bool enable_version_44_;
// quic_enable_version_43 flag
bool enable_version_43_;
- // quic_disable_version_35 flag
- bool disable_version_35_;
+ // quic_disable_version_39 flag
+ bool disable_version_39_;
// The list of versions that may be supported.
ParsedQuicVersionVector allowed_supported_versions_;
// This vector contains QUIC versions which are currently supported based on
diff --git a/quic/core/quic_version_manager_test.cc b/quic/core/quic_version_manager_test.cc
index b734b89..7c7a08d 100644
--- a/quic/core/quic_version_manager_test.cc
+++ b/quic/core/quic_version_manager_test.cc
@@ -16,62 +16,50 @@
class QuicVersionManagerTest : public QuicTest {};
TEST_F(QuicVersionManagerTest, QuicVersionManager) {
- static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u,
+ static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u,
"Supported versions out of sync");
SetQuicReloadableFlag(quic_enable_version_99, false);
SetQuicReloadableFlag(quic_enable_version_47, false);
SetQuicReloadableFlag(quic_enable_version_46, false);
- SetQuicReloadableFlag(quic_enable_version_45, false);
SetQuicReloadableFlag(quic_enable_version_44, false);
SetQuicReloadableFlag(quic_enable_version_43, false);
- SetQuicReloadableFlag(quic_disable_version_35, true);
+ SetQuicReloadableFlag(quic_disable_version_39, true);
QuicVersionManager manager(AllSupportedVersions());
EXPECT_EQ(FilterSupportedTransportVersions(AllSupportedTransportVersions()),
manager.GetSupportedTransportVersions());
+ EXPECT_TRUE(manager.GetSupportedTransportVersions().empty());
+
+ SetQuicReloadableFlag(quic_disable_version_39, false);
EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_39}),
manager.GetSupportedTransportVersions());
- SetQuicReloadableFlag(quic_disable_version_35, false);
- EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_39, QUIC_VERSION_35}),
- manager.GetSupportedTransportVersions());
-
SetQuicReloadableFlag(quic_enable_version_43, true);
- EXPECT_EQ(QuicTransportVersionVector(
- {QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35}),
+ EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_43, QUIC_VERSION_39}),
manager.GetSupportedTransportVersions());
SetQuicReloadableFlag(quic_enable_version_44, true);
- EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_44, QUIC_VERSION_43,
- QUIC_VERSION_39, QUIC_VERSION_35}),
- manager.GetSupportedTransportVersions());
-
- SetQuicReloadableFlag(quic_enable_version_45, true);
- EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_45, QUIC_VERSION_44,
- QUIC_VERSION_43, QUIC_VERSION_39,
- QUIC_VERSION_35}),
+ EXPECT_EQ(QuicTransportVersionVector(
+ {QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39}),
manager.GetSupportedTransportVersions());
SetQuicReloadableFlag(quic_enable_version_46, true);
- EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_46, QUIC_VERSION_45,
- QUIC_VERSION_44, QUIC_VERSION_43,
- QUIC_VERSION_39, QUIC_VERSION_35}),
+ EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_46, QUIC_VERSION_44,
+ QUIC_VERSION_43, QUIC_VERSION_39}),
manager.GetSupportedTransportVersions());
SetQuicReloadableFlag(quic_enable_version_47, true);
- EXPECT_EQ(
- QuicTransportVersionVector(
- {QUIC_VERSION_47, QUIC_VERSION_46, QUIC_VERSION_45, QUIC_VERSION_44,
- QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35}),
- manager.GetSupportedTransportVersions());
+ EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_47, QUIC_VERSION_46,
+ QUIC_VERSION_44, QUIC_VERSION_43,
+ QUIC_VERSION_39}),
+ manager.GetSupportedTransportVersions());
SetQuicReloadableFlag(quic_enable_version_99, true);
- EXPECT_EQ(
- QuicTransportVersionVector(
- {QUIC_VERSION_99, QUIC_VERSION_47, QUIC_VERSION_46, QUIC_VERSION_45,
- QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35}),
- manager.GetSupportedTransportVersions());
+ EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_99, QUIC_VERSION_47,
+ QUIC_VERSION_46, QUIC_VERSION_44,
+ QUIC_VERSION_43, QUIC_VERSION_39}),
+ manager.GetSupportedTransportVersions());
// Ensure that all versions are now supported.
EXPECT_EQ(FilterSupportedTransportVersions(AllSupportedTransportVersions()),
diff --git a/quic/core/quic_versions.cc b/quic/core/quic_versions.cc
index 6f050dd..efc823d 100644
--- a/quic/core/quic_versions.cc
+++ b/quic/core/quic_versions.cc
@@ -54,16 +54,12 @@
return 0;
}
switch (parsed_version.transport_version) {
- case QUIC_VERSION_35:
- return MakeVersionLabel(proto, '0', '3', '5');
case QUIC_VERSION_39:
return MakeVersionLabel(proto, '0', '3', '9');
case QUIC_VERSION_43:
return MakeVersionLabel(proto, '0', '4', '3');
case QUIC_VERSION_44:
return MakeVersionLabel(proto, '0', '4', '4');
- case QUIC_VERSION_45:
- return MakeVersionLabel(proto, '0', '4', '5');
case QUIC_VERSION_46:
return MakeVersionLabel(proto, '0', '4', '6');
case QUIC_VERSION_47:
@@ -123,6 +119,11 @@
continue;
}
for (QuicTransportVersion version : kSupportedTransportVersions) {
+ if (protocol == PROTOCOL_TLS1_3 && version < QUIC_VERSION_47) {
+ // The TLS handshake is only deployable if CRYPTO frames are also used,
+ // which are added in v47.
+ continue;
+ }
supported_versions.push_back(ParsedQuicVersion(protocol, version));
}
}
@@ -163,7 +164,6 @@
if (GetQuicReloadableFlag(quic_enable_version_99) &&
GetQuicReloadableFlag(quic_enable_version_47) &&
GetQuicReloadableFlag(quic_enable_version_46) &&
- GetQuicReloadableFlag(quic_enable_version_45) &&
GetQuicReloadableFlag(quic_enable_version_44) &&
GetQuicReloadableFlag(quic_enable_version_43)) {
filtered_versions.push_back(version);
@@ -171,20 +171,12 @@
} else if (version.transport_version == QUIC_VERSION_47) {
if (GetQuicReloadableFlag(quic_enable_version_47) &&
GetQuicReloadableFlag(quic_enable_version_46) &&
- GetQuicReloadableFlag(quic_enable_version_45) &&
GetQuicReloadableFlag(quic_enable_version_44) &&
GetQuicReloadableFlag(quic_enable_version_43)) {
filtered_versions.push_back(version);
}
} else if (version.transport_version == QUIC_VERSION_46) {
if (GetQuicReloadableFlag(quic_enable_version_46) &&
- GetQuicReloadableFlag(quic_enable_version_45) &&
- GetQuicReloadableFlag(quic_enable_version_44) &&
- GetQuicReloadableFlag(quic_enable_version_43)) {
- filtered_versions.push_back(version);
- }
- } else if (version.transport_version == QUIC_VERSION_45) {
- if (GetQuicReloadableFlag(quic_enable_version_45) &&
GetQuicReloadableFlag(quic_enable_version_44) &&
GetQuicReloadableFlag(quic_enable_version_43)) {
filtered_versions.push_back(version);
@@ -198,8 +190,8 @@
if (GetQuicReloadableFlag(quic_enable_version_43)) {
filtered_versions.push_back(version);
}
- } else if (version.transport_version == QUIC_VERSION_35) {
- if (!GetQuicReloadableFlag(quic_disable_version_35)) {
+ } else if (version.transport_version == QUIC_VERSION_39) {
+ if (!GetQuicReloadableFlag(quic_disable_version_39)) {
filtered_versions.push_back(version);
}
} else {
@@ -290,11 +282,9 @@
QuicString QuicVersionToString(QuicTransportVersion transport_version) {
switch (transport_version) {
- RETURN_STRING_LITERAL(QUIC_VERSION_35);
RETURN_STRING_LITERAL(QUIC_VERSION_39);
RETURN_STRING_LITERAL(QUIC_VERSION_43);
RETURN_STRING_LITERAL(QUIC_VERSION_44);
- RETURN_STRING_LITERAL(QUIC_VERSION_45);
RETURN_STRING_LITERAL(QUIC_VERSION_46);
RETURN_STRING_LITERAL(QUIC_VERSION_47);
RETURN_STRING_LITERAL(QUIC_VERSION_99);
diff --git a/quic/core/quic_versions.h b/quic/core/quic_versions.h
index 2c3ba1f..c0fa34a 100644
--- a/quic/core/quic_versions.h
+++ b/quic/core/quic_versions.h
@@ -76,9 +76,7 @@
// private flag from packet header and changed the ACK format to
// specify ranges of packets acknowledged rather than missing
// ranges.
-
- QUIC_VERSION_35 = 35, // Allows endpoints to independently set stream limit.
-
+ // Version 35 allows endpoints to independently set stream limit.
// Version 36 added support for forced head-of-line blocking experiments.
// Version 37 added perspective into null encryption.
// Version 38 switched to IETF padding frame format and support for NSTP (no
@@ -100,10 +98,12 @@
QUIC_VERSION_43 = 43, // PRIORITY frames are sent by client and accepted by
// server.
QUIC_VERSION_44 = 44, // Use IETF header format.
- QUIC_VERSION_45 = 45, // Added MESSAGE frame.
- QUIC_VERSION_46 = 46, // Use CRYPTO frames for QuicCryptoStreams.
- QUIC_VERSION_47 = 47, // Use IETF draft-17 header format with demultiplexing
+
+ // Version 45 added MESSAGE frame.
+
+ QUIC_VERSION_46 = 46, // Use IETF draft-17 header format with demultiplexing
// bit.
+ QUIC_VERSION_47 = 47, // Use CRYPTO frames for QuicCryptoStreams.
QUIC_VERSION_99 = 99, // Dumping ground for IETF QUIC changes which are not
// yet ready for production.
};
@@ -166,8 +166,9 @@
//
// See go/new-quic-version for more details on how to roll out new versions.
static const QuicTransportVersion kSupportedTransportVersions[] = {
- QUIC_VERSION_99, QUIC_VERSION_47, QUIC_VERSION_46, QUIC_VERSION_45,
- QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35};
+ QUIC_VERSION_99, QUIC_VERSION_47, QUIC_VERSION_46,
+ QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39,
+};
// This vector contains all crypto handshake protocols that are supported.
static const HandshakeProtocol kSupportedHandshakeProtocols[] = {
@@ -308,6 +309,38 @@
std::numeric_limits<size_t>::max());
}
+// Returns true if QuicSpdyStream encodes body using HTTP/3 specification and
+// sends data frame header along with body.
+QUIC_EXPORT_PRIVATE inline bool VersionHasDataFrameHeader(
+ QuicTransportVersion transport_version) {
+ return transport_version == QUIC_VERSION_99;
+}
+
+// Returns true if QuicSpdySession instantiates a QPACK encoder and decoder.
+// TODO(123528590): Implement the following features and gate them on this
+// function as well, optionally renaming this function as appropriate.
+// Send HEADERS on the request/response stream instead of the headers stream.
+// Send PUSH_PROMISE on the request/response stream instead of headers stream.
+// Send PRIORITY on the request/response stream instead of the headers stream.
+// Do not instantiate the headers stream object.
+QUIC_EXPORT_PRIVATE inline bool VersionUsesQpack(
+ QuicTransportVersion transport_version) {
+ const bool uses_qpack = (transport_version == QUIC_VERSION_99);
+ if (uses_qpack) {
+ DCHECK(VersionHasDataFrameHeader(transport_version));
+ }
+ return uses_qpack;
+}
+
+// Returns whether the transport_version supports the variable length integer
+// length field as defined by IETF QUIC draft-13 and later.
+QUIC_EXPORT_PRIVATE inline bool QuicVersionHasLongHeaderLengths(
+ QuicTransportVersion transport_version) {
+ // TODO(dschinazi) if we enable long header lengths before v99, we need to
+ // add support for fixing up lengths in QuicFramer::BuildDataPacket.
+ return transport_version == QUIC_VERSION_99;
+}
+
} // namespace quic
#endif // QUICHE_QUIC_CORE_QUIC_VERSIONS_H_
diff --git a/quic/core/quic_versions_test.cc b/quic/core/quic_versions_test.cc
index a0f664e..db7f53a 100644
--- a/quic/core/quic_versions_test.cc
+++ b/quic/core/quic_versions_test.cc
@@ -34,8 +34,8 @@
log.StartCapturingLogs();
// Explicitly test a specific version.
- EXPECT_EQ(MakeQuicTag('5', '3', '0', 'Q'),
- QuicVersionToQuicVersionLabel(QUIC_VERSION_35));
+ EXPECT_EQ(MakeQuicTag('9', '3', '0', 'Q'),
+ QuicVersionToQuicVersionLabel(QUIC_VERSION_39));
// Loop over all supported versions and make sure that we never hit the
// default case (i.e. all supported versions should be successfully converted
@@ -72,8 +72,8 @@
log.StartCapturingLogs();
// Explicitly test specific versions.
- EXPECT_EQ(QUIC_VERSION_35,
- QuicVersionLabelToQuicVersion(MakeQuicTag('5', '3', '0', 'Q')));
+ EXPECT_EQ(QUIC_VERSION_39,
+ QuicVersionLabelToQuicVersion(MakeQuicTag('9', '3', '0', 'Q')));
for (size_t i = 0; i < QUIC_ARRAYSIZE(kSupportedTransportVersions); ++i) {
QuicTransportVersion version = kSupportedTransportVersions[i];
@@ -130,16 +130,12 @@
}
TEST_F(QuicVersionsTest, ParseQuicVersionLabel) {
- EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_35),
- ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '3', '5')));
EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_39),
ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '3', '9')));
EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43),
ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '3')));
EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_44),
ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '4')));
- EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_45),
- ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '5')));
EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46),
ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '6')));
EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_47),
@@ -147,16 +143,12 @@
// Test a TLS version:
FLAGS_quic_supports_tls_handshake = true;
- EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_35),
- ParseQuicVersionLabel(MakeVersionLabel('T', '0', '3', '5')));
EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_39),
ParseQuicVersionLabel(MakeVersionLabel('T', '0', '3', '9')));
EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_43),
ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '3')));
EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_44),
ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '4')));
- EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_45),
- ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '5')));
EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_46),
ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '6')));
EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_47),
@@ -180,9 +172,6 @@
}
TEST_F(QuicVersionsTest, CreateQuicVersionLabel) {
- EXPECT_EQ(MakeVersionLabel('Q', '0', '3', '5'),
- CreateQuicVersionLabel(
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_35)));
EXPECT_EQ(MakeVersionLabel('Q', '0', '3', '9'),
CreateQuicVersionLabel(
ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_39)));
@@ -192,9 +181,6 @@
EXPECT_EQ(MakeVersionLabel('Q', '0', '4', '4'),
CreateQuicVersionLabel(
ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_44)));
- EXPECT_EQ(MakeVersionLabel('Q', '0', '4', '5'),
- CreateQuicVersionLabel(
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_45)));
EXPECT_EQ(MakeVersionLabel('Q', '0', '4', '6'),
CreateQuicVersionLabel(
ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46)));
@@ -204,9 +190,6 @@
// Test a TLS version:
FLAGS_quic_supports_tls_handshake = true;
- EXPECT_EQ(MakeVersionLabel('T', '0', '3', '5'),
- CreateQuicVersionLabel(
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_35)));
EXPECT_EQ(MakeVersionLabel('T', '0', '3', '9'),
CreateQuicVersionLabel(
ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_39)));
@@ -216,9 +199,6 @@
EXPECT_EQ(MakeVersionLabel('T', '0', '4', '4'),
CreateQuicVersionLabel(
ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_44)));
- EXPECT_EQ(MakeVersionLabel('T', '0', '4', '5'),
- CreateQuicVersionLabel(
- ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_45)));
EXPECT_EQ(MakeVersionLabel('T', '0', '4', '6'),
CreateQuicVersionLabel(
ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_46)));
@@ -236,8 +216,6 @@
EXPECT_EQ(UnsupportedQuicVersion(),
ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '4')));
EXPECT_EQ(UnsupportedQuicVersion(),
- ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '5')));
- EXPECT_EQ(UnsupportedQuicVersion(),
ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '6')));
EXPECT_EQ(UnsupportedQuicVersion(),
ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '7')));
@@ -261,25 +239,25 @@
}
TEST_F(QuicVersionsTest, QuicVersionToString) {
- EXPECT_EQ("QUIC_VERSION_35", QuicVersionToString(QUIC_VERSION_35));
+ EXPECT_EQ("QUIC_VERSION_39", QuicVersionToString(QUIC_VERSION_39));
EXPECT_EQ("QUIC_VERSION_UNSUPPORTED",
QuicVersionToString(QUIC_VERSION_UNSUPPORTED));
- QuicTransportVersion single_version[] = {QUIC_VERSION_35};
+ QuicTransportVersion single_version[] = {QUIC_VERSION_39};
QuicTransportVersionVector versions_vector;
for (size_t i = 0; i < QUIC_ARRAYSIZE(single_version); ++i) {
versions_vector.push_back(single_version[i]);
}
- EXPECT_EQ("QUIC_VERSION_35",
+ EXPECT_EQ("QUIC_VERSION_39",
QuicTransportVersionVectorToString(versions_vector));
QuicTransportVersion multiple_versions[] = {QUIC_VERSION_UNSUPPORTED,
- QUIC_VERSION_35};
+ QUIC_VERSION_39};
versions_vector.clear();
for (size_t i = 0; i < QUIC_ARRAYSIZE(multiple_versions); ++i) {
versions_vector.push_back(multiple_versions[i]);
}
- EXPECT_EQ("QUIC_VERSION_UNSUPPORTED,QUIC_VERSION_35",
+ EXPECT_EQ("QUIC_VERSION_UNSUPPORTED,QUIC_VERSION_39",
QuicTransportVersionVectorToString(versions_vector));
// Make sure that all supported versions are present in QuicVersionToString.
@@ -291,16 +269,16 @@
TEST_F(QuicVersionsTest, ParsedQuicVersionToString) {
ParsedQuicVersion unsupported = UnsupportedQuicVersion();
- ParsedQuicVersion version35(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_35);
- EXPECT_EQ("Q035", ParsedQuicVersionToString(version35));
+ ParsedQuicVersion version39(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_39);
+ EXPECT_EQ("Q039", ParsedQuicVersionToString(version39));
EXPECT_EQ("0", ParsedQuicVersionToString(unsupported));
- ParsedQuicVersionVector versions_vector = {version35};
- EXPECT_EQ("Q035", ParsedQuicVersionVectorToString(versions_vector));
+ ParsedQuicVersionVector versions_vector = {version39};
+ EXPECT_EQ("Q039", ParsedQuicVersionVectorToString(versions_vector));
- versions_vector = {unsupported, version35};
- EXPECT_EQ("0,Q035", ParsedQuicVersionVectorToString(versions_vector));
- EXPECT_EQ("0:Q035", ParsedQuicVersionVectorToString(versions_vector, ":",
+ versions_vector = {unsupported, version39};
+ EXPECT_EQ("0,Q039", ParsedQuicVersionVectorToString(versions_vector));
+ EXPECT_EQ("0:Q039", ParsedQuicVersionVectorToString(versions_vector, ":",
versions_vector.size()));
EXPECT_EQ("0|...", ParsedQuicVersionVectorToString(versions_vector, "|", 0));
@@ -324,10 +302,9 @@
TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsAllVersions) {
QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
- SetQuicReloadableFlag(quic_disable_version_35, false);
+ SetQuicReloadableFlag(quic_disable_version_39, false);
SetQuicReloadableFlag(quic_enable_version_43, true);
SetQuicReloadableFlag(quic_enable_version_44, true);
- SetQuicReloadableFlag(quic_enable_version_45, true);
SetQuicReloadableFlag(quic_enable_version_46, true);
SetQuicReloadableFlag(quic_enable_version_47, true);
SetQuicReloadableFlag(quic_enable_version_99, true);
@@ -336,8 +313,8 @@
parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
}
QuicTransportVersionVector expected_versions = {
- QUIC_VERSION_99, QUIC_VERSION_47, QUIC_VERSION_46, QUIC_VERSION_45,
- QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35};
+ QUIC_VERSION_99, QUIC_VERSION_47, QUIC_VERSION_46,
+ QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39};
ParsedQuicVersionVector expected_parsed_versions;
for (QuicTransportVersion version : expected_versions) {
expected_parsed_versions.push_back(
@@ -350,10 +327,9 @@
TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo99) {
QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
- SetQuicReloadableFlag(quic_disable_version_35, false);
+ SetQuicReloadableFlag(quic_disable_version_39, false);
SetQuicReloadableFlag(quic_enable_version_43, true);
SetQuicReloadableFlag(quic_enable_version_44, true);
- SetQuicReloadableFlag(quic_enable_version_45, true);
SetQuicReloadableFlag(quic_enable_version_46, true);
SetQuicReloadableFlag(quic_enable_version_47, true);
SetQuicReloadableFlag(quic_enable_version_99, false);
@@ -362,8 +338,8 @@
parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
}
QuicTransportVersionVector expected_versions = {
- QUIC_VERSION_47, QUIC_VERSION_46, QUIC_VERSION_45, QUIC_VERSION_44,
- QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35};
+ QUIC_VERSION_47, QUIC_VERSION_46, QUIC_VERSION_44, QUIC_VERSION_43,
+ QUIC_VERSION_39};
ParsedQuicVersionVector expected_parsed_versions;
for (QuicTransportVersion version : expected_versions) {
expected_parsed_versions.push_back(
@@ -376,10 +352,9 @@
TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo47) {
QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
- SetQuicReloadableFlag(quic_disable_version_35, false);
+ SetQuicReloadableFlag(quic_disable_version_39, false);
SetQuicReloadableFlag(quic_enable_version_43, true);
SetQuicReloadableFlag(quic_enable_version_44, true);
- SetQuicReloadableFlag(quic_enable_version_45, true);
SetQuicReloadableFlag(quic_enable_version_46, true);
SetQuicReloadableFlag(quic_enable_version_47, false);
SetQuicReloadableFlag(quic_enable_version_99, false);
@@ -388,8 +363,7 @@
parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
}
QuicTransportVersionVector expected_versions = {
- QUIC_VERSION_46, QUIC_VERSION_45, QUIC_VERSION_44,
- QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35};
+ QUIC_VERSION_46, QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39};
ParsedQuicVersionVector expected_parsed_versions;
for (QuicTransportVersion version : expected_versions) {
expected_parsed_versions.push_back(
@@ -402,10 +376,9 @@
TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo46) {
QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
- SetQuicReloadableFlag(quic_disable_version_35, false);
+ SetQuicReloadableFlag(quic_disable_version_39, false);
SetQuicReloadableFlag(quic_enable_version_43, true);
SetQuicReloadableFlag(quic_enable_version_44, true);
- SetQuicReloadableFlag(quic_enable_version_45, true);
SetQuicReloadableFlag(quic_enable_version_46, false);
SetQuicReloadableFlag(quic_enable_version_47, false);
SetQuicReloadableFlag(quic_enable_version_99, false);
@@ -414,33 +387,7 @@
parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
}
QuicTransportVersionVector expected_versions = {
- QUIC_VERSION_45, QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39,
- QUIC_VERSION_35};
- ParsedQuicVersionVector expected_parsed_versions;
- for (QuicTransportVersion version : expected_versions) {
- expected_parsed_versions.push_back(
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
- }
-
- ASSERT_EQ(expected_versions, FilterSupportedTransportVersions(all_versions));
- ASSERT_EQ(expected_parsed_versions, FilterSupportedVersions(parsed_versions));
-}
-
-TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo45) {
- QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
- SetQuicReloadableFlag(quic_disable_version_35, false);
- SetQuicReloadableFlag(quic_enable_version_43, true);
- SetQuicReloadableFlag(quic_enable_version_44, true);
- SetQuicReloadableFlag(quic_enable_version_45, false);
- SetQuicReloadableFlag(quic_enable_version_46, false);
- SetQuicReloadableFlag(quic_enable_version_47, false);
- SetQuicReloadableFlag(quic_enable_version_99, false);
- ParsedQuicVersionVector parsed_versions;
- for (QuicTransportVersion version : all_versions) {
- parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
- }
- QuicTransportVersionVector expected_versions = {
- QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35};
+ QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39};
ParsedQuicVersionVector expected_parsed_versions;
for (QuicTransportVersion version : expected_versions) {
expected_parsed_versions.push_back(
@@ -453,10 +400,9 @@
TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo44) {
QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
- SetQuicReloadableFlag(quic_disable_version_35, false);
+ SetQuicReloadableFlag(quic_disable_version_39, false);
SetQuicReloadableFlag(quic_enable_version_43, true);
SetQuicReloadableFlag(quic_enable_version_44, false);
- SetQuicReloadableFlag(quic_enable_version_45, false);
SetQuicReloadableFlag(quic_enable_version_46, false);
SetQuicReloadableFlag(quic_enable_version_47, false);
SetQuicReloadableFlag(quic_enable_version_99, false);
@@ -464,8 +410,8 @@
for (QuicTransportVersion version : all_versions) {
parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
}
- QuicTransportVersionVector expected_versions = {
- QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35};
+ QuicTransportVersionVector expected_versions = {QUIC_VERSION_43,
+ QUIC_VERSION_39};
ParsedQuicVersionVector expected_parsed_versions;
for (QuicTransportVersion version : expected_versions) {
expected_parsed_versions.push_back(
@@ -478,35 +424,9 @@
TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo43) {
QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
- SetQuicReloadableFlag(quic_disable_version_35, false);
+ SetQuicReloadableFlag(quic_disable_version_39, false);
SetQuicReloadableFlag(quic_enable_version_43, false);
SetQuicReloadableFlag(quic_enable_version_44, false);
- SetQuicReloadableFlag(quic_enable_version_45, false);
- SetQuicReloadableFlag(quic_enable_version_46, false);
- SetQuicReloadableFlag(quic_enable_version_47, false);
- SetQuicReloadableFlag(quic_enable_version_99, false);
- ParsedQuicVersionVector parsed_versions;
- for (QuicTransportVersion version : all_versions) {
- parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
- }
- QuicTransportVersionVector expected_versions = {QUIC_VERSION_39,
- QUIC_VERSION_35};
- ParsedQuicVersionVector expected_parsed_versions;
- for (QuicTransportVersion version : expected_versions) {
- expected_parsed_versions.push_back(
- ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
- }
-
- ASSERT_EQ(expected_versions, FilterSupportedTransportVersions(all_versions));
- ASSERT_EQ(expected_parsed_versions, FilterSupportedVersions(parsed_versions));
-}
-
-TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo35) {
- QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
- SetQuicReloadableFlag(quic_disable_version_35, true);
- SetQuicReloadableFlag(quic_enable_version_43, false);
- SetQuicReloadableFlag(quic_enable_version_44, false);
- SetQuicReloadableFlag(quic_enable_version_45, false);
SetQuicReloadableFlag(quic_enable_version_46, false);
SetQuicReloadableFlag(quic_enable_version_47, false);
SetQuicReloadableFlag(quic_enable_version_99, false);
@@ -525,8 +445,31 @@
ASSERT_EQ(expected_parsed_versions, FilterSupportedVersions(parsed_versions));
}
+TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo39) {
+ QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
+ SetQuicReloadableFlag(quic_disable_version_39, true);
+ SetQuicReloadableFlag(quic_enable_version_43, true);
+ SetQuicReloadableFlag(quic_enable_version_44, false);
+ SetQuicReloadableFlag(quic_enable_version_46, false);
+ SetQuicReloadableFlag(quic_enable_version_47, false);
+ SetQuicReloadableFlag(quic_enable_version_99, false);
+ ParsedQuicVersionVector parsed_versions;
+ for (QuicTransportVersion version : all_versions) {
+ parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
+ }
+ QuicTransportVersionVector expected_versions = {QUIC_VERSION_43};
+ ParsedQuicVersionVector expected_parsed_versions;
+ for (QuicTransportVersion version : expected_versions) {
+ expected_parsed_versions.push_back(
+ ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
+ }
+
+ ASSERT_EQ(expected_versions, FilterSupportedTransportVersions(all_versions));
+ ASSERT_EQ(expected_parsed_versions, FilterSupportedVersions(parsed_versions));
+}
+
TEST_F(QuicVersionsTest, LookUpVersionByIndex) {
- QuicTransportVersionVector all_versions = {QUIC_VERSION_35, QUIC_VERSION_39};
+ QuicTransportVersionVector all_versions = {QUIC_VERSION_39};
int version_count = all_versions.size();
for (int i = -5; i <= version_count + 1; ++i) {
if (i >= 0 && i < version_count) {
@@ -564,13 +507,11 @@
// yet a typo was made in doing the #defines and it was caught
// only in some test far removed from here... Better safe than sorry.
TEST_F(QuicVersionsTest, CheckVersionNumbersForTypos) {
- static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u,
+ static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u,
"Supported versions out of sync");
- EXPECT_EQ(QUIC_VERSION_35, 35);
EXPECT_EQ(QUIC_VERSION_39, 39);
EXPECT_EQ(QUIC_VERSION_43, 43);
EXPECT_EQ(QUIC_VERSION_44, 44);
- EXPECT_EQ(QUIC_VERSION_45, 45);
EXPECT_EQ(QUIC_VERSION_46, 46);
EXPECT_EQ(QUIC_VERSION_47, 47);
EXPECT_EQ(QUIC_VERSION_99, 99);
diff --git a/quic/core/stateless_rejector_test.cc b/quic/core/stateless_rejector_test.cc
index 497fe54..19eef64 100644
--- a/quic/core/stateless_rejector_test.cc
+++ b/quic/core/stateless_rejector_test.cc
@@ -169,10 +169,9 @@
QuicString stk_hex_;
};
-INSTANTIATE_TEST_CASE_P(Flags,
- StatelessRejectorTest,
- ::testing::ValuesIn(GetTestParams()),
- TestParamToString);
+INSTANTIATE_TEST_SUITE_P(Flags, StatelessRejectorTest,
+ ::testing::ValuesIn(GetTestParams()),
+ TestParamToString);
TEST_P(StatelessRejectorTest, InvalidChlo) {
// clang-format off
diff --git a/quic/core/tls_handshaker.cc b/quic/core/tls_handshaker.cc
index a471aa4..e2efa0f 100644
--- a/quic/core/tls_handshaker.cc
+++ b/quic/core/tls_handshaker.cc
@@ -108,7 +108,7 @@
return ENCRYPTION_NONE;
case ssl_encryption_early_data:
case ssl_encryption_handshake:
- return ENCRYPTION_INITIAL;
+ return ENCRYPTION_ZERO_RTT;
case ssl_encryption_application:
return ENCRYPTION_FORWARD_SECURE;
}
@@ -120,7 +120,7 @@
switch (level) {
case ENCRYPTION_NONE:
return ssl_encryption_initial;
- case ENCRYPTION_INITIAL:
+ case ENCRYPTION_ZERO_RTT:
return ssl_encryption_handshake;
case ENCRYPTION_FORWARD_SECURE:
return ssl_encryption_application;
@@ -214,7 +214,7 @@
// alternative decrypter instead of the primary decrypter. One reason for
// this is that after the forward secure keys become available, the server
// still has crypto handshake messages to read at the handshake encryption
- // level, meaning that both the ENCRYPTION_INITIAL and
+ // level, meaning that both the ENCRYPTION_ZERO_RTT and
// ENCRYPTION_FORWARD_SECURE decrypters need to be available. (Tests also
// assume that an alternative decrypter gets set, so at some point we need
// to call SetAlternativeDecrypter.)
diff --git a/quic/core/uber_quic_stream_id_manager_test.cc b/quic/core/uber_quic_stream_id_manager_test.cc
index a413a0b..353e35d 100644
--- a/quic/core/uber_quic_stream_id_manager_test.cc
+++ b/quic/core/uber_quic_stream_id_manager_test.cc
@@ -67,10 +67,9 @@
QuicFrame frame_;
};
-INSTANTIATE_TEST_CASE_P(Tests,
- UberQuicStreamIdManagerTest,
- ::testing::ValuesIn({Perspective::IS_CLIENT,
- Perspective::IS_SERVER}));
+INSTANTIATE_TEST_SUITE_P(Tests, UberQuicStreamIdManagerTest,
+ ::testing::ValuesIn({Perspective::IS_CLIENT,
+ Perspective::IS_SERVER}));
TEST_P(UberQuicStreamIdManagerTest, Initialization) {
if (GetParam() == Perspective::IS_SERVER) {
diff --git a/quic/platform/api/quic_containers.h b/quic/platform/api/quic_containers.h
index 04c462e..7cfb311 100644
--- a/quic/platform/api/quic_containers.h
+++ b/quic/platform/api/quic_containers.h
@@ -33,11 +33,6 @@
template <typename Key, typename Value, int Size>
using QuicSmallMap = QuicSmallMapImpl<Key, Value, Size>;
-// A data structure used to represent a sorted set of non-empty, non-adjacent,
-// and mutually disjoint intervals.
-template <typename T>
-using QuicIntervalSet = QuicIntervalSetImpl<T>;
-
// Represents a simple queue which may be backed by a list or
// a flat circular buffer.
//
diff --git a/quic/platform/api/quic_default_proof_providers.h b/quic/platform/api/quic_default_proof_providers.h
new file mode 100644
index 0000000..ab683c1
--- /dev/null
+++ b/quic/platform/api/quic_default_proof_providers.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_PLATFORM_API_QUIC_DEFAULT_PROOF_PROVIDERS_H_
+#define QUICHE_QUIC_PLATFORM_API_QUIC_DEFAULT_PROOF_PROVIDERS_H_
+
+#include <memory>
+
+#include "net/third_party/quiche/src/quic/core/crypto/proof_verifier.h"
+#include "net/quic/platform/impl/quic_default_proof_providers_impl.h"
+
+namespace quic {
+
+// Provides a default proof verifier. The verifier has to do a good faith
+// attempt at verifying the certificate against a reasonable root store, and not
+// just always return success.
+std::unique_ptr<ProofVerifier> CreateDefaultProofVerifier() {
+ return CreateDefaultProofVerifierImpl();
+}
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_PLATFORM_API_QUIC_DEFAULT_PROOF_PROVIDERS_H_
diff --git a/quic/platform/api/quic_epoll.h b/quic/platform/api/quic_epoll.h
index c289ef4..e429ef8 100644
--- a/quic/platform/api/quic_epoll.h
+++ b/quic/platform/api/quic_epoll.h
@@ -1,3 +1,7 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
#ifndef QUICHE_QUIC_PLATFORM_API_QUIC_EPOLL_H_
#define QUICHE_QUIC_PLATFORM_API_QUIC_EPOLL_H_
diff --git a/quic/platform/api/quic_error_code_wrappers.h b/quic/platform/api/quic_error_code_wrappers.h
new file mode 100644
index 0000000..733572e
--- /dev/null
+++ b/quic/platform/api/quic_error_code_wrappers.h
@@ -0,0 +1,14 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_PLATFORM_API_QUIC_ERROR_CODE_WRAPPERS_H_
+#define QUICHE_QUIC_PLATFORM_API_QUIC_ERROR_CODE_WRAPPERS_H_
+
+#include "net/quic/platform/impl/quic_error_code_wrappers_impl.h"
+
+// TODO(vasilvv): ensure WRITE_STATUS_MSG_TOO_BIG works everywhere and remove
+// this.
+#define QUIC_EMSGSIZE QUIC_EMSGSIZE_IMPL
+
+#endif // QUICHE_QUIC_PLATFORM_API_QUIC_ERROR_CODE_WRAPPERS_H_
diff --git a/quic/platform/api/quic_exported_stats.h b/quic/platform/api/quic_exported_stats.h
index b911c70..28c82ec 100644
--- a/quic/platform/api/quic_exported_stats.h
+++ b/quic/platform/api/quic_exported_stats.h
@@ -64,9 +64,9 @@
#define QUIC_HISTOGRAM_TIMES(name, sample, min, max, bucket_count, docstring) \
do { \
QUIC_CLIENT_HISTOGRAM_TIMES_IMPL(name, sample, min, max, bucket_count, \
- docstring) \
+ docstring); \
QUIC_SERVER_HISTOGRAM_TIMES_IMPL(name, sample, min, max, bucket_count, \
- docstring) \
+ docstring); \
} while (0)
//------------------------------------------------------------------------------
diff --git a/quic/platform/api/quic_flags.h b/quic/platform/api/quic_flags.h
index 6ddc13a..45145a7 100644
--- a/quic/platform/api/quic_flags.h
+++ b/quic/platform/api/quic_flags.h
@@ -5,8 +5,16 @@
#ifndef QUICHE_QUIC_PLATFORM_API_QUIC_FLAGS_H_
#define QUICHE_QUIC_PLATFORM_API_QUIC_FLAGS_H_
+#include <vector>
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
#include "net/quic/platform/impl/quic_flags_impl.h"
+// Define a command-line flag that can be automatically set via
+// QuicParseCommandLineFlags().
+#define DEFINE_QUIC_COMMAND_LINE_FLAG(type, name, default_value, help) \
+ DEFINE_QUIC_COMMAND_LINE_FLAG_IMPL(type, name, default_value, help)
+
#define GetQuicReloadableFlag(flag) GetQuicReloadableFlagImpl(flag)
#define SetQuicReloadableFlag(flag, value) \
SetQuicReloadableFlagImpl(flag, value)
@@ -15,4 +23,26 @@
#define GetQuicFlag(flag) GetQuicFlagImpl(flag)
#define SetQuicFlag(flag, value) SetQuicFlagImpl(flag, value)
+namespace quic {
+
+// Parses command-line flags, setting flag variables defined using
+// DEFINE_QUIC_COMMAND_LINE_FLAG if they appear in the command line, and
+// returning a list of any non-flag arguments specified in the command line. If
+// the command line specifies '-h' or '--help', prints a usage message with flag
+// descriptions to stdout and exits with status 0. If a flag has an unparsable
+// value, writes an error message to stderr and exits with status 1.
+inline std::vector<QuicString> QuicParseCommandLineFlags(
+ const char* usage,
+ int argc,
+ const char* const* argv) {
+ return QuicParseCommandLineFlagsImpl(usage, argc, argv);
+}
+
+// Prints a usage message with flag descriptions to stdout.
+inline void QuicPrintCommandLineFlagHelp(const char* usage) {
+ QuicPrintCommandLineFlagHelpImpl(usage);
+}
+
+} // namespace quic
+
#endif // QUICHE_QUIC_PLATFORM_API_QUIC_FLAGS_H_
diff --git a/quic/platform/api/quic_interval.h b/quic/platform/api/quic_interval.h
deleted file mode 100644
index 51d2f52..0000000
--- a/quic/platform/api/quic_interval.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef QUICHE_QUIC_PLATFORM_API_QUIC_INTERVAL_H_
-#define QUICHE_QUIC_PLATFORM_API_QUIC_INTERVAL_H_
-
-#include "net/quic/platform/impl/quic_interval_impl.h"
-
-namespace quic {
-
-template <class T>
-using QuicInterval = QuicIntervalImpl<T>;
-
-} // namespace quic
-
-#endif // QUICHE_QUIC_PLATFORM_API_QUIC_INTERVAL_H_
diff --git a/quic/platform/api/quic_macros.h b/quic/platform/api/quic_macros.h
new file mode 100644
index 0000000..9dee2e9
--- /dev/null
+++ b/quic/platform/api/quic_macros.h
@@ -0,0 +1,13 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_PLATFORM_API_QUIC_MACROS_H_
+#define QUICHE_QUIC_PLATFORM_API_QUIC_MACROS_H_
+
+#include "net/quic/platform/impl/quic_macros_impl.h"
+
+#define QUIC_MUST_USE_RESULT QUIC_MUST_USE_RESULT_IMPL
+#define QUIC_UNUSED QUIC_UNUSED_IMPL
+
+#endif // QUICHE_QUIC_PLATFORM_API_QUIC_MACROS_H_
diff --git a/quic/platform/api/quic_mem_slice_span.h b/quic/platform/api/quic_mem_slice_span.h
index 39436be..781382e 100644
--- a/quic/platform/api/quic_mem_slice_span.h
+++ b/quic/platform/api/quic_mem_slice_span.h
@@ -35,6 +35,12 @@
return impl_.SaveMemSlicesInSendBuffer(send_buffer);
}
+ // Save data buffers as message data in |message_frame|. |message_frame| will
+ // hold a reference to all data buffers.
+ void SaveMemSlicesAsMessageData(QuicMessageFrame* message_frame) {
+ impl_.SaveMemSlicesAsMessageData(message_frame);
+ }
+
// Return data of the span at |index| by the form of a QuicStringPiece.
QuicStringPiece GetData(int index) { return impl_.GetData(index); }
diff --git a/quic/platform/api/quic_mem_slice_storage_test.cc b/quic/platform/api/quic_mem_slice_storage_test.cc
index d5a5b8f..72623e1 100644
--- a/quic/platform/api/quic_mem_slice_storage_test.cc
+++ b/quic/platform/api/quic_mem_slice_storage_test.cc
@@ -4,7 +4,6 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage.h"
#include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h"
-
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
namespace quic {
diff --git a/quic/platform/api/quic_port_utils.h b/quic/platform/api/quic_port_utils.h
new file mode 100644
index 0000000..aa85fc5
--- /dev/null
+++ b/quic/platform/api/quic_port_utils.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_PLATFORM_API_QUIC_PORT_UTILS_H_
+#define QUICHE_QUIC_PLATFORM_API_QUIC_PORT_UTILS_H_
+
+#include "net/quic/platform/impl/quic_port_utils_impl.h"
+
+namespace quic {
+
+// Returns a UDP port that is currently unused. Check-fails if none are
+// available.
+inline int QuicPickUnusedPortOrDie() {
+ return QuicPickUnusedPortOrDieImpl();
+}
+
+// Indicates that a specified port previously returned by
+// QuicPickUnusedPortOrDie is no longer used.
+inline void QuicRecyclePort(int port) {
+ return QuicRecyclePortImpl(port);
+}
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_PLATFORM_API_QUIC_PORT_UTILS_H_
diff --git a/quic/quartc/quartc_connection_helper.cc b/quic/quartc/quartc_connection_helper.cc
new file mode 100644
index 0000000..6c6ee97
--- /dev/null
+++ b/quic/quartc/quartc_connection_helper.cc
@@ -0,0 +1,24 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/quartc/quartc_connection_helper.h"
+
+namespace quic {
+
+QuartcConnectionHelper::QuartcConnectionHelper(const QuicClock* clock)
+ : clock_(clock) {}
+
+const QuicClock* QuartcConnectionHelper::GetClock() const {
+ return clock_;
+}
+
+QuicRandom* QuartcConnectionHelper::GetRandomGenerator() {
+ return QuicRandom::GetInstance();
+}
+
+QuicBufferAllocator* QuartcConnectionHelper::GetStreamSendBufferAllocator() {
+ return &buffer_allocator_;
+}
+
+} // namespace quic
diff --git a/quic/quartc/quartc_connection_helper.h b/quic/quartc/quartc_connection_helper.h
new file mode 100644
index 0000000..2b1d62f
--- /dev/null
+++ b/quic/quartc/quartc_connection_helper.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QUARTC_QUARTC_CONNECTION_HELPER_H_
+#define QUICHE_QUIC_QUARTC_QUARTC_CONNECTION_HELPER_H_
+
+#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
+#include "net/third_party/quiche/src/quic/core/quic_buffer_allocator.h"
+#include "net/third_party/quiche/src/quic/core/quic_connection.h"
+#include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_clock.h"
+
+namespace quic {
+
+// Simple implementation of QuicConnectionHelperInterface for Quartc.
+class QuartcConnectionHelper : public QuicConnectionHelperInterface {
+ public:
+ explicit QuartcConnectionHelper(const QuicClock* clock);
+
+ // QuicConnectionHelperInterface overrides.
+ const QuicClock* GetClock() const override;
+ QuicRandom* GetRandomGenerator() override;
+ QuicBufferAllocator* GetStreamSendBufferAllocator() override;
+
+ private:
+ const QuicClock* clock_;
+ SimpleBufferAllocator buffer_allocator_;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QUARTC_QUARTC_CONNECTION_HELPER_H_
diff --git a/quic/quartc/quartc_crypto_helpers.cc b/quic/quartc/quartc_crypto_helpers.cc
new file mode 100644
index 0000000..865fec4
--- /dev/null
+++ b/quic/quartc/quartc_crypto_helpers.cc
@@ -0,0 +1,162 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.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"
+
+namespace quic {
+
+void DummyProofSource::GetProof(const QuicSocketAddress& server_address,
+ const QuicString& hostname,
+ const QuicString& server_config,
+ QuicTransportVersion transport_version,
+ QuicStringPiece chlo_hash,
+ std::unique_ptr<Callback> callback) {
+ QuicReferenceCountedPointer<ProofSource::Chain> chain =
+ GetCertChain(server_address, hostname);
+ QuicCryptoProof proof;
+ proof.signature = "Dummy signature";
+ proof.leaf_cert_scts = "Dummy timestamp";
+ callback->Run(true, chain, proof, nullptr /* details */);
+}
+
+QuicReferenceCountedPointer<DummyProofSource::Chain>
+DummyProofSource::GetCertChain(const QuicSocketAddress& server_address,
+ const QuicString& hostname) {
+ std::vector<QuicString> certs;
+ certs.push_back(kDummyCertName);
+ return QuicReferenceCountedPointer<ProofSource::Chain>(
+ new ProofSource::Chain(certs));
+}
+
+void DummyProofSource::ComputeTlsSignature(
+ const QuicSocketAddress& server_address,
+ const QuicString& hostname,
+ uint16_t signature_algorithm,
+ QuicStringPiece in,
+ std::unique_ptr<SignatureCallback> callback) {
+ callback->Run(true, "Dummy signature");
+}
+
+QuicAsyncStatus InsecureProofVerifier::VerifyProof(
+ const QuicString& hostname,
+ const uint16_t port,
+ const QuicString& server_config,
+ QuicTransportVersion transport_version,
+ QuicStringPiece chlo_hash,
+ const std::vector<QuicString>& certs,
+ const QuicString& cert_sct,
+ const QuicString& signature,
+ const ProofVerifyContext* context,
+ QuicString* error_details,
+ std::unique_ptr<ProofVerifyDetails>* verify_details,
+ std::unique_ptr<ProofVerifierCallback> callback) {
+ return QUIC_SUCCESS;
+}
+
+QuicAsyncStatus InsecureProofVerifier::VerifyCertChain(
+ const QuicString& hostname,
+ const std::vector<QuicString>& certs,
+ const ProofVerifyContext* context,
+ QuicString* error_details,
+ std::unique_ptr<ProofVerifyDetails>* details,
+ std::unique_ptr<ProofVerifierCallback> callback) {
+ return QUIC_SUCCESS;
+}
+
+std::unique_ptr<ProofVerifyContext>
+InsecureProofVerifier::CreateDefaultContext() {
+ return nullptr;
+}
+
+QuicConnectionId QuartcCryptoServerStreamHelper::GenerateConnectionIdForReject(
+ QuicTransportVersion version,
+ QuicConnectionId connection_id) const {
+ // TODO(b/124399417): Request a zero-length connection id here when the QUIC
+ // server perspective supports it. Right now, the stateless rejector requires
+ // a connection id that is not the same as the client-chosen connection id.
+ return QuicUtils::CreateRandomConnectionId();
+}
+
+bool QuartcCryptoServerStreamHelper::CanAcceptClientHello(
+ const CryptoHandshakeMessage& message,
+ const QuicSocketAddress& client_address,
+ const QuicSocketAddress& peer_address,
+ const QuicSocketAddress& self_address,
+ QuicString* error_details) const {
+ return true;
+}
+
+std::unique_ptr<QuicCryptoClientConfig> CreateCryptoClientConfig(
+ QuicStringPiece pre_shared_key) {
+ auto config = QuicMakeUnique<QuicCryptoClientConfig>(
+ QuicMakeUnique<InsecureProofVerifier>(),
+ TlsClientHandshaker::CreateSslCtx());
+ config->set_pad_inchoate_hello(false);
+ config->set_pad_full_hello(false);
+ if (!pre_shared_key.empty()) {
+ config->set_pre_shared_key(pre_shared_key);
+ }
+ return config;
+}
+
+CryptoServerConfig CreateCryptoServerConfig(QuicRandom* random,
+ const QuicClock* clock,
+ QuicStringPiece pre_shared_key) {
+ CryptoServerConfig crypto_server_config;
+
+ // Generate a random source address token secret. For long-running servers
+ // it's better to not regenerate it for each connection to enable zero-RTT
+ // handshakes, but for transient clients it does not matter.
+ char source_address_token_secret[kInputKeyingMaterialLength];
+ random->RandBytes(source_address_token_secret, kInputKeyingMaterialLength);
+ auto config = QuicMakeUnique<QuicCryptoServerConfig>(
+ QuicString(source_address_token_secret, kInputKeyingMaterialLength),
+ random, QuicMakeUnique<DummyProofSource>(), KeyExchangeSource::Default(),
+ TlsServerHandshaker::CreateSslCtx());
+
+ // We run QUIC over ICE, and ICE is verifying remote side with STUN pings.
+ // We disable source address token validation in order to allow for 0-rtt
+ // setup (plus source ip addresses are changing even during the connection
+ // when ICE is used).
+ config->set_validate_source_address_token(false);
+
+ // Effectively disables the anti-amplification measures (we don't need
+ // them because we use ICE, and we need to disable them because we disable
+ // padding of crypto packets).
+ // This multiplier must be large enough so that the crypto handshake packet
+ // (approx. 300 bytes) multiplied by this multiplier is larger than a fully
+ // sized packet (currently 1200 bytes).
+ // 1500 is a bit extreme: if you can imagine sending a 1 byte packet, and
+ // your largest MTU would be below 1500 bytes, 1500*1 >=
+ // any_packet_that_you_can_imagine_sending.
+ // (again, we hardcode packet size to 1200, so we are not dealing with jumbo
+ // frames).
+ config->set_chlo_multiplier(1500);
+
+ // We are sending small client hello, we must not validate its size.
+ config->set_validate_chlo_size(false);
+
+ // Provide server with serialized config string to prove ownership.
+ QuicCryptoServerConfig::ConfigOptions options;
+ // The |message| is used to handle the return value of AddDefaultConfig
+ // which is raw pointer of the CryptoHandshakeMessage.
+ std::unique_ptr<CryptoHandshakeMessage> message(
+ config->AddDefaultConfig(random, clock, options));
+ config->set_pad_rej(false);
+ config->set_pad_shlo(false);
+ if (!pre_shared_key.empty()) {
+ config->set_pre_shared_key(pre_shared_key);
+ }
+ crypto_server_config.config = std::move(config);
+ const QuicData& data = message->GetSerialized();
+
+ crypto_server_config.serialized_crypto_config =
+ QuicString(data.data(), data.length());
+ return crypto_server_config;
+}
+
+} // namespace quic
diff --git a/quic/quartc/quartc_crypto_helpers.h b/quic/quartc/quartc_crypto_helpers.h
new file mode 100644
index 0000000..2b280b5
--- /dev/null
+++ b/quic/quartc/quartc_crypto_helpers.h
@@ -0,0 +1,121 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QUARTC_QUARTC_CRYPTO_HELPERS_H_
+#define QUICHE_QUIC_QUARTC_QUARTC_CRYPTO_HELPERS_H_
+
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h"
+#include "net/third_party/quiche/src/quic/core/crypto/proof_source.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/quic_crypto_server_config.h"
+#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
+#include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h"
+#include "net/third_party/quiche/src/quic/core/quic_versions.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_string.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+
+namespace quic {
+
+// Never, ever, change this certificate name. You will break 0-rtt handshake if
+// you do.
+static constexpr char kDummyCertName[] = "Dummy cert";
+
+struct CryptoServerConfig {
+ std::unique_ptr<QuicCryptoServerConfig> config;
+ QuicString serialized_crypto_config;
+};
+
+// Length of HKDF input keying material, equal to its number of bytes.
+// https://tools.ietf.org/html/rfc5869#section-2.2.
+// TODO(zhihuang): Verify that input keying material length is correct.
+constexpr size_t kInputKeyingMaterialLength = 32;
+
+// Used by QuicCryptoServerConfig to provide dummy proof credentials.
+// TODO(zhihuang): Remove when secure P2P QUIC handshake is possible.
+class DummyProofSource : public ProofSource {
+ public:
+ DummyProofSource() {}
+ ~DummyProofSource() override {}
+
+ // ProofSource overrides.
+ void GetProof(const QuicSocketAddress& server_address,
+ const QuicString& hostname,
+ const QuicString& server_config,
+ QuicTransportVersion transport_version,
+ QuicStringPiece chlo_hash,
+ std::unique_ptr<Callback> callback) override;
+
+ QuicReferenceCountedPointer<Chain> GetCertChain(
+ const QuicSocketAddress& server_address,
+ const QuicString& hostname) override;
+
+ void ComputeTlsSignature(
+ const QuicSocketAddress& server_address,
+ const QuicString& hostname,
+ uint16_t signature_algorithm,
+ QuicStringPiece in,
+ std::unique_ptr<SignatureCallback> callback) override;
+};
+
+// Used by QuicCryptoClientConfig to ignore the peer's credentials
+// and establish an insecure QUIC connection.
+// TODO(zhihuang): Remove when secure P2P QUIC handshake is possible.
+class InsecureProofVerifier : public ProofVerifier {
+ public:
+ InsecureProofVerifier() {}
+ ~InsecureProofVerifier() override {}
+
+ // ProofVerifier overrides.
+ QuicAsyncStatus VerifyProof(
+ const QuicString& hostname,
+ const uint16_t port,
+ const QuicString& server_config,
+ QuicTransportVersion transport_version,
+ QuicStringPiece chlo_hash,
+ const std::vector<QuicString>& certs,
+ const QuicString& cert_sct,
+ const QuicString& signature,
+ const ProofVerifyContext* context,
+ QuicString* error_details,
+ std::unique_ptr<ProofVerifyDetails>* verify_details,
+ std::unique_ptr<ProofVerifierCallback> callback) override;
+
+ QuicAsyncStatus VerifyCertChain(
+ const QuicString& hostname,
+ const std::vector<QuicString>& certs,
+ const ProofVerifyContext* context,
+ QuicString* error_details,
+ std::unique_ptr<ProofVerifyDetails>* details,
+ std::unique_ptr<ProofVerifierCallback> callback) override;
+
+ std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override;
+};
+
+// Implementation of the server-side crypto stream helper.
+class QuartcCryptoServerStreamHelper : public QuicCryptoServerStream::Helper {
+ public:
+ QuicConnectionId GenerateConnectionIdForReject(
+ QuicTransportVersion version,
+ QuicConnectionId connection_id) const override;
+
+ bool CanAcceptClientHello(const CryptoHandshakeMessage& message,
+ const QuicSocketAddress& client_address,
+ const QuicSocketAddress& peer_address,
+ const QuicSocketAddress& self_address,
+ QuicString* error_details) const override;
+};
+
+std::unique_ptr<QuicCryptoClientConfig> CreateCryptoClientConfig(
+ QuicStringPiece pre_shared_key);
+
+CryptoServerConfig CreateCryptoServerConfig(QuicRandom* random,
+ const QuicClock* clock,
+ QuicStringPiece pre_shared_key);
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QUARTC_QUARTC_CRYPTO_HELPERS_H_
diff --git a/quic/quartc/quartc_dispatcher.cc b/quic/quartc/quartc_dispatcher.cc
new file mode 100644
index 0000000..7c398e2
--- /dev/null
+++ b/quic/quartc/quartc_dispatcher.cc
@@ -0,0 +1,79 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/quartc/quartc_dispatcher.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_versions.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/quartc/quartc_factory.h"
+
+namespace quic {
+
+QuartcDispatcher::QuartcDispatcher(
+ std::unique_ptr<QuicConfig> config,
+ std::unique_ptr<QuicCryptoServerConfig> crypto_config,
+ QuicStringPiece crypto_config_serialized,
+ std::unique_ptr<QuicVersionManager> version_manager,
+ std::unique_ptr<QuicConnectionHelperInterface> helper,
+ std::unique_ptr<QuicCryptoServerStream::Helper> session_helper,
+ std::unique_ptr<QuicAlarmFactory> alarm_factory,
+ std::unique_ptr<QuartcPacketWriter> packet_writer,
+ Delegate* delegate)
+ : QuicDispatcher(config.get(),
+ crypto_config.get(),
+ version_manager.get(),
+ std::move(helper),
+ std::move(session_helper),
+ std::move(alarm_factory)),
+ owned_quic_config_(std::move(config)),
+ owned_crypto_config_(std::move(crypto_config)),
+ crypto_config_(crypto_config_serialized),
+ owned_version_manager_(std::move(version_manager)),
+ delegate_(delegate),
+ packet_writer_(packet_writer.get()) {
+ // QuicDispatcher takes ownership of the writer.
+ QuicDispatcher::InitializeWithWriter(packet_writer.release());
+ // NB: This must happen *after* InitializeWithWriter. It can call us back
+ // with OnTransportCanWrite() immediately, and the dispatcher needs to be
+ // fully initialized to handle that.
+ packet_writer_->SetPacketTransportDelegate(this);
+}
+
+QuartcDispatcher::~QuartcDispatcher() {
+ packet_writer_->SetPacketTransportDelegate(nullptr);
+}
+
+QuartcSession* QuartcDispatcher::CreateQuicSession(
+ QuicConnectionId connection_id,
+ const QuicSocketAddress& client_address,
+ QuicStringPiece alpn,
+ const ParsedQuicVersion& version) {
+ std::unique_ptr<QuicConnection> connection = CreateQuicConnection(
+ connection_id, client_address, helper(), alarm_factory(), writer(),
+ Perspective::IS_SERVER, ParsedQuicVersionVector{version});
+ QuartcSession* session = new QuartcServerSession(
+ std::move(connection), /*visitor=*/this, config(), GetSupportedVersions(),
+ helper()->GetClock(), crypto_config(), compressed_certs_cache(),
+ session_helper());
+ delegate_->OnSessionCreated(session);
+ return session;
+}
+
+void QuartcDispatcher::OnTransportCanWrite() {
+ OnCanWrite();
+}
+
+void QuartcDispatcher::OnTransportReceived(const char* data, size_t data_len) {
+ // QuartcPacketTransport does not surface real peer addresses, so the
+ // dispatcher uses a dummy address when processing incoming packets. Note that
+ // the dispatcher refuses to process anything with port 0.
+ static const QuicSocketAddress* dummy_address =
+ new QuicSocketAddress(QuicIpAddress::Any4(), /*port=*/1);
+
+ QuicReceivedPacket packet(data, data_len, helper()->GetClock()->Now());
+ ProcessPacket(/*self_address=*/*dummy_address,
+ /*peer_address=*/*dummy_address, packet);
+}
+
+} // namespace quic
diff --git a/quic/quartc/quartc_dispatcher.h b/quic/quartc/quartc_dispatcher.h
new file mode 100644
index 0000000..6022720
--- /dev/null
+++ b/quic/quartc/quartc_dispatcher.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QUARTC_QUARTC_DISPATCHER_H_
+#define QUICHE_QUIC_QUARTC_QUARTC_DISPATCHER_H_
+
+#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h"
+#include "net/third_party/quiche/src/quic/core/quic_alarm_factory.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_crypto_server_stream.h"
+#include "net/third_party/quiche/src/quic/core/quic_dispatcher.h"
+#include "net/third_party/quiche/src/quic/core/quic_version_manager.h"
+#include "net/third_party/quiche/src/quic/core/quic_versions.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+#include "net/third_party/quiche/src/quic/quartc/quartc_session.h"
+
+namespace quic {
+
+class QuartcDispatcher : public QuicDispatcher,
+ QuartcPacketTransport::Delegate {
+ public:
+ class Delegate {
+ public:
+ virtual ~Delegate() = default;
+ virtual void OnSessionCreated(QuartcSession* session) = 0;
+ };
+
+ QuartcDispatcher(
+ std::unique_ptr<QuicConfig> config,
+ std::unique_ptr<QuicCryptoServerConfig> crypto_config,
+ QuicStringPiece crypto_config_serialized,
+ std::unique_ptr<QuicVersionManager> version_manager,
+ std::unique_ptr<QuicConnectionHelperInterface> helper,
+ std::unique_ptr<QuicCryptoServerStream::Helper> session_helper,
+ std::unique_ptr<QuicAlarmFactory> alarm_factory,
+ std::unique_ptr<QuartcPacketWriter> packet_writer,
+ Delegate* delegate);
+ ~QuartcDispatcher() override;
+
+ QuartcSession* CreateQuicSession(QuicConnectionId connection_id,
+ const QuicSocketAddress& client_address,
+ QuicStringPiece alpn,
+ const ParsedQuicVersion& version) override;
+
+ // QuartcPacketTransport::Delegate overrides.
+ void OnTransportCanWrite() override;
+ void OnTransportReceived(const char* data, size_t data_len) override;
+
+ // A serialized server config in quic wire format.
+ QuicStringPiece server_crypto_config() const { return crypto_config_; }
+
+ private:
+ // Members owned by QuartcDispatcher but not QuicDispatcher.
+ std::unique_ptr<QuicConfig> owned_quic_config_;
+ std::unique_ptr<QuicCryptoServerConfig> owned_crypto_config_;
+ QuicString crypto_config_;
+ std::unique_ptr<QuicVersionManager> owned_version_manager_;
+
+ // Delegate invoked when the dispatcher creates a new session.
+ Delegate* delegate_;
+
+ // The packet writer used by this dispatcher. Owned by the base class, but
+ // the base class upcasts it to QuicPacketWriter (which prevents detaching the
+ // transport delegate without a downcast).
+ QuartcPacketWriter* packet_writer_;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QUARTC_QUARTC_DISPATCHER_H_
diff --git a/quic/quartc/quartc_endpoint.cc b/quic/quartc/quartc_endpoint.cc
new file mode 100644
index 0000000..8d03b0a
--- /dev/null
+++ b/quic/quartc/quartc_endpoint.cc
@@ -0,0 +1,107 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/quartc/quartc_endpoint.h"
+#include "net/third_party/quiche/src/quic/core/quic_version_manager.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/quartc/quartc_connection_helper.h"
+#include "net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h"
+#include "net/third_party/quiche/src/quic/quartc/quartc_dispatcher.h"
+
+namespace quic {
+
+namespace {
+
+// Wrapper around a QuicAlarmFactory which delegates to the wrapped factory.
+// Usee to convert an unowned pointer into an owned pointer, so that the new
+// "owner" does not delete the underlying factory. Note that this is only valid
+// when the unowned pointer is already guaranteed to outlive the new "owner".
+class QuartcAlarmFactoryWrapper : public QuicAlarmFactory {
+ public:
+ explicit QuartcAlarmFactoryWrapper(QuicAlarmFactory* impl) : impl_(impl) {}
+
+ QuicAlarm* CreateAlarm(QuicAlarm::Delegate* delegate) override;
+ QuicArenaScopedPtr<QuicAlarm> CreateAlarm(
+ QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
+ QuicConnectionArena* arena) override;
+
+ private:
+ QuicAlarmFactory* impl_;
+};
+
+QuicAlarm* QuartcAlarmFactoryWrapper::CreateAlarm(
+ QuicAlarm::Delegate* delegate) {
+ return impl_->CreateAlarm(delegate);
+}
+
+QuicArenaScopedPtr<QuicAlarm> QuartcAlarmFactoryWrapper::CreateAlarm(
+ QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
+ QuicConnectionArena* arena) {
+ return impl_->CreateAlarm(std::move(delegate), arena);
+}
+
+QuartcFactoryConfig CreateFactoryConfig(QuicAlarmFactory* alarm_factory,
+ const QuicClock* clock) {
+ QuartcFactoryConfig config;
+ config.alarm_factory = alarm_factory;
+ config.clock = clock;
+ return config;
+}
+
+} // namespace
+
+QuartcClientEndpoint::QuartcClientEndpoint(
+ QuicAlarmFactory* alarm_factory,
+ const QuicClock* clock,
+ QuartcEndpoint::Delegate* delegate,
+ QuicStringPiece serialized_server_config)
+ : alarm_factory_(alarm_factory),
+ clock_(clock),
+ delegate_(delegate),
+ serialized_server_config_(serialized_server_config),
+ create_session_alarm_(QuicWrapUnique(
+ alarm_factory_->CreateAlarm(new CreateSessionDelegate(this)))),
+ factory_(QuicMakeUnique<QuartcFactory>(
+ CreateFactoryConfig(alarm_factory, clock))) {}
+
+void QuartcClientEndpoint::Connect(const QuartcSessionConfig& config) {
+ config_ = config;
+ create_session_alarm_->Set(clock_->Now());
+}
+
+void QuartcClientEndpoint::OnCreateSessionAlarm() {
+ session_ =
+ factory_->CreateQuartcClientSession(config_, serialized_server_config_);
+ delegate_->OnSessionCreated(session_.get());
+}
+
+QuartcServerEndpoint::QuartcServerEndpoint(QuicAlarmFactory* alarm_factory,
+ const QuicClock* clock,
+ QuartcEndpoint::Delegate* delegate)
+ : alarm_factory_(alarm_factory), clock_(clock), delegate_(delegate) {}
+
+void QuartcServerEndpoint::Connect(const QuartcSessionConfig& config) {
+ auto connection_helper = QuicMakeUnique<QuartcConnectionHelper>(clock_);
+ auto crypto_config = CreateCryptoServerConfig(
+ connection_helper->GetRandomGenerator(), clock_, config.pre_shared_key);
+ dispatcher_ = QuicMakeUnique<QuartcDispatcher>(
+ QuicMakeUnique<QuicConfig>(CreateQuicConfig(config)),
+ std::move(crypto_config.config), crypto_config.serialized_crypto_config,
+ QuicMakeUnique<QuicVersionManager>(AllSupportedVersions()),
+ std::move(connection_helper),
+ QuicMakeUnique<QuartcCryptoServerStreamHelper>(),
+ QuicMakeUnique<QuartcAlarmFactoryWrapper>(alarm_factory_),
+ QuicMakeUnique<QuartcPacketWriter>(config.packet_transport,
+ config.max_packet_size),
+ this);
+ // The dispatcher requires at least one call to |ProcessBufferedChlos| to
+ // set the number of connections it is allowed to create.
+ dispatcher_->ProcessBufferedChlos(/*max_connections_to_create=*/1);
+}
+
+void QuartcServerEndpoint::OnSessionCreated(QuartcSession* session) {
+ delegate_->OnSessionCreated(session);
+}
+
+} // namespace quic
diff --git a/quic/quartc/quartc_endpoint.h b/quic/quartc/quartc_endpoint.h
new file mode 100644
index 0000000..108fe12
--- /dev/null
+++ b/quic/quartc/quartc_endpoint.h
@@ -0,0 +1,156 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_QUARTC_QUARTC_ENDPOINT_H_
+#define QUICHE_QUIC_QUARTC_QUARTC_ENDPOINT_H_
+
+#include "net/third_party/quiche/src/quic/core/quic_alarm_factory.h"
+#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_clock.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
+#include "net/third_party/quiche/src/quic/quartc/quartc_dispatcher.h"
+#include "net/third_party/quiche/src/quic/quartc/quartc_factory.h"
+
+namespace quic {
+
+// Private implementation of QuartcEndpoint. Enables different implementations
+// for client and server endpoints.
+class QuartcEndpointImpl {
+ public:
+ virtual ~QuartcEndpointImpl() = default;
+
+ virtual QuicStringPiece server_crypto_config() const = 0;
+};
+
+// Endpoint (client or server) in a peer-to-peer Quartc connection.
+class QuartcEndpoint {
+ public:
+ class Delegate {
+ public:
+ virtual ~Delegate() = default;
+
+ // Called when an endpoint creates a new session, before any packets are
+ // processed or sent. The callee should perform any additional
+ // configuration required, such as setting a session delegate, before
+ // returning. |session| is owned by the endpoint, but remains safe to use
+ // until another call to |OnSessionCreated| occurs, at which point previous
+ // session is destroyed.
+ virtual void OnSessionCreated(QuartcSession* session) = 0;
+
+ // Called if the endpoint fails to establish a session after a call to
+ // Connect. (The most likely cause is a network idle timeout.)
+ virtual void OnConnectError(QuicErrorCode error,
+ const QuicString& error_details) = 0;
+ };
+
+ virtual ~QuartcEndpoint() = default;
+
+ // Connects the endpoint using the given session config. After |Connect| is
+ // called, the endpoint will asynchronously create a session, then call
+ // |Delegate::OnSessionCreated|.
+ virtual void Connect(const QuartcSessionConfig& config) = 0;
+};
+
+// Implementation of QuartcEndpoint which immediately (but asynchronously)
+// creates a session by scheduling a QuicAlarm. Only suitable for use with the
+// client perspective.
+class QuartcClientEndpoint : public QuartcEndpoint {
+ public:
+ // |alarm_factory|, |clock|, and |delegate| are owned by the caller and must
+ // outlive the endpoint.
+ QuartcClientEndpoint(QuicAlarmFactory* alarm_factory,
+ const QuicClock* clock,
+ Delegate* delegate,
+ QuicStringPiece serialized_server_config);
+
+ void Connect(const QuartcSessionConfig& config) override;
+
+ private:
+ friend class CreateSessionDelegate;
+ class CreateSessionDelegate : public QuicAlarm::Delegate {
+ public:
+ CreateSessionDelegate(QuartcClientEndpoint* endpoint)
+ : endpoint_(endpoint) {}
+
+ void OnAlarm() override { endpoint_->OnCreateSessionAlarm(); }
+
+ private:
+ QuartcClientEndpoint* endpoint_;
+ };
+
+ // Callback which occurs when |create_session_alarm_| fires.
+ void OnCreateSessionAlarm();
+
+ // Implementation of QuicAlarmFactory used by this endpoint. Unowned.
+ QuicAlarmFactory* alarm_factory_;
+
+ // Implementation of QuicClock used by this endpoint. Unowned.
+ const QuicClock* clock_;
+
+ // Delegate which receives callbacks for newly created sessions.
+ QuartcEndpoint::Delegate* delegate_;
+
+ // Server config. If valid, used to perform a 0-RTT connection.
+ const QuicString serialized_server_config_;
+
+ // Alarm for creating sessions asynchronously. The alarm is set when
+ // Connect() is called. When it fires, the endpoint creates a session and
+ // calls the delegate.
+ std::unique_ptr<QuicAlarm> create_session_alarm_;
+
+ // QuartcFactory used by this endpoint to create sessions. This is an
+ // implementation detail of the QuartcEndpoint, and will eventually be
+ // replaced by a dispatcher (for servers) or version-negotiation agent (for
+ // clients).
+ std::unique_ptr<QuartcFactory> factory_;
+
+ // Config to be used for new sessions.
+ QuartcSessionConfig config_;
+
+ // The currently-active session. Nullptr until |Connect| and
+ // |Delegate::OnSessionCreated| are called.
+ std::unique_ptr<QuartcSession> session_;
+};
+
+// Implementation of QuartcEndpoint which uses a QuartcDispatcher to listen for
+// an incoming CHLO and create a session when one arrives. Only suitable for
+// use with the server perspective.
+class QuartcServerEndpoint : public QuartcEndpoint,
+ public QuartcDispatcher::Delegate {
+ public:
+ QuartcServerEndpoint(QuicAlarmFactory* alarm_factory,
+ const QuicClock* clock,
+ QuartcEndpoint::Delegate* delegate);
+
+ // Implements QuartcEndpoint.
+ void Connect(const QuartcSessionConfig& config) override;
+
+ // Implements QuartcDispatcher::Delegate.
+ void OnSessionCreated(QuartcSession* session) override;
+
+ // Accessor to retrieve the server crypto config. May only be called after
+ // Connect().
+ QuicStringPiece server_crypto_config() const {
+ return dispatcher_->server_crypto_config();
+ }
+
+ private:
+ // Implementation of QuicAlarmFactory used by this endpoint. Unowned.
+ QuicAlarmFactory* alarm_factory_;
+
+ // Implementation of QuicClock used by this endpoint. Unowned.
+ const QuicClock* clock_;
+
+ // Delegate which receives callbacks for newly created sessions.
+ QuartcEndpoint::Delegate* delegate_;
+
+ // QuartcDispatcher waits for an incoming CHLO, then either rejects it or
+ // creates a session to respond to it. The dispatcher owns all sessions it
+ // creates.
+ std::unique_ptr<QuartcDispatcher> dispatcher_;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_QUARTC_QUARTC_ENDPOINT_H_
diff --git a/quic/quartc/quartc_endpoint_test.cc b/quic/quartc/quartc_endpoint_test.cc
new file mode 100644
index 0000000..59ca847
--- /dev/null
+++ b/quic/quartc/quartc_endpoint_test.cc
@@ -0,0 +1,64 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/quartc/quartc_endpoint.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h"
+
+namespace quic {
+namespace {
+
+static QuicByteCount kDefaultMaxPacketSize = 1200;
+
+class FakeEndpointDelegate : public QuartcEndpoint::Delegate {
+ public:
+ void OnSessionCreated(QuartcSession* session) override {
+ last_session_ = session;
+ }
+
+ void OnConnectError(QuicErrorCode /*error*/,
+ const QuicString& /*error_details*/) override {}
+
+ QuartcSession* last_session() { return last_session_; }
+
+ private:
+ QuartcSession* last_session_ = nullptr;
+};
+
+class QuartcEndpointTest : public QuicTest {
+ protected:
+ QuartcEndpointTest()
+ : transport_(&simulator_,
+ "client_transport",
+ "server_transport",
+ 10 * kDefaultMaxPacketSize) {}
+
+ simulator::Simulator simulator_;
+ simulator::SimulatedQuartcPacketTransport transport_;
+ FakeEndpointDelegate delegate_;
+};
+
+// After calling Connect, the client endpoint must wait for an async callback.
+// The callback occurs after a finite amount of time and produces a session.
+TEST_F(QuartcEndpointTest, ClientCreatesSessionAsynchronously) {
+ QuartcClientEndpoint endpoint_(simulator_.GetAlarmFactory(),
+ simulator_.GetClock(), &delegate_,
+ /*serialized_server_config=*/"");
+ QuartcSessionConfig config;
+ config.packet_transport = &transport_;
+ config.max_packet_size = kDefaultMaxPacketSize;
+ endpoint_.Connect(config);
+
+ EXPECT_EQ(delegate_.last_session(), nullptr);
+
+ EXPECT_TRUE(simulator_.RunUntil(
+ [this] { return delegate_.last_session() != nullptr; }));
+}
+
+} // namespace
+} // namespace quic
diff --git a/quic/quartc/quartc_factory.cc b/quic/quartc/quartc_factory.cc
index ee637e5..336ca14 100644
--- a/quic/quartc/quartc_factory.cc
+++ b/quic/quartc/quartc_factory.cc
@@ -5,40 +5,63 @@
#include "net/third_party/quiche/src/quic/quartc/quartc_factory.h"
#include "net/third_party/quiche/src/quic/core/crypto/quic_random.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_ptr_util.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
+#include "net/third_party/quiche/src/quic/quartc/quartc_connection_helper.h"
+#include "net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h"
#include "net/third_party/quiche/src/quic/quartc/quartc_session.h"
namespace quic {
QuartcFactory::QuartcFactory(const QuartcFactoryConfig& factory_config)
: alarm_factory_(factory_config.alarm_factory),
- clock_(factory_config.clock) {}
+ clock_(factory_config.clock),
+ connection_helper_(QuicMakeUnique<QuartcConnectionHelper>(clock_)),
+ compressed_certs_cache_(QuicMakeUnique<QuicCompressedCertsCache>(
+ QuicCompressedCertsCache::kQuicCompressedCertsCacheSize)),
+ stream_helper_(QuicMakeUnique<QuartcCryptoServerStreamHelper>()) {}
-QuartcFactory::~QuartcFactory() {}
-
-std::unique_ptr<QuartcSession> QuartcFactory::CreateQuartcSession(
- const QuartcSessionConfig& quartc_session_config) {
+std::unique_ptr<QuartcSession> QuartcFactory::CreateQuartcClientSession(
+ const QuartcSessionConfig& quartc_session_config,
+ QuicStringPiece server_crypto_config) {
DCHECK(quartc_session_config.packet_transport);
- Perspective perspective = quartc_session_config.perspective;
-
// QuartcSession will eventually own both |writer| and |quic_connection|.
auto writer =
QuicMakeUnique<QuartcPacketWriter>(quartc_session_config.packet_transport,
quartc_session_config.max_packet_size);
+ // While the QuicConfig is not directly used by the connection, creating it
+ // also sets flag values which must be set before creating the connection.
+ QuicConfig quic_config = CreateQuicConfig(quartc_session_config);
+ std::unique_ptr<QuicConnection> quic_connection =
+ CreateQuicConnection(Perspective::IS_CLIENT, writer.get());
+
+ return QuicMakeUnique<QuartcClientSession>(
+ std::move(quic_connection), quic_config, CurrentSupportedVersions(),
+ clock_, std::move(writer),
+ CreateCryptoClientConfig(quartc_session_config.pre_shared_key),
+ server_crypto_config);
+}
+
+QuicConfig CreateQuicConfig(const QuartcSessionConfig& quartc_session_config) {
+ // TODO(b/124398962): Figure out a better way to initialize QUIC flags.
+ // Creating a config shouldn't have global side-effects on flags. However,
+ // this has the advantage of ensuring that flag values stay in sync with the
+ // options requested by configs, so simply splitting the config and flag
+ // settings doesn't seem preferable.
+
// Fixes behavior of StopReading() with level-triggered stream sequencers.
SetQuicReloadableFlag(quic_stop_reading_when_level_triggered, true);
// Fix b/110259444.
SetQuicReloadableFlag(quic_fix_spurious_ack_alarm, true);
- // Enable version 45+ to enable SendMessage API.
- // Enable version 47+ to enable 'quic bit' per draft 17.
- SetQuicReloadableFlag(quic_enable_version_45, true);
+ // Enable version 46+ to enable SendMessage API and 'quic bit' per draft 17.
SetQuicReloadableFlag(quic_enable_version_46, true);
- SetQuicReloadableFlag(quic_enable_version_47, true);
// Fix for inconsistent reporting of crypto handshake.
SetQuicReloadableFlag(quic_fix_has_pending_crypto_data, true);
@@ -57,9 +80,6 @@
// to implement negotiation outside of QuicConnection.
SetQuicRestartFlag(quic_no_server_conn_ver_negotiation2, false);
- std::unique_ptr<QuicConnection> quic_connection =
- CreateQuicConnection(perspective, writer.get());
-
QuicTagVector copt;
copt.push_back(kNSTP);
@@ -78,22 +98,6 @@
// Enable time-based loss detection.
copt.push_back(kTIME);
- QuicSentPacketManager& sent_packet_manager =
- quic_connection->sent_packet_manager();
-
- // Default delayed ack time is 25ms.
- // If data packets are sent less often (e.g. because p-time was modified),
- // we would force acks to be sent every 25ms regardless, increasing
- // overhead. Since generally we guarantee a packet every 20ms, changing
- // this value should have miniscule effect on quality on good connections,
- // but on poor connections, changing this number significantly reduced the
- // number of ack-only packets.
- // The p-time can go up to as high as 120ms, and when it does, it's
- // when the low overhead is the most important thing. Ideally it should be
- // above 120ms, but it cannot be higher than 0.5*RTO, which equals to 100ms.
- sent_packet_manager.set_delayed_ack_time(
- QuicTime::Delta::FromMilliseconds(100));
-
// Note: flag settings have no effect for Exoblaze builds since
// SetQuicReloadableFlag() gets stubbed out.
SetQuicReloadableFlag(quic_bbr_less_probe_rtt, true); // Enable BBR6,7,8.
@@ -115,15 +119,6 @@
copt.push_back(kNTLP);
}
- quic_connection->set_fill_up_link_during_probing(true);
-
- // We start ack decimation after 15 packets. Typically, we would see
- // 1-2 crypto handshake packets, one media packet, and 10 probing packets.
- // We want to get acks for the probing packets as soon as possible,
- // but we can start using ack decimation right after first probing completes.
- // The default was to not start ack decimation for the first 100 packets.
- quic_connection->set_min_received_before_ack_decimation(15);
-
// TODO(b/112192153): Test and possible enable slower startup when pipe
// filling is ready to use. Slower startup is kBBRS.
@@ -175,42 +170,63 @@
// number of open streams gives sufficient headroom to recover before QUIC
// refuses new streams.
quic_config.SetMaxIncomingDynamicStreamsToSend(1000);
- return QuicMakeUnique<QuartcSession>(
- std::move(quic_connection), quic_config, CurrentSupportedVersions(),
- quartc_session_config.unique_remote_server_id, perspective,
- this /*QuicConnectionHelperInterface*/, clock_, std::move(writer));
+
+ return quic_config;
}
std::unique_ptr<QuicConnection> QuartcFactory::CreateQuicConnection(
Perspective perspective,
QuartcPacketWriter* packet_writer) {
- // dummy_id and dummy_address are used because Quartc network layer will not
- // use these two.
- QuicConnectionId dummy_id;
- if (!QuicConnectionIdSupportsVariableLength(perspective)) {
- dummy_id = QuicConnectionIdFromUInt64(0);
- } else {
+ // |dummy_id| and |dummy_address| are used because Quartc network layer will
+ // not use these two.
char connection_id_bytes[sizeof(uint64_t)] = {};
- dummy_id = QuicConnectionId(static_cast<char*>(connection_id_bytes),
- sizeof(connection_id_bytes));
- }
- QuicSocketAddress dummy_address(QuicIpAddress::Any4(), 0 /*Port*/);
- return QuicMakeUnique<QuicConnection>(
- dummy_id, dummy_address, this, /*QuicConnectionHelperInterface*/
- alarm_factory_ /*QuicAlarmFactory*/, packet_writer, /*owns_writer=*/false,
- perspective, CurrentSupportedVersions());
+ QuicConnectionId dummy_id = QuicConnectionId(
+ static_cast<char*>(connection_id_bytes), sizeof(connection_id_bytes));
+ QuicSocketAddress dummy_address(QuicIpAddress::Any4(), /*port=*/0);
+ return quic::CreateQuicConnection(
+ dummy_id, dummy_address, connection_helper_.get(), alarm_factory_,
+ packet_writer, perspective, CurrentSupportedVersions());
}
-const QuicClock* QuartcFactory::GetClock() const {
- return clock_;
-}
+std::unique_ptr<QuicConnection> CreateQuicConnection(
+ QuicConnectionId connection_id,
+ const QuicSocketAddress& peer_address,
+ QuicConnectionHelperInterface* connection_helper,
+ QuicAlarmFactory* alarm_factory,
+ QuicPacketWriter* packet_writer,
+ Perspective perspective,
+ ParsedQuicVersionVector supported_versions) {
+ auto quic_connection = QuicMakeUnique<QuicConnection>(
+ connection_id, peer_address, connection_helper, alarm_factory,
+ packet_writer,
+ /*owns_writer=*/false, perspective, supported_versions);
-QuicRandom* QuartcFactory::GetRandomGenerator() {
- return QuicRandom::GetInstance();
-}
+ QuicSentPacketManager& sent_packet_manager =
+ quic_connection->sent_packet_manager();
-QuicBufferAllocator* QuartcFactory::GetStreamSendBufferAllocator() {
- return &buffer_allocator_;
+ // Default delayed ack time is 25ms.
+ // If data packets are sent less often (e.g. because p-time was modified),
+ // we would force acks to be sent every 25ms regardless, increasing
+ // overhead. Since generally we guarantee a packet every 20ms, changing
+ // this value should have miniscule effect on quality on good connections,
+ // but on poor connections, changing this number significantly reduced the
+ // number of ack-only packets.
+ // The p-time can go up to as high as 120ms, and when it does, it's
+ // when the low overhead is the most important thing. Ideally it should be
+ // above 120ms, but it cannot be higher than 0.5*RTO, which equals to 100ms.
+ sent_packet_manager.set_delayed_ack_time(
+ QuicTime::Delta::FromMilliseconds(100));
+
+ quic_connection->set_fill_up_link_during_probing(true);
+
+ // We start ack decimation after 15 packets. Typically, we would see
+ // 1-2 crypto handshake packets, one media packet, and 10 probing packets.
+ // We want to get acks for the probing packets as soon as possible,
+ // but we can start using ack decimation right after first probing completes.
+ // The default was to not start ack decimation for the first 100 packets.
+ quic_connection->set_min_received_before_ack_decimation(15);
+
+ return quic_connection;
}
std::unique_ptr<QuartcFactory> CreateQuartcFactory(
diff --git a/quic/quartc/quartc_factory.h b/quic/quartc/quartc_factory.h
index c4ea67f..ec9fd7b 100644
--- a/quic/quartc/quartc_factory.h
+++ b/quic/quartc/quartc_factory.h
@@ -26,20 +26,18 @@
};
struct QuartcSessionConfig {
- // When using Quartc, there are two endpoints. The QuartcSession on one
- // endpoint must act as a server and the one on the other side must act as a
- // client.
- Perspective perspective = Perspective::IS_CLIENT;
- // This is only needed when is_server = false. It must be unique
- // for each endpoint the local endpoint may communicate with. For example,
- // a WebRTC client could use the remote endpoint's crypto fingerprint
- QuicString unique_remote_server_id;
+ // If a pre-shared cryptographic key is available for this session, specify it
+ // here. This value will only be used if non-empty.
+ QuicString pre_shared_key;
+
// The way the QuicConnection will send and receive packets, like a virtual
// UDP socket. For WebRTC, this will typically be an IceTransport.
QuartcPacketTransport* packet_transport = nullptr;
+
// The maximum size of the packet can be written with the packet writer.
// 1200 bytes by default.
QuicPacketLength max_packet_size = 1200;
+
// Timeouts for the crypto handshake. Set them to higher values to
// prevent closing the session before it started on a slow network.
// Zero entries are ignored and QUIC defaults are used in that case.
@@ -57,21 +55,14 @@
// Factory that creates instances of QuartcSession. Implements the
// QuicConnectionHelperInterface used by the QuicConnections. Only one
// QuartcFactory is expected to be created.
-class QUIC_EXPORT_PRIVATE QuartcFactory : public QuicConnectionHelperInterface {
+class QUIC_EXPORT_PRIVATE QuartcFactory {
public:
explicit QuartcFactory(const QuartcFactoryConfig& factory_config);
- ~QuartcFactory() override;
// Creates a new QuartcSession using the given configuration.
- std::unique_ptr<QuartcSession> CreateQuartcSession(
- const QuartcSessionConfig& quartc_session_config);
-
- // QuicConnectionHelperInterface overrides.
- const QuicClock* GetClock() const override;
-
- QuicRandom* GetRandomGenerator() override;
-
- QuicBufferAllocator* GetStreamSendBufferAllocator() override;
+ std::unique_ptr<QuartcSession> CreateQuartcClientSession(
+ const QuartcSessionConfig& quartc_session_config,
+ QuicStringPiece server_crypto_config);
private:
std::unique_ptr<QuicConnection> CreateQuicConnection(
@@ -84,9 +75,28 @@
// Used to implement the QuicConnectionHelperInterface. Owned by the user and
// must outlive QuartcFactory.
const QuicClock* clock_;
- SimpleBufferAllocator buffer_allocator_;
+
+ // Helper used by all QuicConnections.
+ std::unique_ptr<QuicConnectionHelperInterface> connection_helper_;
+
+ // Used by QuicCryptoServerStream to track most recently compressed certs.
+ std::unique_ptr<QuicCompressedCertsCache> compressed_certs_cache_;
+
+ // This helper is needed to create QuicCryptoServerStreams.
+ std::unique_ptr<QuicCryptoServerStream::Helper> stream_helper_;
};
+QuicConfig CreateQuicConfig(const QuartcSessionConfig& quartc_session_config);
+
+std::unique_ptr<QuicConnection> CreateQuicConnection(
+ QuicConnectionId connection_id,
+ const QuicSocketAddress& peer_address,
+ QuicConnectionHelperInterface* connection_helper,
+ QuicAlarmFactory* alarm_factory,
+ QuicPacketWriter* packet_writer,
+ Perspective perspective,
+ ParsedQuicVersionVector supported_versions);
+
// Creates a new instance of QuartcFactory.
std::unique_ptr<QuartcFactory> CreateQuartcFactory(
const QuartcFactoryConfig& factory_config);
diff --git a/quic/quartc/quartc_interval_counter.h b/quic/quartc/quartc_interval_counter.h
index a9b827c..fe3b083 100644
--- a/quic/quartc/quartc_interval_counter.h
+++ b/quic/quartc/quartc_interval_counter.h
@@ -8,8 +8,8 @@
#include <stddef.h>
#include <vector>
-#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_interval.h"
+#include "net/third_party/quiche/src/quic/core/quic_interval.h"
+#include "net/third_party/quiche/src/quic/core/quic_interval_set.h"
namespace quic {
diff --git a/quic/quartc/quartc_interval_counter_test.cc b/quic/quartc/quartc_interval_counter_test.cc
index 9ba14b2..9bc9af5 100644
--- a/quic/quartc/quartc_interval_counter_test.cc
+++ b/quic/quartc/quartc_interval_counter_test.cc
@@ -6,7 +6,7 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_interval.h"
+#include "net/third_party/quiche/src/quic/core/quic_interval.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
namespace quic {
diff --git a/quic/quartc/quartc_packet_writer.cc b/quic/quartc/quartc_packet_writer.cc
index 84a8bcf..64a72a8 100644
--- a/quic/quartc/quartc_packet_writer.cc
+++ b/quic/quartc/quartc_packet_writer.cc
@@ -6,6 +6,10 @@
namespace quic {
+std::unique_ptr<PerPacketOptions> QuartcPerPacketOptions::Clone() const {
+ return QuicMakeUnique<QuartcPerPacketOptions>(*this);
+}
+
QuartcPacketWriter::QuartcPacketWriter(QuartcPacketTransport* packet_transport,
QuicByteCount max_packet_size)
: packet_transport_(packet_transport), max_packet_size_(max_packet_size) {}
@@ -19,10 +23,12 @@
DCHECK(packet_transport_);
QuartcPacketTransport::PacketInfo info;
- if (connection_) {
- info.packet_number = connection_->packet_generator().packet_number();
+ QuartcPerPacketOptions* quartc_options =
+ static_cast<QuartcPerPacketOptions*>(options);
+ if (quartc_options && quartc_options->connection) {
+ info.packet_number =
+ quartc_options->connection->packet_generator().packet_number();
}
-
int bytes_written = packet_transport_->Write(buffer, buf_len, info);
if (bytes_written <= 0) {
writable_ = false;
@@ -31,10 +37,6 @@
return WriteResult(WRITE_STATUS_OK, bytes_written);
}
-bool QuartcPacketWriter::IsWriteBlockedDataBuffered() const {
- return false;
-}
-
bool QuartcPacketWriter::IsWriteBlocked() const {
return !writable_;
}
diff --git a/quic/quartc/quartc_packet_writer.h b/quic/quartc/quartc_packet_writer.h
index 3efb8a8..517d143 100644
--- a/quic/quartc/quartc_packet_writer.h
+++ b/quic/quartc/quartc_packet_writer.h
@@ -51,6 +51,13 @@
virtual void SetDelegate(Delegate* delegate) = 0;
};
+struct QUIC_EXPORT_PRIVATE QuartcPerPacketOptions : public PerPacketOptions {
+ std::unique_ptr<PerPacketOptions> Clone() const override;
+
+ // The connection which is sending this packet.
+ QuicConnection* connection = nullptr;
+};
+
// Implements a QuicPacketWriter using a QuartcPacketTransport, which allows a
// QuicConnection to use (for example), a WebRTC IceTransport.
class QUIC_EXPORT_PRIVATE QuartcPacketWriter : public QuicPacketWriter {
@@ -67,9 +74,6 @@
const QuicSocketAddress& peer_address,
PerPacketOptions* options) override;
- // This is always set to false so that QuicConnection buffers unsent packets.
- bool IsWriteBlockedDataBuffered() const override;
-
// Whether the underneath |transport_| is blocked. If this returns true,
// outgoing QUIC packets are queued by QuicConnection until SetWritable() is
// called.
@@ -93,10 +97,6 @@
WriteResult Flush() override;
- // Sets the connection which sends packets using this writer. Connection must
- // be set in order to attach packet info (eg. packet numbers) to writes.
- void set_connection(QuicConnection* connection) { connection_ = connection; }
-
void SetPacketTransportDelegate(QuartcPacketTransport::Delegate* delegate);
private:
@@ -105,9 +105,6 @@
// The maximum size of the packet can be written by this writer.
QuicByteCount max_packet_size_;
- // The current connection sending packets using this writer.
- QuicConnection* connection_;
-
// Whether packets can be written.
bool writable_ = false;
};
diff --git a/quic/quartc/quartc_session.cc b/quic/quartc/quartc_session.cc
index 37d2cbe..e169e82 100644
--- a/quic/quartc/quartc_session.cc
+++ b/quic/quartc/quartc_session.cc
@@ -7,202 +7,33 @@
#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_mem_slice_storage.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h"
namespace quic {
-
namespace {
// Arbitrary server port number for net::QuicCryptoClientConfig.
const int kQuicServerPort = 0;
-// Length of HKDF input keying material, equal to its number of bytes.
-// https://tools.ietf.org/html/rfc5869#section-2.2.
-// TODO(zhihuang): Verify that input keying material length is correct.
-const size_t kInputKeyingMaterialLength = 32;
-
-// Used by QuicCryptoServerConfig to provide dummy proof credentials.
-// TODO(zhihuang): Remove when secure P2P QUIC handshake is possible.
-class DummyProofSource : public ProofSource {
- public:
- DummyProofSource() {}
- ~DummyProofSource() override {}
-
- // ProofSource override.
- void GetProof(const QuicSocketAddress& server_address,
- const QuicString& hostname,
- const QuicString& server_config,
- QuicTransportVersion transport_version,
- QuicStringPiece chlo_hash,
- std::unique_ptr<Callback> callback) override {
- QuicReferenceCountedPointer<ProofSource::Chain> chain =
- GetCertChain(server_address, hostname);
- QuicCryptoProof proof;
- proof.signature = "Dummy signature";
- proof.leaf_cert_scts = "Dummy timestamp";
- callback->Run(true, chain, proof, nullptr /* details */);
- }
-
- QuicReferenceCountedPointer<Chain> GetCertChain(
- const QuicSocketAddress& server_address,
- const QuicString& hostname) override {
- std::vector<QuicString> certs;
- certs.push_back("Dummy cert");
- return QuicReferenceCountedPointer<ProofSource::Chain>(
- new ProofSource::Chain(certs));
- }
-
- void ComputeTlsSignature(
- const QuicSocketAddress& server_address,
- const QuicString& hostname,
- uint16_t signature_algorithm,
- QuicStringPiece in,
- std::unique_ptr<SignatureCallback> callback) override {
- callback->Run(true, "Dummy signature");
- }
-};
-
-// Used by QuicCryptoClientConfig to ignore the peer's credentials
-// and establish an insecure QUIC connection.
-// TODO(zhihuang): Remove when secure P2P QUIC handshake is possible.
-class InsecureProofVerifier : public ProofVerifier {
- public:
- InsecureProofVerifier() {}
- ~InsecureProofVerifier() override {}
-
- // ProofVerifier override.
- QuicAsyncStatus VerifyProof(
- const QuicString& hostname,
- const uint16_t port,
- const QuicString& server_config,
- QuicTransportVersion transport_version,
- QuicStringPiece chlo_hash,
- const std::vector<QuicString>& certs,
- const QuicString& cert_sct,
- const QuicString& signature,
- const ProofVerifyContext* context,
- QuicString* error_details,
- std::unique_ptr<ProofVerifyDetails>* verify_details,
- std::unique_ptr<ProofVerifierCallback> callback) override {
- return QUIC_SUCCESS;
- }
-
- QuicAsyncStatus VerifyCertChain(
- const QuicString& hostname,
- const std::vector<QuicString>& certs,
- const ProofVerifyContext* context,
- QuicString* error_details,
- std::unique_ptr<ProofVerifyDetails>* details,
- std::unique_ptr<ProofVerifierCallback> callback) override {
- return QUIC_SUCCESS;
- }
-
- std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override {
- return nullptr;
- }
-};
-
} // namespace
-QuicConnectionId QuartcCryptoServerStreamHelper::GenerateConnectionIdForReject(
- QuicTransportVersion version,
- QuicConnectionId connection_id) const {
- return QuicUtils::CreateZeroConnectionId(version);
-}
-
-bool QuartcCryptoServerStreamHelper::CanAcceptClientHello(
- const CryptoHandshakeMessage& message,
- const QuicSocketAddress& client_address,
- const QuicSocketAddress& peer_address,
- const QuicSocketAddress& self_address,
- QuicString* error_details) const {
- return true;
-}
-
QuartcSession::QuartcSession(std::unique_ptr<QuicConnection> connection,
+ Visitor* visitor,
const QuicConfig& config,
const ParsedQuicVersionVector& supported_versions,
- const QuicString& unique_remote_server_id,
- Perspective perspective,
- QuicConnectionHelperInterface* helper,
- const QuicClock* clock,
- std::unique_ptr<QuartcPacketWriter> packet_writer)
- : QuicSession(connection.get(),
- nullptr /*visitor*/,
- config,
- supported_versions),
- unique_remote_server_id_(unique_remote_server_id),
- perspective_(perspective),
- packet_writer_(std::move(packet_writer)),
+ const QuicClock* clock)
+ : QuicSession(connection.get(), visitor, config, supported_versions),
connection_(std::move(connection)),
- helper_(helper),
- clock_(clock) {
- packet_writer_->set_connection(connection_.get());
-
- // Initialization with default crypto configuration.
- if (perspective_ == Perspective::IS_CLIENT) {
- std::unique_ptr<ProofVerifier> proof_verifier(new InsecureProofVerifier);
- quic_crypto_client_config_ = QuicMakeUnique<QuicCryptoClientConfig>(
- std::move(proof_verifier), TlsClientHandshaker::CreateSslCtx());
- quic_crypto_client_config_->set_pad_inchoate_hello(false);
- quic_crypto_client_config_->set_pad_full_hello(false);
- } else {
- std::unique_ptr<ProofSource> proof_source(new DummyProofSource);
- // Generate a random source address token secret. For long-running servers
- // it's better to not regenerate it for each connection to enable zero-RTT
- // handshakes, but for transient clients it does not matter.
- char source_address_token_secret[kInputKeyingMaterialLength];
- helper_->GetRandomGenerator()->RandBytes(source_address_token_secret,
- kInputKeyingMaterialLength);
- quic_crypto_server_config_ = QuicMakeUnique<QuicCryptoServerConfig>(
- QuicString(source_address_token_secret, kInputKeyingMaterialLength),
- helper_->GetRandomGenerator(), std::move(proof_source),
- KeyExchangeSource::Default(), TlsServerHandshaker::CreateSslCtx());
-
- // Effectively disables the anti-amplification measures (we don't need
- // them because we use ICE, and we need to disable them because we disable
- // padding of crypto packets).
- // This multiplier must be large enough so that the crypto handshake packet
- // (approx. 300 bytes) multiplied by this multiplier is larger than a fully
- // sized packet (currently 1200 bytes).
- // 1500 is a bit extreme: if you can imagine sending a 1 byte packet, and
- // your largest MTU would be below 1500 bytes, 1500*1 >=
- // any_packet_that_you_can_imagine_sending.
- // (again, we hardcode packet size to 1200, so we are not dealing with jumbo
- // frames).
- quic_crypto_server_config_->set_chlo_multiplier(1500);
-
- // We are sending small client hello, we must not validate its size.
- quic_crypto_server_config_->set_validate_chlo_size(false);
-
- // We run QUIC over ICE, and ICE is verifying remote side with STUN pings.
- // We disable source address token validation in order to allow for 0-rtt
- // setup (plus source ip addresses are changing even during the connection
- // when ICE is used).
- quic_crypto_server_config_->set_validate_source_address_token(false);
-
- // Provide server with serialized config string to prove ownership.
- QuicCryptoServerConfig::ConfigOptions options;
- // The |message| is used to handle the return value of AddDefaultConfig
- // which is raw pointer of the CryptoHandshakeMessage.
- std::unique_ptr<CryptoHandshakeMessage> message(
- quic_crypto_server_config_->AddDefaultConfig(
- helper_->GetRandomGenerator(), helper_->GetClock(), options));
- quic_crypto_server_config_->set_pad_rej(false);
- quic_crypto_server_config_->set_pad_shlo(false);
- }
+ clock_(clock),
+ per_packet_options_(QuicMakeUnique<QuartcPerPacketOptions>()) {
+ per_packet_options_->connection = connection_.get();
+ connection_->set_per_packet_options(per_packet_options_.get());
}
QuartcSession::~QuartcSession() {}
-const QuicCryptoStream* QuartcSession::GetCryptoStream() const {
- return crypto_stream_.get();
-}
-
-QuicCryptoStream* QuartcSession::GetMutableCryptoStream() {
- return crypto_stream_.get();
-}
-
QuartcStream* QuartcSession::CreateOutgoingBidirectionalStream() {
// Use default priority for incoming QUIC streams.
// TODO(zhihuang): Determine if this value is correct.
@@ -234,7 +65,12 @@
void QuartcSession::ProcessSendMessageQueue() {
while (!send_message_queue_.empty()) {
- MessageResult result = SendMessage(send_message_queue_.front());
+ struct iovec iov = {const_cast<char*>(send_message_queue_.front().data()),
+ send_message_queue_.front().length()};
+ QuicMemSliceStorage storage(
+ &iov, 1, connection()->helper()->GetStreamSendBufferAllocator(),
+ send_message_queue_.front().length());
+ MessageResult result = SendMessage(storage.ToSpan());
const size_t message_size = send_message_queue_.front().size();
@@ -346,45 +182,6 @@
QuicSession::OnConnectionClosed(error, error_details, source);
DCHECK(session_delegate_);
session_delegate_->OnConnectionClosed(error, error_details, source);
-
- // The session may be deleted after OnConnectionClosed(), so |this| must be
- // removed from the packet transport's delegate before it is deleted.
- packet_writer_->SetPacketTransportDelegate(nullptr);
-}
-
-void QuartcSession::SetPreSharedKey(QuicStringPiece key) {
- if (perspective_ == Perspective::IS_CLIENT) {
- quic_crypto_client_config_->set_pre_shared_key(key);
- } else {
- quic_crypto_server_config_->set_pre_shared_key(key);
- }
-}
-
-void QuartcSession::StartCryptoHandshake() {
- if (perspective_ == Perspective::IS_CLIENT) {
- QuicServerId server_id(unique_remote_server_id_, kQuicServerPort,
- /*privacy_mode_enabled=*/false);
- QuicCryptoClientStream* crypto_stream = new QuicCryptoClientStream(
- server_id, this,
- quic_crypto_client_config_->proof_verifier()->CreateDefaultContext(),
- quic_crypto_client_config_.get(), this);
- crypto_stream_.reset(crypto_stream);
- QuicSession::Initialize();
- crypto_stream->CryptoConnect();
- } else {
- quic_compressed_certs_cache_.reset(new QuicCompressedCertsCache(
- QuicCompressedCertsCache::kQuicCompressedCertsCacheSize));
- bool use_stateless_rejects_if_peer_supported = false;
- QuicCryptoServerStream* crypto_stream = new QuicCryptoServerStream(
- quic_crypto_server_config_.get(), quic_compressed_certs_cache_.get(),
- use_stateless_rejects_if_peer_supported, this, &stream_helper_);
- crypto_stream_.reset(crypto_stream);
- QuicSession::Initialize();
- }
-
- // QUIC is ready to process incoming packets after QuicSession::Initialize().
- // Set the packet transport delegate to begin receiving packets.
- packet_writer_->SetPacketTransportDelegate(this);
}
void QuartcSession::CloseConnection(const QuicString& details) {
@@ -418,16 +215,6 @@
session_delegate_->OnMessageReceived(message);
}
-void QuartcSession::OnProofValid(
- const QuicCryptoClientConfig::CachedState& cached) {
- // TODO(zhihuang): Handle the proof verification.
-}
-
-void QuartcSession::OnProofVerifyDetailsAvailable(
- const ProofVerifyDetails& verify_details) {
- // TODO(zhihuang): Handle the proof verification.
-}
-
QuicStream* QuartcSession::CreateIncomingStream(QuicStreamId id) {
return ActivateDataStream(CreateDataStream(id, QuicStream::kDefaultPriority));
}
@@ -440,7 +227,8 @@
std::unique_ptr<QuartcStream> QuartcSession::CreateDataStream(
QuicStreamId id,
spdy::SpdyPriority priority) {
- if (crypto_stream_ == nullptr || !crypto_stream_->encryption_established()) {
+ if (GetCryptoStream() == nullptr ||
+ !GetCryptoStream()->encryption_established()) {
// Encryption not active so no stream created
return nullptr;
}
@@ -481,4 +269,124 @@
return raw;
}
+QuartcClientSession::QuartcClientSession(
+ std::unique_ptr<QuicConnection> connection,
+ const QuicConfig& config,
+ const ParsedQuicVersionVector& supported_versions,
+ const QuicClock* clock,
+ std::unique_ptr<QuartcPacketWriter> packet_writer,
+ std::unique_ptr<QuicCryptoClientConfig> client_crypto_config,
+ QuicStringPiece server_crypto_config)
+ : QuartcSession(std::move(connection),
+ /*visitor=*/nullptr,
+ config,
+ supported_versions,
+ clock),
+ packet_writer_(std::move(packet_writer)),
+ client_crypto_config_(std::move(client_crypto_config)),
+ server_config_(server_crypto_config) {
+ DCHECK_EQ(QuartcSession::connection()->perspective(), Perspective::IS_CLIENT);
+}
+
+QuartcClientSession::~QuartcClientSession() {
+ // The client session is the packet transport delegate, so it must be unset
+ // before the session is deleted.
+ packet_writer_->SetPacketTransportDelegate(nullptr);
+}
+
+void QuartcClientSession::Initialize() {
+ DCHECK(crypto_stream_) << "Do not call QuartcSession::Initialize(), call "
+ "StartCryptoHandshake() instead.";
+ QuartcSession::Initialize();
+
+ // QUIC is ready to process incoming packets after Initialize().
+ // Set the packet transport delegate to begin receiving packets.
+ packet_writer_->SetPacketTransportDelegate(this);
+}
+
+const QuicCryptoStream* QuartcClientSession::GetCryptoStream() const {
+ return crypto_stream_.get();
+}
+
+QuicCryptoStream* QuartcClientSession::GetMutableCryptoStream() {
+ return crypto_stream_.get();
+}
+
+void QuartcClientSession::StartCryptoHandshake() {
+ QuicServerId server_id(/*host=*/"", kQuicServerPort,
+ /*privacy_mode_enabled=*/false);
+
+ if (!server_config_.empty()) {
+ QuicCryptoServerConfig::ConfigOptions options;
+
+ QuicString error;
+ QuicWallTime now = clock()->WallNow();
+ QuicCryptoClientConfig::CachedState::ServerConfigState result =
+ client_crypto_config_->LookupOrCreate(server_id)->SetServerConfig(
+ server_config_, now,
+ /*expiry_time=*/now.Add(QuicTime::Delta::Infinite()), &error);
+
+ if (result == QuicCryptoClientConfig::CachedState::SERVER_CONFIG_VALID) {
+ DCHECK_EQ(error, "");
+ client_crypto_config_->LookupOrCreate(server_id)->SetProof(
+ std::vector<QuicString>{kDummyCertName}, /*cert_sct=*/"",
+ /*chlo_hash=*/"", /*signature=*/"anything");
+ } else {
+ LOG(DFATAL) << "Unable to set server config, error=" << error;
+ }
+ }
+
+ crypto_stream_ = QuicMakeUnique<QuicCryptoClientStream>(
+ server_id, this,
+ client_crypto_config_->proof_verifier()->CreateDefaultContext(),
+ client_crypto_config_.get(), this);
+ Initialize();
+ crypto_stream_->CryptoConnect();
+}
+
+void QuartcClientSession::OnProofValid(
+ const QuicCryptoClientConfig::CachedState& cached) {
+ // TODO(zhihuang): Handle the proof verification.
+}
+
+void QuartcClientSession::OnProofVerifyDetailsAvailable(
+ const ProofVerifyDetails& verify_details) {
+ // TODO(zhihuang): Handle the proof verification.
+}
+
+QuartcServerSession::QuartcServerSession(
+ std::unique_ptr<QuicConnection> connection,
+ Visitor* visitor,
+ const QuicConfig& config,
+ const ParsedQuicVersionVector& supported_versions,
+ const QuicClock* clock,
+ const QuicCryptoServerConfig* server_crypto_config,
+ QuicCompressedCertsCache* const compressed_certs_cache,
+ QuicCryptoServerStream::Helper* const stream_helper)
+ : QuartcSession(std::move(connection),
+ visitor,
+ config,
+ supported_versions,
+ clock),
+ server_crypto_config_(server_crypto_config),
+ compressed_certs_cache_(compressed_certs_cache),
+ stream_helper_(stream_helper) {
+ DCHECK_EQ(QuartcSession::connection()->perspective(), Perspective::IS_SERVER);
+}
+
+const QuicCryptoStream* QuartcServerSession::GetCryptoStream() const {
+ return crypto_stream_.get();
+}
+
+QuicCryptoStream* QuartcServerSession::GetMutableCryptoStream() {
+ return crypto_stream_.get();
+}
+
+void QuartcServerSession::StartCryptoHandshake() {
+ crypto_stream_ = QuicMakeUnique<QuicCryptoServerStream>(
+ server_crypto_config_, compressed_certs_cache_,
+ /*use_stateless_rejects_if_peer_supported=*/false, this, stream_helper_);
+ Initialize();
+}
+
} // namespace quic
diff --git a/quic/quartc/quartc_session.h b/quic/quartc/quartc_session.h
index 411c94c..0c414d8 100644
--- a/quic/quartc/quartc_session.h
+++ b/quic/quartc/quartc_session.h
@@ -20,43 +20,21 @@
namespace quic {
-// A helper class is used by the QuicCryptoServerStream.
-class QuartcCryptoServerStreamHelper : public QuicCryptoServerStream::Helper {
- public:
- QuicConnectionId GenerateConnectionIdForReject(
- QuicTransportVersion version,
- QuicConnectionId connection_id) const override;
-
- bool CanAcceptClientHello(const CryptoHandshakeMessage& message,
- const QuicSocketAddress& client_address,
- const QuicSocketAddress& peer_address,
- const QuicSocketAddress& self_address,
- QuicString* error_details) const override;
-};
-
// QuartcSession owns and manages a QUIC connection.
class QUIC_EXPORT_PRIVATE QuartcSession
: public QuicSession,
- public QuartcPacketTransport::Delegate,
- public QuicCryptoClientStream::ProofHandler {
+ public QuartcPacketTransport::Delegate {
public:
QuartcSession(std::unique_ptr<QuicConnection> connection,
+ Visitor* visitor,
const QuicConfig& config,
const ParsedQuicVersionVector& supported_versions,
- const QuicString& unique_remote_server_id,
- Perspective perspective,
- QuicConnectionHelperInterface* helper,
- const QuicClock* clock,
- std::unique_ptr<QuartcPacketWriter> packet_writer);
+ const QuicClock* clock);
QuartcSession(const QuartcSession&) = delete;
QuartcSession& operator=(const QuartcSession&) = delete;
~QuartcSession() override;
// QuicSession overrides.
- QuicCryptoStream* GetMutableCryptoStream() override;
-
- const QuicCryptoStream* GetCryptoStream() const override;
-
QuartcStream* CreateOutgoingBidirectionalStream();
// Sends short unreliable message using quic message frame (message must fit
@@ -81,7 +59,7 @@
// Return true if transport support message frame.
bool CanSendMessage() const {
- return connection()->transport_version() >= QUIC_VERSION_45;
+ return connection()->transport_version() > QUIC_VERSION_44;
}
void OnCryptoHandshakeEvent(CryptoHandshakeEvent event) override;
@@ -96,12 +74,7 @@
ConnectionCloseSource source) override;
// QuartcSession methods.
-
- // Sets a pre-shared key for use during the crypto handshake. Must be set
- // before StartCryptoHandshake() is called.
- void SetPreSharedKey(QuicStringPiece key);
-
- void StartCryptoHandshake();
+ virtual void StartCryptoHandshake() = 0;
// Closes the connection with the given human-readable error details.
// The connection closes with the QUIC_CONNECTION_CANCELLED error code to
@@ -171,15 +144,6 @@
void OnMessageReceived(QuicStringPiece message) override;
- // ProofHandler overrides.
- void OnProofValid(const QuicCryptoClientConfig::CachedState& cached) override;
-
- // Called by the client crypto handshake when proof verification details
- // become available, either because proof verification is complete, or when
- // cached details are used.
- void OnProofVerifyDetailsAvailable(
- const ProofVerifyDetails& verify_details) override;
-
// Returns number of queued (not sent) messages submitted by
// SendOrQueueMessage. Messages are queued if connection is congestion
// controlled.
@@ -200,6 +164,8 @@
void ResetStream(QuicStreamId stream_id, QuicRstStreamErrorCode error);
+ const QuicClock* clock() { return clock_; }
+
private:
std::unique_ptr<QuartcStream> InitializeDataStream(
std::unique_ptr<QuartcStream> stream,
@@ -207,32 +173,19 @@
void ProcessSendMessageQueue();
- // For crypto handshake.
- std::unique_ptr<QuicCryptoStream> crypto_stream_;
- const QuicString unique_remote_server_id_;
- Perspective perspective_;
-
- // Packet writer used by |connection_|.
- std::unique_ptr<QuartcPacketWriter> packet_writer_;
-
// Take ownership of the QuicConnection. Note: if |connection_| changes,
// the new value of |connection_| must be given to |packet_writer_| before any
// packets are written. Otherwise, |packet_writer_| will crash.
std::unique_ptr<QuicConnection> connection_;
- // Not owned by QuartcSession. From the QuartcFactory.
- QuicConnectionHelperInterface* helper_;
+
// For recording packet receipt time
const QuicClock* clock_;
+
// Not owned by QuartcSession.
Delegate* session_delegate_ = nullptr;
- // Used by QUIC crypto server stream to track most recently compressed certs.
- std::unique_ptr<QuicCompressedCertsCache> quic_compressed_certs_cache_;
- // This helper is needed when create QuicCryptoServerStream.
- QuartcCryptoServerStreamHelper stream_helper_;
- // Config for QUIC crypto client stream, used by the client.
- std::unique_ptr<QuicCryptoClientConfig> quic_crypto_client_config_;
- // Config for QUIC crypto server stream, used by the server.
- std::unique_ptr<QuicCryptoServerConfig> quic_crypto_server_config_;
+
+ // Options passed to the packet writer for each packet.
+ std::unique_ptr<QuartcPerPacketOptions> per_packet_options_;
// Queue of pending messages sent by SendQuartcMessage that were not sent
// yet or blocked by congestion control. Messages are queued in the order
@@ -240,6 +193,94 @@
QuicDeque<QuicString> send_message_queue_;
};
+class QUIC_EXPORT_PRIVATE QuartcClientSession
+ : public QuartcSession,
+ public QuicCryptoClientStream::ProofHandler {
+ public:
+ QuartcClientSession(
+ std::unique_ptr<QuicConnection> connection,
+ const QuicConfig& config,
+ const ParsedQuicVersionVector& supported_versions,
+ const QuicClock* clock,
+ std::unique_ptr<QuartcPacketWriter> packet_writer,
+ std::unique_ptr<QuicCryptoClientConfig> client_crypto_config,
+ QuicStringPiece server_crypto_config);
+ QuartcClientSession(const QuartcClientSession&) = delete;
+ QuartcClientSession& operator=(const QuartcClientSession&) = delete;
+
+ ~QuartcClientSession() override;
+
+ // Initialize should not be called on a QuartcSession. Instead, call
+ // StartCryptoHandshake().
+ // TODO(mellem): Move creation of the crypto stream into Initialize() and
+ // remove StartCryptoHandshake() to bring QuartcSession in line with other
+ // implementations of QuicSession, which can be started by calling
+ // Initialize().
+ void Initialize() override;
+
+ // Accessors for the client crypto stream.
+ QuicCryptoStream* GetMutableCryptoStream() override;
+ const QuicCryptoStream* GetCryptoStream() const override;
+
+ // Initializes the session and sends a handshake.
+ void StartCryptoHandshake() override;
+
+ // ProofHandler overrides.
+ void OnProofValid(const QuicCryptoClientConfig::CachedState& cached) override;
+
+ // Called by the client crypto handshake when proof verification details
+ // become available, either because proof verification is complete, or when
+ // cached details are used.
+ void OnProofVerifyDetailsAvailable(
+ const ProofVerifyDetails& verify_details) override;
+
+ private:
+ // Packet writer used by |connection_|.
+ std::unique_ptr<QuartcPacketWriter> packet_writer_;
+
+ // Config for QUIC crypto stream.
+ std::unique_ptr<QuicCryptoClientConfig> client_crypto_config_;
+
+ // Client perspective crypto stream.
+ std::unique_ptr<QuicCryptoClientStream> crypto_stream_;
+
+ const QuicString server_config_;
+};
+
+class QUIC_EXPORT_PRIVATE QuartcServerSession : public QuartcSession {
+ public:
+ QuartcServerSession(std::unique_ptr<QuicConnection> connection,
+ Visitor* visitor,
+ const QuicConfig& config,
+ const ParsedQuicVersionVector& supported_versions,
+ const QuicClock* clock,
+ const QuicCryptoServerConfig* server_crypto_config,
+ QuicCompressedCertsCache* const compressed_certs_cache,
+ QuicCryptoServerStream::Helper* const stream_helper);
+ QuartcServerSession(const QuartcServerSession&) = delete;
+ QuartcServerSession& operator=(const QuartcServerSession&) = delete;
+
+ // Accessors for the server crypto stream.
+ QuicCryptoStream* GetMutableCryptoStream() override;
+ const QuicCryptoStream* GetCryptoStream() const override;
+
+ // Initializes the session and prepares to receive a handshake.
+ void StartCryptoHandshake() override;
+
+ private:
+ // Config for QUIC crypto stream.
+ const QuicCryptoServerConfig* server_crypto_config_;
+
+ // Used by QUIC crypto server stream to track most recently compressed certs.
+ QuicCompressedCertsCache* const compressed_certs_cache_;
+
+ // This helper is needed to create QuicCryptoServerStream.
+ QuicCryptoServerStream::Helper* const stream_helper_;
+
+ // Server perspective crypto stream.
+ std::unique_ptr<QuicCryptoServerStream> crypto_stream_;
+};
+
} // namespace quic
#endif // QUICHE_QUIC_QUARTC_QUARTC_SESSION_H_
diff --git a/quic/quartc/quartc_session_test.cc b/quic/quartc/quartc_session_test.cc
index 78efa9e..0ca9a58 100644
--- a/quic/quartc/quartc_session_test.cc
+++ b/quic/quartc/quartc_session_test.cc
@@ -16,7 +16,7 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test_mem_slice_vector.h"
#include "net/third_party/quiche/src/quic/quartc/counting_packet_filter.h"
-#include "net/third_party/quiche/src/quic/quartc/quartc_factory.h"
+#include "net/third_party/quiche/src/quic/quartc/quartc_endpoint.h"
#include "net/third_party/quiche/src/quic/quartc/quartc_packet_writer.h"
#include "net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h"
#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h"
@@ -27,8 +27,40 @@
namespace {
+constexpr QuicTime::Delta kPropagationDelay =
+ QuicTime::Delta::FromMilliseconds(10);
+// Propagation delay and a bit, but no more than full RTT.
+constexpr QuicTime::Delta kPropagationDelayAndABit =
+ QuicTime::Delta::FromMilliseconds(12);
+
static QuicByteCount kDefaultMaxPacketSize = 1200;
+class FakeQuartcEndpointDelegate : public QuartcEndpoint::Delegate {
+ public:
+ explicit FakeQuartcEndpointDelegate(QuartcSession::Delegate* session_delegate)
+ : session_delegate_(session_delegate) {}
+
+ void OnSessionCreated(QuartcSession* session) override {
+ CHECK_EQ(session_, nullptr);
+ CHECK_NE(session, nullptr);
+ session_ = session;
+ session_->SetDelegate(session_delegate_);
+ session_->StartCryptoHandshake();
+ }
+
+ void OnConnectError(QuicErrorCode error,
+ const QuicString& error_details) override {
+ LOG(FATAL) << "Unexpected error during QuartcEndpoint::Connect(); error="
+ << error << ", error_details=" << error_details;
+ }
+
+ QuartcSession* session() { return session_; }
+
+ private:
+ QuartcSession::Delegate* session_delegate_;
+ QuartcSession* session_ = nullptr;
+};
+
class FakeQuartcSessionDelegate : public QuartcSession::Delegate {
public:
explicit FakeQuartcSessionDelegate(QuartcStream::Delegate* stream_delegate,
@@ -140,49 +172,61 @@
client_server_link_ = QuicMakeUnique<simulator::SymmetricLink>(
client_filter_.get(), server_transport_.get(),
- QuicBandwidth::FromKBitsPerSecond(10 * 1000),
- QuicTime::Delta::FromMilliseconds(10));
+ QuicBandwidth::FromKBitsPerSecond(10 * 1000), kPropagationDelay);
client_stream_delegate_ = QuicMakeUnique<FakeQuartcStreamDelegate>();
client_session_delegate_ = QuicMakeUnique<FakeQuartcSessionDelegate>(
client_stream_delegate_.get(), simulator_.GetClock());
+ client_endpoint_delegate_ = QuicMakeUnique<FakeQuartcEndpointDelegate>(
+ client_session_delegate_.get());
server_stream_delegate_ = QuicMakeUnique<FakeQuartcStreamDelegate>();
server_session_delegate_ = QuicMakeUnique<FakeQuartcSessionDelegate>(
server_stream_delegate_.get(), simulator_.GetClock());
+ server_endpoint_delegate_ = QuicMakeUnique<FakeQuartcEndpointDelegate>(
+ server_session_delegate_.get());
- QuartcFactoryConfig factory_config;
- factory_config.alarm_factory = simulator_.GetAlarmFactory();
- factory_config.clock = simulator_.GetClock();
- quartc_factory_ = QuicMakeUnique<QuartcFactory>(factory_config);
+ client_endpoint_ = QuicMakeUnique<QuartcClientEndpoint>(
+ simulator_.GetAlarmFactory(), simulator_.GetClock(),
+ client_endpoint_delegate_.get(), /*serialized_server_config=*/"");
+ server_endpoint_ = QuicMakeUnique<QuartcServerEndpoint>(
+ simulator_.GetAlarmFactory(), simulator_.GetClock(),
+ server_endpoint_delegate_.get());
}
// Note that input session config will apply to both server and client.
// Perspective and packet_transport will be overwritten.
- void CreateClientAndServerSessions(
- const QuartcSessionConfig& session_config) {
- Init();
-
- QuartcSessionConfig client_session_config = session_config;
- client_session_config.perspective = Perspective::IS_CLIENT;
- client_session_config.packet_transport = client_transport_.get();
- client_peer_ = quartc_factory_->CreateQuartcSession(client_session_config);
- client_peer_->SetDelegate(client_session_delegate_.get());
+ void CreateClientAndServerSessions(const QuartcSessionConfig& session_config,
+ bool init = true) {
+ if (init) {
+ Init();
+ }
QuartcSessionConfig server_session_config = session_config;
- server_session_config.perspective = Perspective::IS_SERVER;
server_session_config.packet_transport = server_transport_.get();
- server_peer_ = quartc_factory_->CreateQuartcSession(server_session_config);
- server_peer_->SetDelegate(server_session_delegate_.get());
+ server_endpoint_->Connect(server_session_config);
+
+ QuartcSessionConfig client_session_config = session_config;
+ client_session_config.packet_transport = client_transport_.get();
+ client_endpoint_->Connect(client_session_config);
+
+ CHECK(simulator_.RunUntil([this] {
+ return client_endpoint_delegate_->session() != nullptr &&
+ server_endpoint_delegate_->session() != nullptr;
+ }));
+
+ client_peer_ = client_endpoint_delegate_->session();
+ server_peer_ = server_endpoint_delegate_->session();
}
// Runs all tasks scheduled in the next 200 ms.
void RunTasks() { simulator_.RunFor(QuicTime::Delta::FromMilliseconds(200)); }
- void StartHandshake() {
- server_peer_->StartCryptoHandshake();
- client_peer_->StartCryptoHandshake();
- RunTasks();
+ void AwaitHandshake() {
+ simulator_.RunUntil([this] {
+ return client_peer_->IsCryptoHandshakeConfirmed() &&
+ server_peer_->IsCryptoHandshakeConfirmed();
+ });
}
// Test handshake establishment and sending/receiving of data for two
@@ -270,7 +314,7 @@
ASSERT_TRUE(client_peer_->CanSendMessage());
QuartcSession* const peer_sending =
- direction_from_server ? server_peer_.get() : client_peer_.get();
+ direction_from_server ? server_peer_ : client_peer_;
FakeQuartcSessionDelegate* const delegate_receiving =
direction_from_server ? client_session_delegate_.get()
@@ -334,51 +378,54 @@
protected:
simulator::Simulator simulator_;
- std::unique_ptr<QuartcFactory> quartc_factory_;
-
std::unique_ptr<simulator::SimulatedQuartcPacketTransport> client_transport_;
std::unique_ptr<simulator::SimulatedQuartcPacketTransport> server_transport_;
std::unique_ptr<simulator::CountingPacketFilter> client_filter_;
std::unique_ptr<simulator::SymmetricLink> client_server_link_;
- std::unique_ptr<QuartcSession> client_peer_;
- std::unique_ptr<QuartcSession> server_peer_;
-
std::unique_ptr<FakeQuartcStreamDelegate> client_stream_delegate_;
std::unique_ptr<FakeQuartcSessionDelegate> client_session_delegate_;
+ std::unique_ptr<FakeQuartcEndpointDelegate> client_endpoint_delegate_;
std::unique_ptr<FakeQuartcStreamDelegate> server_stream_delegate_;
std::unique_ptr<FakeQuartcSessionDelegate> server_session_delegate_;
+ std::unique_ptr<FakeQuartcEndpointDelegate> server_endpoint_delegate_;
+
+ std::unique_ptr<QuartcClientEndpoint> client_endpoint_;
+ std::unique_ptr<QuartcServerEndpoint> server_endpoint_;
+
+ QuartcSession* client_peer_ = nullptr;
+ QuartcSession* server_peer_ = nullptr;
};
TEST_F(QuartcSessionTest, SendReceiveStreams) {
CreateClientAndServerSessions(QuartcSessionConfig());
- StartHandshake();
+ AwaitHandshake();
TestSendReceiveStreams();
}
TEST_F(QuartcSessionTest, SendReceiveMessages) {
CreateClientAndServerSessions(QuartcSessionConfig());
- StartHandshake();
+ AwaitHandshake();
TestSendReceiveMessage();
}
TEST_F(QuartcSessionTest, SendReceiveQueuedMessages) {
CreateClientAndServerSessions(QuartcSessionConfig());
- StartHandshake();
+ AwaitHandshake();
TestSendReceiveQueuedMessages(/*direction_from_server=*/true);
TestSendReceiveQueuedMessages(/*direction_from_server=*/false);
}
TEST_F(QuartcSessionTest, SendMessageFails) {
CreateClientAndServerSessions(QuartcSessionConfig());
- StartHandshake();
+ AwaitHandshake();
TestSendLongMessage();
}
TEST_F(QuartcSessionTest, TestCryptoHandshakeCanWriteTriggers) {
CreateClientAndServerSessions(QuartcSessionConfig());
- StartHandshake();
+ AwaitHandshake();
RunTasks();
@@ -399,10 +446,10 @@
}
TEST_F(QuartcSessionTest, PreSharedKeyHandshake) {
- CreateClientAndServerSessions(QuartcSessionConfig());
- client_peer_->SetPreSharedKey("foo");
- server_peer_->SetPreSharedKey("foo");
- StartHandshake();
+ QuartcSessionConfig config;
+ config.pre_shared_key = "foo";
+ CreateClientAndServerSessions(config);
+ AwaitHandshake();
TestSendReceiveStreams();
TestSendReceiveMessage();
}
@@ -416,7 +463,7 @@
TEST_F(QuartcSessionTest, CancelQuartcStream) {
CreateClientAndServerSessions(QuartcSessionConfig());
- StartHandshake();
+ AwaitHandshake();
ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed());
ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed());
@@ -438,7 +485,7 @@
// SimulatedQuartcPacketTransport::last_packet_number().
TEST_F(QuartcSessionTest, WriterGivesPacketNumberToTransport) {
CreateClientAndServerSessions(QuartcSessionConfig());
- StartHandshake();
+ AwaitHandshake();
ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed());
ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed());
@@ -459,7 +506,7 @@
TEST_F(QuartcSessionTest, CloseConnection) {
CreateClientAndServerSessions(QuartcSessionConfig());
- StartHandshake();
+ AwaitHandshake();
ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed());
ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed());
@@ -471,7 +518,7 @@
TEST_F(QuartcSessionTest, StreamRetransmissionEnabled) {
CreateClientAndServerSessions(QuartcSessionConfig());
- StartHandshake();
+ AwaitHandshake();
ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed());
ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed());
@@ -504,10 +551,15 @@
// message will be retransmitted to to probe for more bandwidth.
client_peer_->connection()->set_fill_up_link_during_probing(false);
- StartHandshake();
+ AwaitHandshake();
ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed());
ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed());
+ // The client sends an ACK for the crypto handshake next. This must be
+ // flushed before we set the filter to drop the next packet, in order to
+ // ensure that the filter drops a data-bearing packet instead of just an ack.
+ RunTasks();
+
QuartcStream* stream = client_peer_->CreateOutgoingBidirectionalStream();
QuicStreamId stream_id = stream->id();
stream->SetDelegate(client_stream_delegate_.get());
@@ -543,6 +595,85 @@
QUIC_STREAM_CANCELLED);
}
+TEST_F(QuartcSessionTest, ServerRegistersAsWriteBlocked) {
+ // Initialize client and server session, but with the server write-blocked.
+ Init();
+ server_transport_->SetWritable(false);
+ CreateClientAndServerSessions(QuartcSessionConfig(), /*init=*/false);
+
+ // Let the client send a few copies of the CHLO. The server can't respond, as
+ // it's still write-blocked.
+ RunTasks();
+
+ // Making the server's transport writable should trigger a callback that
+ // reaches the server session, allowing it to write packets.
+ server_transport_->SetWritable(true);
+
+ // Now the server should respond with the SHLO, encryption should be
+ // established, and data should flow normally.
+ // Note that if the server is *not* correctly registered as write-blocked,
+ // it will crash here (see b/124527328 for details).
+ AwaitHandshake();
+ TestSendReceiveStreams();
+}
+
+TEST_F(QuartcSessionTest, PreSharedKeyHandshakeIs0RTT) {
+ QuartcSessionConfig session_config;
+ session_config.pre_shared_key = "foo";
+
+ Init();
+
+ QuartcSessionConfig server_session_config = session_config;
+ server_session_config.packet_transport = server_transport_.get();
+ server_endpoint_->Connect(server_session_config);
+
+ client_endpoint_ = absl::make_unique<QuartcClientEndpoint>(
+ simulator_.GetAlarmFactory(), simulator_.GetClock(),
+ client_endpoint_delegate_.get(),
+ // This is the key line here. It passes through the server config
+ // from the server to the client.
+ server_endpoint_->server_crypto_config());
+
+ QuartcSessionConfig client_session_config = session_config;
+ QuicString();
+ client_session_config.packet_transport = client_transport_.get();
+ client_endpoint_->Connect(client_session_config);
+
+ // Running for 1ms. This is shorter than the RTT, so the
+ // client session should be created, but server won't be created yet.
+ simulator_.RunFor(QuicTime::Delta::FromMilliseconds(1));
+
+ client_peer_ = client_endpoint_delegate_->session();
+ server_peer_ = server_endpoint_delegate_->session();
+
+ ASSERT_NE(client_peer_, nullptr);
+ ASSERT_EQ(server_peer_, nullptr);
+
+ // Write data to the client before running tasks. This should be sent by the
+ // client and received by the server if the handshake is 0RTT.
+ // If this test fails, add 'RunTasks()' above, and see what error is sent
+ // by the server in the rejection message.
+ QuartcStream* stream = client_peer_->CreateOutgoingBidirectionalStream();
+ ASSERT_NE(stream, nullptr);
+ QuicStreamId stream_id = stream->id();
+ stream->SetDelegate(client_stream_delegate_.get());
+
+ char message[] = "Hello in 0RTTs!";
+ test::QuicTestMemSliceVector data({std::make_pair(message, strlen(message))});
+ stream->WriteMemSlices(data.span(), /*fin=*/false);
+
+ // This will now run the rest of the connection. But the
+ // Server peer will receive the CHLO and message after 1 delay.
+ simulator_.RunFor(kPropagationDelayAndABit);
+
+ // If we can decrypt the data, it means that 0 rtt was successful.
+ // This is because we waited only a propagation delay. So if the decryption
+ // failed, we would send sREJ instead of SHLO, but it wouldn't be delivered to
+ // the client yet.
+ ASSERT_TRUE(server_stream_delegate_->has_data());
+ EXPECT_EQ(server_stream_delegate_->data()[stream_id], message);
+}
+
} // namespace
} // namespace quic
diff --git a/quic/quartc/quartc_stream.cc b/quic/quartc/quartc_stream.cc
index a0be2c7..49ade23 100644
--- a/quic/quartc/quartc_stream.cc
+++ b/quic/quartc/quartc_stream.cc
@@ -76,14 +76,15 @@
bool QuartcStream::OnStreamFrameAcked(QuicStreamOffset offset,
QuicByteCount data_length,
bool fin_acked,
- QuicTime::Delta ack_delay_time) {
+ QuicTime::Delta ack_delay_time,
+ QuicByteCount* newly_acked_length) {
// Previous losses of acked data are no longer relevant to the retransmission
// count. Once data is acked, it will never be retransmitted.
lost_frame_counter_.RemoveInterval(
QuicInterval<QuicStreamOffset>(offset, offset + data_length));
return QuicStream::OnStreamFrameAcked(offset, data_length, fin_acked,
- ack_delay_time);
+ ack_delay_time, newly_acked_length);
}
void QuartcStream::OnStreamFrameRetransmitted(QuicStreamOffset offset,
diff --git a/quic/quartc/quartc_stream.h b/quic/quartc/quartc_stream.h
index d34c2c2..e30afbf 100644
--- a/quic/quartc/quartc_stream.h
+++ b/quic/quartc/quartc_stream.h
@@ -47,7 +47,8 @@
bool OnStreamFrameAcked(QuicStreamOffset offset,
QuicByteCount data_length,
bool fin_acked,
- QuicTime::Delta ack_delay_time) override;
+ QuicTime::Delta ack_delay_time,
+ QuicByteCount* newly_acked_length) override;
void OnStreamFrameRetransmitted(QuicStreamOffset offset,
QuicByteCount data_length,
diff --git a/quic/quartc/quartc_stream_test.cc b/quic/quartc/quartc_stream_test.cc
index 075aca1..87e6170 100644
--- a/quic/quartc/quartc_stream_test.cc
+++ b/quic/quartc/quartc_stream_test.cc
@@ -138,9 +138,7 @@
return WriteResult(WRITE_STATUS_ERROR, 0);
}
- bool IsWriteBlockedDataBuffered() const override { return false; }
-
- bool IsWriteBlocked() const override { return false; };
+ bool IsWriteBlocked() const override { return false; }
void SetWritable() override {}
@@ -563,8 +561,10 @@
// Ack bytes [0, 7). These bytes should be pruned from the data tracked by
// the stream.
- stream_->OnStreamFrameAcked(0, 7, false,
- QuicTime::Delta::FromMilliseconds(1));
+ QuicByteCount newly_acked_length = 0;
+ stream_->OnStreamFrameAcked(0, 7, false, QuicTime::Delta::FromMilliseconds(1),
+ &newly_acked_length);
+ EXPECT_EQ(7u, newly_acked_length);
stream_->OnCanWrite();
EXPECT_EQ("Foo barFoo bar", write_buffer_);
diff --git a/quic/quartc/simulated_packet_transport.cc b/quic/quartc/simulated_packet_transport.cc
index 66bfb2b..5c0d374 100644
--- a/quic/quartc/simulated_packet_transport.cc
+++ b/quic/quartc/simulated_packet_transport.cc
@@ -24,6 +24,9 @@
int SimulatedQuartcPacketTransport::Write(const char* buffer,
size_t buf_len,
const PacketInfo& info) {
+ if (!writable_) {
+ return 0;
+ }
if (egress_queue_.bytes_queued() + buf_len > egress_queue_.capacity()) {
return 0;
}
@@ -69,16 +72,24 @@
}
void SimulatedQuartcPacketTransport::OnPacketDequeued() {
- if (delegate_) {
+ if (delegate_ && writable_) {
delegate_->OnTransportCanWrite();
}
}
void SimulatedQuartcPacketTransport::Act() {
- if (delegate_) {
+ if (delegate_ && writable_) {
delegate_->OnTransportCanWrite();
}
}
+void SimulatedQuartcPacketTransport::SetWritable(bool writable) {
+ writable_ = writable;
+ if (writable_) {
+ // May need to call |Delegate::OnTransportCanWrite|.
+ Schedule(clock_->Now());
+ }
+}
+
} // namespace simulator
} // namespace quic
diff --git a/quic/quartc/simulated_packet_transport.h b/quic/quartc/simulated_packet_transport.h
index 5f1c468..1b190a0 100644
--- a/quic/quartc/simulated_packet_transport.h
+++ b/quic/quartc/simulated_packet_transport.h
@@ -53,6 +53,13 @@
// callback to unblock it.)
void Act() override;
+ // Changes whether the transport is writable. If |writable| is false, the
+ // transport will reject calls to |Write| and will not call
+ // |Delegate::OnTransportCanWrite|. If |writable| is true, the transport will
+ // allow calls to |Write| and will call |Delegate::OnTransportCanWrite|
+ // whenever it is able to write another packet.
+ void SetWritable(bool writable);
+
// Last packet number sent over this simulated transport.
// TODO(b/112561077): Reorganize tests so that this method can be deleted.
// This exists purely for use by quartc_session_test.cc, to test that the
@@ -64,6 +71,10 @@
Delegate* delegate_ = nullptr;
Queue egress_queue_;
QuicPacketNumber last_packet_number_;
+
+ // Controls whether the transport is considered to be writable. Used to
+ // simulate behavior that arises when the transport is blocked.
+ bool writable_ = true;
};
} // namespace simulator
diff --git a/quic/test_tools/crypto_test_utils.cc b/quic/test_tools/crypto_test_utils.cc
index fd270c3..e36ba52 100644
--- a/quic/test_tools/crypto_test_utils.cc
+++ b/quic/test_tools/crypto_test_utils.cc
@@ -5,6 +5,7 @@
#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
#include <memory>
+#include <string>
#include "third_party/boringssl/src/include/openssl/bn.h"
#include "third_party/boringssl/src/include/openssl/ec.h"
@@ -507,11 +508,19 @@
const CryptoHandshakeMessage& message,
Perspective perspective) {
const QuicData& data = message.GetSerialized();
- QuicStreamFrame frame(
- QuicUtils::GetCryptoStreamId(
- QuicStreamPeer::session(stream)->connection()->transport_version()),
- false, stream->stream_bytes_read(), data.AsStringPiece());
- stream->OnStreamFrame(frame);
+ QuicSession* session = QuicStreamPeer::session(stream);
+ if (session->connection()->transport_version() < QUIC_VERSION_47) {
+ QuicStreamFrame frame(QuicUtils::GetCryptoStreamId(
+ session->connection()->transport_version()),
+ false, stream->crypto_bytes_read(),
+ data.AsStringPiece());
+ stream->OnStreamFrame(frame);
+ } else {
+ EncryptionLevel level = session->connection()->last_decrypted_level();
+ QuicCryptoFrame frame(level, stream->BytesReadOnLevel(level),
+ data.AsStringPiece());
+ stream->OnCryptoFrame(frame);
+ }
}
void CommunicateHandshakeMessages(PacketSavingConnection* client_conn,
@@ -589,7 +598,7 @@
uint64_t LeafCertHashForTesting() {
QuicReferenceCountedPointer<ProofSource::Chain> chain;
- QuicSocketAddress server_address;
+ QuicSocketAddress server_address(QuicIpAddress::Any4(), 42);
QuicCryptoProof proof;
std::unique_ptr<ProofSource> proof_source(ProofSourceForTesting());
@@ -724,7 +733,7 @@
QuicFramer* server_framer = QuicConnectionPeer::GetFramer(
QuicStreamPeer::session(server)->connection());
const QuicEncrypter* client_encrypter(
- QuicFramerPeer::GetEncrypter(client_framer, ENCRYPTION_INITIAL));
+ QuicFramerPeer::GetEncrypter(client_framer, ENCRYPTION_ZERO_RTT));
const QuicDecrypter* client_decrypter(
QuicStreamPeer::session(client)->connection()->decrypter());
const QuicEncrypter* client_forward_secure_encrypter(
@@ -732,7 +741,7 @@
const QuicDecrypter* client_forward_secure_decrypter(
QuicStreamPeer::session(client)->connection()->alternative_decrypter());
const QuicEncrypter* server_encrypter(
- QuicFramerPeer::GetEncrypter(server_framer, ENCRYPTION_INITIAL));
+ QuicFramerPeer::GetEncrypter(server_framer, ENCRYPTION_ZERO_RTT));
const QuicDecrypter* server_decrypter(
QuicStreamPeer::session(server)->connection()->decrypter());
const QuicEncrypter* server_forward_secure_encrypter(
@@ -936,6 +945,7 @@
break;
}
QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer());
+ dest_conn->OnDecryptedPacket(framer.last_decrypted_level());
if (dest_stream->handshake_protocol() == PROTOCOL_TLS1_3) {
// Try to process the packet with a framer that only has the NullDecrypter
@@ -961,6 +971,9 @@
for (const auto& stream_frame : framer.stream_frames()) {
dest_stream->OnStreamFrame(*stream_frame);
}
+ for (const auto& crypto_frame : framer.crypto_frames()) {
+ dest_stream->OnCryptoFrame(*crypto_frame);
+ }
}
*inout_packet_index = index;
diff --git a/quic/test_tools/crypto_test_utils_test.cc b/quic/test_tools/crypto_test_utils_test.cc
index 601103c..39a3b23 100644
--- a/quic/test_tools/crypto_test_utils_test.cc
+++ b/quic/test_tools/crypto_test_utils_test.cc
@@ -113,7 +113,7 @@
QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(),
crypto_test_utils::ProofSourceForTesting(), KeyExchangeSource::Default(),
TlsServerHandshaker::CreateSslCtx());
- QuicSocketAddress server_addr;
+ QuicSocketAddress server_addr(QuicIpAddress::Any4(), 5);
QuicSocketAddress client_addr(QuicIpAddress::Loopback4(), 1);
QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config(
new QuicSignedServerConfig);
diff --git a/quic/test_tools/fuzzing/quic_framer_fuzzer.cc b/quic/test_tools/fuzzing/quic_framer_fuzzer.cc
index 1d83802..a14f410 100644
--- a/quic/test_tools/fuzzing/quic_framer_fuzzer.cc
+++ b/quic/test_tools/fuzzing/quic_framer_fuzzer.cc
@@ -1,3 +1,7 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
#include "base/commandlineflags.h"
#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"
diff --git a/quic/test_tools/mock_quic_dispatcher.cc b/quic/test_tools/mock_quic_dispatcher.cc
index 621a161..d7ccf2c 100644
--- a/quic/test_tools/mock_quic_dispatcher.cc
+++ b/quic/test_tools/mock_quic_dispatcher.cc
@@ -10,7 +10,7 @@
namespace test {
MockQuicDispatcher::MockQuicDispatcher(
- const QuicConfig& config,
+ const QuicConfig* config,
const QuicCryptoServerConfig* crypto_config,
QuicVersionManager* version_manager,
std::unique_ptr<QuicConnectionHelperInterface> helper,
diff --git a/quic/test_tools/mock_quic_dispatcher.h b/quic/test_tools/mock_quic_dispatcher.h
index 394a90b..93acda9 100644
--- a/quic/test_tools/mock_quic_dispatcher.h
+++ b/quic/test_tools/mock_quic_dispatcher.h
@@ -19,7 +19,7 @@
class MockQuicDispatcher : public QuicSimpleDispatcher {
public:
MockQuicDispatcher(
- const QuicConfig& config,
+ const QuicConfig* config,
const QuicCryptoServerConfig* crypto_config,
QuicVersionManager* version_manager,
std::unique_ptr<QuicConnectionHelperInterface> helper,
diff --git a/quic/test_tools/packet_dropping_test_writer.cc b/quic/test_tools/packet_dropping_test_writer.cc
index d296367..87935d5 100644
--- a/quic/test_tools/packet_dropping_test_writer.cc
+++ b/quic/test_tools/packet_dropping_test_writer.cc
@@ -246,7 +246,7 @@
options(std::move(options)),
send_time(send_time) {}
-PacketDroppingTestWriter::DelayedWrite::~DelayedWrite() {}
+PacketDroppingTestWriter::DelayedWrite::~DelayedWrite() = default;
} // namespace test
} // namespace quic
diff --git a/quic/test_tools/packet_dropping_test_writer.h b/quic/test_tools/packet_dropping_test_writer.h
index 404be81..51b3fc7 100644
--- a/quic/test_tools/packet_dropping_test_writer.h
+++ b/quic/test_tools/packet_dropping_test_writer.h
@@ -12,6 +12,7 @@
#include "net/third_party/quiche/src/quic/core/quic_alarm.h"
#include "net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_clock.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_macros.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_test_client.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
@@ -117,9 +118,7 @@
}
// Useful for reproducing very flaky issues.
- ABSL_ATTRIBUTE_UNUSED void set_seed(uint64_t seed) {
- simple_random_.set_seed(seed);
- }
+ QUIC_UNUSED void set_seed(uint64_t seed) { simple_random_.set_seed(seed); }
private:
// Writes out the next packet to the contained writer and returns the time
diff --git a/quic/test_tools/quic_framer_peer.cc b/quic/test_tools/quic_framer_peer.cc
index 20cbc49..89b0170 100644
--- a/quic/test_tools/quic_framer_peer.cc
+++ b/quic/test_tools/quic_framer_peer.cc
@@ -213,17 +213,18 @@
}
// static
-bool QuicFramerPeer::AppendMaxStreamIdFrame(QuicFramer* framer,
- const QuicMaxStreamIdFrame& frame,
- QuicDataWriter* writer) {
- return framer->AppendMaxStreamIdFrame(frame, writer);
+bool QuicFramerPeer::AppendMaxStreamsFrame(QuicFramer* framer,
+ const QuicMaxStreamIdFrame& frame,
+ QuicDataWriter* writer) {
+ return framer->AppendMaxStreamsFrame(frame, writer);
}
// static
-bool QuicFramerPeer::ProcessMaxStreamIdFrame(QuicFramer* framer,
- QuicDataReader* reader,
- QuicMaxStreamIdFrame* frame) {
- return framer->ProcessMaxStreamIdFrame(reader, frame);
+bool QuicFramerPeer::ProcessMaxStreamsFrame(QuicFramer* framer,
+ QuicDataReader* reader,
+ QuicMaxStreamIdFrame* frame,
+ uint64_t frame_type) {
+ return framer->ProcessMaxStreamsFrame(reader, frame, frame_type);
}
// static
@@ -255,19 +256,19 @@
}
// static
-bool QuicFramerPeer::AppendStreamIdBlockedFrame(
+bool QuicFramerPeer::AppendStreamsBlockedFrame(
QuicFramer* framer,
const QuicStreamIdBlockedFrame& frame,
QuicDataWriter* writer) {
- return framer->AppendStreamIdBlockedFrame(frame, writer);
+ return framer->AppendStreamsBlockedFrame(frame, writer);
}
// static
-bool QuicFramerPeer::ProcessStreamIdBlockedFrame(
- QuicFramer* framer,
- QuicDataReader* reader,
- QuicStreamIdBlockedFrame* frame) {
- return framer->ProcessStreamIdBlockedFrame(reader, frame);
+bool QuicFramerPeer::ProcessStreamsBlockedFrame(QuicFramer* framer,
+ QuicDataReader* reader,
+ QuicStreamIdBlockedFrame* frame,
+ uint64_t frame_type) {
+ return framer->ProcessStreamsBlockedFrame(reader, frame, frame_type);
}
// static
diff --git a/quic/test_tools/quic_framer_peer.h b/quic/test_tools/quic_framer_peer.h
index 1fa7351..cfe259a 100644
--- a/quic/test_tools/quic_framer_peer.h
+++ b/quic/test_tools/quic_framer_peer.h
@@ -116,12 +116,13 @@
static bool ProcessMaxStreamDataFrame(QuicFramer* framer,
QuicDataReader* reader,
QuicWindowUpdateFrame* frame);
- static bool AppendMaxStreamIdFrame(QuicFramer* framer,
- const QuicMaxStreamIdFrame& frame,
- QuicDataWriter* writer);
- static bool ProcessMaxStreamIdFrame(QuicFramer* framer,
- QuicDataReader* reader,
- QuicMaxStreamIdFrame* frame);
+ static bool AppendMaxStreamsFrame(QuicFramer* framer,
+ const QuicMaxStreamIdFrame& frame,
+ QuicDataWriter* writer);
+ static bool ProcessMaxStreamsFrame(QuicFramer* framer,
+ QuicDataReader* reader,
+ QuicMaxStreamIdFrame* frame,
+ uint64_t frame_type);
static bool AppendIetfBlockedFrame(QuicFramer* framer,
const QuicBlockedFrame& frame,
QuicDataWriter* writer);
@@ -136,12 +137,13 @@
QuicDataReader* reader,
QuicBlockedFrame* frame);
- static bool AppendStreamIdBlockedFrame(QuicFramer* framer,
- const QuicStreamIdBlockedFrame& frame,
- QuicDataWriter* writer);
- static bool ProcessStreamIdBlockedFrame(QuicFramer* framer,
- QuicDataReader* reader,
- QuicStreamIdBlockedFrame* frame);
+ static bool AppendStreamsBlockedFrame(QuicFramer* framer,
+ const QuicStreamIdBlockedFrame& frame,
+ QuicDataWriter* writer);
+ static bool ProcessStreamsBlockedFrame(QuicFramer* framer,
+ QuicDataReader* reader,
+ QuicStreamIdBlockedFrame* frame,
+ uint64_t frame_type);
static bool AppendNewConnectionIdFrame(QuicFramer* framer,
const QuicNewConnectionIdFrame& frame,
diff --git a/quic/test_tools/quic_packet_creator_peer.cc b/quic/test_tools/quic_packet_creator_peer.cc
index efcda92..51d9588 100644
--- a/quic/test_tools/quic_packet_creator_peer.cc
+++ b/quic/test_tools/quic_packet_creator_peer.cc
@@ -43,6 +43,18 @@
return creator->GetPacketNumberLength();
}
+// static
+QuicVariableLengthIntegerLength
+QuicPacketCreatorPeer::GetRetryTokenLengthLength(QuicPacketCreator* creator) {
+ return creator->GetRetryTokenLengthLength();
+}
+
+// static
+QuicVariableLengthIntegerLength QuicPacketCreatorPeer::GetLengthLength(
+ QuicPacketCreator* creator) {
+ return creator->GetLengthLength();
+}
+
void QuicPacketCreatorPeer::SetPacketNumber(QuicPacketCreator* creator,
uint64_t s) {
DCHECK_NE(0u, s);
diff --git a/quic/test_tools/quic_packet_creator_peer.h b/quic/test_tools/quic_packet_creator_peer.h
index 94c461a..c637ac2 100644
--- a/quic/test_tools/quic_packet_creator_peer.h
+++ b/quic/test_tools/quic_packet_creator_peer.h
@@ -27,6 +27,10 @@
QuicPacketNumberLength packet_number_length);
static QuicPacketNumberLength GetPacketNumberLength(
QuicPacketCreator* creator);
+ static QuicVariableLengthIntegerLength GetRetryTokenLengthLength(
+ QuicPacketCreator* creator);
+ static QuicVariableLengthIntegerLength GetLengthLength(
+ QuicPacketCreator* creator);
static void SetPacketNumber(QuicPacketCreator* creator, uint64_t s);
static void ClearPacketNumber(QuicPacketCreator* creator);
static void FillPacketHeader(QuicPacketCreator* creator,
diff --git a/quic/test_tools/quic_sent_packet_manager_peer.cc b/quic/test_tools/quic_sent_packet_manager_peer.cc
index 469fa40..3057e5e 100644
--- a/quic/test_tools/quic_sent_packet_manager_peer.cc
+++ b/quic/test_tools/quic_sent_packet_manager_peer.cc
@@ -8,6 +8,7 @@
#include "net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h"
#include "net/third_party/quiche/src/quic/core/quic_packets.h"
#include "net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_unacked_packet_map_peer.h"
namespace quic {
namespace test {
@@ -41,7 +42,8 @@
void QuicSentPacketManagerPeer::SetPerspective(
QuicSentPacketManager* sent_packet_manager,
Perspective perspective) {
- sent_packet_manager->perspective_ = perspective;
+ QuicUnackedPacketMapPeer::SetPerspective(
+ &sent_packet_manager->unacked_packets_, perspective);
}
// static
diff --git a/quic/test_tools/quic_spdy_session_peer.cc b/quic/test_tools/quic_spdy_session_peer.cc
index b84a7da..b739fa1 100644
--- a/quic/test_tools/quic_spdy_session_peer.cc
+++ b/quic/test_tools/quic_spdy_session_peer.cc
@@ -50,55 +50,15 @@
}
// static
-size_t QuicSpdySessionPeer::WriteHeadersImpl(
+size_t QuicSpdySessionPeer::WriteHeadersOnHeadersStream(
QuicSpdySession* session,
QuicStreamId id,
spdy::SpdyHeaderBlock headers,
bool fin,
- int weight,
- QuicStreamId parent_stream_id,
- bool exclusive,
+ spdy::SpdyPriority priority,
QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
- return session->WriteHeadersImpl(id, std::move(headers), fin, weight,
- parent_stream_id, exclusive,
- std::move(ack_listener));
-}
-
-// static
-QuicStreamId QuicSpdySessionPeer::StreamIdDelta(
- const QuicSpdySession& session) {
- return QuicUtils::StreamIdDelta(session.connection()->transport_version());
-}
-
-// static
-QuicStreamId QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId(
- const QuicSpdySession& session,
- int n) {
- return QuicUtils::GetFirstBidirectionalStreamId(
- session.connection()->transport_version(),
- Perspective::IS_CLIENT) +
- // + 1 because spdy_session contains headers stream.
- QuicSpdySessionPeer::StreamIdDelta(session) * (n + 1);
-}
-
-// static
-QuicStreamId QuicSpdySessionPeer::GetNthServerInitiatedBidirectionalStreamId(
- const QuicSpdySession& session,
- int n) {
- return QuicUtils::GetFirstBidirectionalStreamId(
- session.connection()->transport_version(),
- Perspective::IS_SERVER) +
- QuicSpdySessionPeer::StreamIdDelta(session) * n;
-}
-
-// static
-QuicStreamId QuicSpdySessionPeer::GetNthServerInitiatedUnidirectionalStreamId(
- const QuicSpdySession& session,
- int n) {
- return QuicUtils::GetFirstUnidirectionalStreamId(
- session.connection()->transport_version(),
- Perspective::IS_SERVER) +
- QuicSpdySessionPeer::StreamIdDelta(session) * n;
+ return session->WriteHeadersOnHeadersStream(
+ id, std::move(headers), fin, priority, std::move(ack_listener));
}
} // namespace test
diff --git a/quic/test_tools/quic_spdy_session_peer.h b/quic/test_tools/quic_spdy_session_peer.h
index e0dbddc..1993ec5 100644
--- a/quic/test_tools/quic_spdy_session_peer.h
+++ b/quic/test_tools/quic_spdy_session_peer.h
@@ -35,30 +35,13 @@
static void SetMaxUncompressedHeaderBytes(
QuicSpdySession* session,
size_t set_max_uncompressed_header_bytes);
- static size_t WriteHeadersImpl(
+ static size_t WriteHeadersOnHeadersStream(
QuicSpdySession* session,
QuicStreamId id,
spdy::SpdyHeaderBlock headers,
bool fin,
- int weight,
- QuicStreamId parent_stream_id,
- bool exclusive,
+ spdy::SpdyPriority priority,
QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
- // Helper functions for stream ids, to allow test logic to abstract
- // over the HTTP stream numbering scheme (i.e. whether one or
- // two QUIC streams are used per HTTP transaction).
- static QuicStreamId StreamIdDelta(const QuicSpdySession& session);
- // n should start at 0.
- static QuicStreamId GetNthClientInitiatedBidirectionalStreamId(
- const QuicSpdySession& session,
- int n);
- // n should start at 0.
- static QuicStreamId GetNthServerInitiatedBidirectionalStreamId(
- const QuicSpdySession& session,
- int n);
- static QuicStreamId GetNthServerInitiatedUnidirectionalStreamId(
- const QuicSpdySession& session,
- int n);
};
} // namespace test
diff --git a/quic/test_tools/quic_spdy_stream_peer.cc b/quic/test_tools/quic_spdy_stream_peer.cc
new file mode 100644
index 0000000..6632ec1
--- /dev/null
+++ b/quic/test_tools/quic_spdy_stream_peer.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/test_tools/quic_spdy_stream_peer.h"
+
+#include "net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h"
+
+namespace quic {
+namespace test {
+
+// static
+void QuicSpdyStreamPeer::set_ack_listener(
+ QuicSpdyStream* stream,
+ QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
+ stream->set_ack_listener(std::move(ack_listener));
+}
+
+// static
+const QuicIntervalSet<QuicStreamOffset>&
+QuicSpdyStreamPeer::unacked_frame_headers_offsets(QuicSpdyStream* stream) {
+ return stream->unacked_frame_headers_offsets();
+}
+
+} // namespace test
+} // namespace quic
diff --git a/quic/test_tools/quic_spdy_stream_peer.h b/quic/test_tools/quic_spdy_stream_peer.h
new file mode 100644
index 0000000..7b3fe7c
--- /dev/null
+++ b/quic/test_tools/quic_spdy_stream_peer.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_SPDY_STREAM_PEER_H_
+#define QUICHE_QUIC_TEST_TOOLS_QUIC_SPDY_STREAM_PEER_H_
+
+#include "net/third_party/quiche/src/quic/core/quic_ack_listener_interface.h"
+#include "net/third_party/quiche/src/quic/core/quic_interval_set.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
+
+namespace quic {
+
+class QuicSpdyStream;
+
+namespace test {
+
+class QuicSpdyStreamPeer {
+ public:
+ static void set_ack_listener(
+ QuicSpdyStream* stream,
+ QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
+ static const QuicIntervalSet<QuicStreamOffset>& unacked_frame_headers_offsets(
+ QuicSpdyStream* stream);
+};
+
+} // namespace test
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_TEST_TOOLS_QUIC_SPDY_STREAM_PEER_H_
diff --git a/quic/test_tools/quic_stream_peer.cc b/quic/test_tools/quic_stream_peer.cc
index e512ba4..7607523 100644
--- a/quic/test_tools/quic_stream_peer.cc
+++ b/quic/test_tools/quic_stream_peer.cc
@@ -87,12 +87,5 @@
return stream->send_buffer_;
}
-// static
-void QuicStreamPeer::set_ack_listener(
- QuicStream* stream,
- QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
- stream->set_ack_listener(std::move(ack_listener));
-}
-
} // namespace test
} // namespace quic
diff --git a/quic/test_tools/quic_stream_peer.h b/quic/test_tools/quic_stream_peer.h
index e1ba33a..e0058ba 100644
--- a/quic/test_tools/quic_stream_peer.h
+++ b/quic/test_tools/quic_stream_peer.h
@@ -48,10 +48,6 @@
static QuicSession* session(QuicStream* stream);
static QuicStreamSendBuffer& SendBuffer(QuicStream* stream);
-
- static void set_ack_listener(
- QuicStream* stream,
- QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
};
} // namespace test
diff --git a/quic/test_tools/quic_test_client.cc b/quic/test_tools/quic_test_client.cc
index a6298a6..213a7fd 100644
--- a/quic/test_tools/quic_test_client.cc
+++ b/quic/test_tools/quic_test_client.cc
@@ -25,12 +25,10 @@
#include "net/third_party/quiche/src/quic/test_tools/quic_client_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_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_spdy_stream_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
#include "net/third_party/quiche/src/quic/tools/quic_url.h"
-using spdy::SpdyHeaderBlock;
-
namespace quic {
namespace test {
namespace {
@@ -341,9 +339,8 @@
session->connection(), QuicConnection::SEND_ACK_IF_PENDING);
ssize_t ret = SendMessage(headers, "", /*fin=*/true, /*flush=*/false);
- QuicStreamId stream_id =
- QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId(*session,
- 0);
+ QuicStreamId stream_id = GetNthClientInitiatedBidirectionalStreamId(
+ session->connection()->transport_version(), 0);
session->SendRstStream(stream_id, QUIC_STREAM_CANCELLED, 0);
return ret;
}
@@ -385,18 +382,18 @@
if (stream == nullptr) {
return 0;
}
- QuicStreamPeer::set_ack_listener(stream, ack_listener);
+ QuicSpdyStreamPeer::set_ack_listener(stream, ack_listener);
ssize_t ret = 0;
if (headers != nullptr) {
- SpdyHeaderBlock spdy_headers(headers->Clone());
+ spdy::SpdyHeaderBlock spdy_headers(headers->Clone());
if (spdy_headers[":authority"].as_string().empty()) {
spdy_headers[":authority"] = client_->server_id().host();
}
ret = stream->SendRequest(std::move(spdy_headers), body, fin);
++num_requests_;
} else {
- stream->WriteOrBufferBody(QuicString(body), fin, ack_listener);
+ stream->WriteOrBufferBody(QuicString(body), fin);
ret = body.length();
}
if (GetQuicReloadableFlag(enable_quic_stateless_reject_support)) {
@@ -741,9 +738,9 @@
open_streams_.erase(id);
}
-bool QuicTestClient::CheckVary(const SpdyHeaderBlock& client_request,
- const SpdyHeaderBlock& promise_request,
- const SpdyHeaderBlock& promise_response) {
+bool QuicTestClient::CheckVary(const spdy::SpdyHeaderBlock& client_request,
+ const spdy::SpdyHeaderBlock& promise_request,
+ const spdy::SpdyHeaderBlock& promise_response) {
return true;
}
diff --git a/quic/test_tools/quic_test_server.cc b/quic/test_tools/quic_test_server.cc
index d2d33d6..220969b 100644
--- a/quic/test_tools/quic_test_server.cc
+++ b/quic/test_tools/quic_test_server.cc
@@ -70,7 +70,7 @@
class QuicTestDispatcher : public QuicSimpleDispatcher {
public:
QuicTestDispatcher(
- const QuicConfig& config,
+ const QuicConfig* config,
const QuicCryptoServerConfig* crypto_config,
QuicVersionManager* version_manager,
std::unique_ptr<QuicConnectionHelperInterface> helper,
@@ -165,7 +165,7 @@
QuicDispatcher* QuicTestServer::CreateQuicDispatcher() {
return new QuicTestDispatcher(
- config(), &crypto_config(), version_manager(),
+ &config(), &crypto_config(), version_manager(),
QuicMakeUnique<QuicEpollConnectionHelper>(epoll_server(),
QuicAllocator::BUFFER_POOL),
std::unique_ptr<QuicCryptoServerStream::Helper>(
diff --git a/quic/test_tools/quic_test_utils.cc b/quic/test_tools/quic_test_utils.cc
index da76b33..b10b509 100644
--- a/quic/test_tools/quic_test_utils.cc
+++ b/quic/test_tools/quic_test_utils.cc
@@ -41,9 +41,6 @@
}
QuicConnectionId TestConnectionId(uint64_t connection_number) {
- if (!QuicConnectionIdUseNetworkByteOrder()) {
- return QuicConnectionIdFromUInt64(connection_number);
- }
const uint64_t connection_id64_net =
QuicEndian::HostToNet64(connection_number);
return QuicConnectionId(reinterpret_cast<const char*>(&connection_id64_net),
@@ -51,9 +48,6 @@
}
uint64_t TestConnectionIdToUInt64(QuicConnectionId connection_id) {
- if (!QuicConnectionIdUseNetworkByteOrder()) {
- return QuicConnectionIdToUInt64(connection_id);
- }
DCHECK_EQ(connection_id.length(), kQuicDefaultConnectionIdLength);
uint64_t connection_id64_net = 0;
memcpy(&connection_id64_net, connection_id.data(),
@@ -124,14 +118,17 @@
const QuicFrames& frames,
size_t packet_size) {
char* buffer = new char[packet_size];
- size_t length = framer->BuildDataPacket(header, frames, buffer, packet_size);
+ size_t length = framer->BuildDataPacket(header, frames, buffer, packet_size,
+ ENCRYPTION_NONE);
DCHECK_NE(0u, length);
// Re-construct the data packet with data ownership.
return QuicMakeUnique<QuicPacket>(
buffer, length, /* owns_buffer */ true,
header.destination_connection_id_length,
header.source_connection_id_length, header.version_flag,
- header.nonce != nullptr, header.packet_number_length);
+ header.nonce != nullptr, header.packet_number_length,
+ header.retry_token_length_length, header.retry_token.length(),
+ header.length_length);
}
QuicString Sha1Hash(QuicStringPiece data) {
@@ -221,6 +218,8 @@
return true;
}
+void NoOpFramerVisitor::OnCoalescedPacket(const QuicEncryptedPacket& packet) {}
+
bool NoOpFramerVisitor::OnStreamFrame(const QuicStreamFrame& frame) {
return true;
}
@@ -433,6 +432,11 @@
ON_CALL(*this, OnError(_))
.WillByDefault(
Invoke(this, &PacketSavingConnection::QuicConnection_OnError));
+ ON_CALL(*this, SendCryptoData(_, _, _))
+ .WillByDefault(
+ Invoke(this, &MockQuicConnection::QuicConnection_SendCryptoData));
+
+ SetSelfAddress(QuicSocketAddress(QuicIpAddress::Any4(), 5));
}
MockQuicConnection::~MockQuicConnection() {}
@@ -466,10 +470,11 @@
void PacketSavingConnection::SendOrQueuePacket(SerializedPacket* packet) {
encrypted_packets_.push_back(QuicMakeUnique<QuicEncryptedPacket>(
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, QuicPacketNumber(), QuicTime::Zero(), NOT_RETRANSMISSION,
+ packet, QuicPacketNumber(), clock_.ApproximateNow(), NOT_RETRANSMISSION,
HAS_RETRANSMITTABLE_DATA);
}
@@ -581,16 +586,6 @@
crypto_stream_.reset(crypto_stream);
}
-size_t MockQuicSpdySession::WriteHeaders(
- QuicStreamId id,
- spdy::SpdyHeaderBlock headers,
- bool fin,
- spdy::SpdyPriority priority,
- QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
- write_headers_ = std::move(headers);
- return WriteHeadersMock(id, write_headers_, fin, priority, ack_listener);
-}
-
TestQuicSpdyServerSession::TestQuicSpdyServerSession(
QuicConnection* connection,
const QuicConfig& config,
@@ -853,17 +848,27 @@
header.reset_flag = reset_flag;
header.packet_number_length = packet_number_length;
header.packet_number = QuicPacketNumber(packet_number);
- QuicFrame frame(QuicStreamFrame(
- QuicUtils::GetCryptoStreamId(
- versions != nullptr
- ? (*versions)[0].transport_version
- : CurrentSupportedVersions()[0].transport_version),
- false, 0, QuicStringPiece(data)));
+ ParsedQuicVersionVector supported_versions = CurrentSupportedVersions();
+ if (!versions) {
+ versions = &supported_versions;
+ }
+ if (QuicVersionHasLongHeaderLengths((*versions)[0].transport_version) &&
+ version_flag) {
+ header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1;
+ header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2;
+ }
+
QuicFrames frames;
- frames.push_back(frame);
- QuicFramer framer(
- versions != nullptr ? *versions : CurrentSupportedVersions(),
- QuicTime::Zero(), perspective);
+ QuicFramer framer(*versions, QuicTime::Zero(), perspective);
+ if ((*versions)[0].transport_version < QUIC_VERSION_47) {
+ QuicFrame frame(QuicStreamFrame(
+ QuicUtils::GetCryptoStreamId((*versions)[0].transport_version), false,
+ 0, QuicStringPiece(data)));
+ frames.push_back(frame);
+ } else {
+ QuicFrame frame(new QuicCryptoFrame(ENCRYPTION_NONE, 0, data));
+ frames.push_back(frame);
+ }
std::unique_ptr<QuicPacket> packet(
BuildUnsizedDataPacket(&framer, header, frames));
@@ -873,6 +878,7 @@
framer.EncryptPayload(ENCRYPTION_NONE, QuicPacketNumber(packet_number),
*packet, buffer, kMaxPacketSize);
EXPECT_NE(0u, encrypted_length);
+ DeleteFrames(&frames);
return new QuicEncryptedPacket(buffer, encrypted_length, true);
}
@@ -921,7 +927,9 @@
packet->mutable_data())[GetStartOfEncryptedData(
framer.transport_version(), destination_connection_id_length,
source_connection_id_length, version_flag,
- false /* no diversification nonce */, packet_number_length)] = 0x1F;
+ false /* no diversification nonce */, packet_number_length,
+ VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0)] =
+ 0x1F;
char* buffer = new char[kMaxPacketSize];
size_t encrypted_length =
@@ -969,6 +977,8 @@
QuicConnectionIdLength destination_connection_id_length,
QuicConnectionIdLength source_connection_id_length,
QuicPacketNumberLength packet_number_length,
+ QuicVariableLengthIntegerLength retry_token_length_length,
+ QuicVariableLengthIntegerLength length_length,
size_t* payload_length) {
*payload_length = 1;
const size_t stream_length =
@@ -976,14 +986,16 @@
QuicPacketCreator::StreamFramePacketOverhead(
version, destination_connection_id_length,
source_connection_id_length, include_version,
- include_diversification_nonce, packet_number_length, 0u);
+ include_diversification_nonce, packet_number_length,
+ retry_token_length_length, length_length, 0u);
const size_t ack_length =
NullEncrypter(Perspective::IS_CLIENT)
.GetCiphertextSize(QuicFramer::GetMinAckFrameSize(
version, PACKET_1BYTE_PACKET_NUMBER)) +
GetPacketHeaderSize(version, destination_connection_id_length,
source_connection_id_length, include_version,
- include_diversification_nonce, packet_number_length);
+ include_diversification_nonce, packet_number_length,
+ retry_token_length_length, 0, length_length);
if (stream_length < ack_length) {
*payload_length = 1 + ack_length - stream_length;
}
@@ -993,7 +1005,8 @@
QuicPacketCreator::StreamFramePacketOverhead(
version, destination_connection_id_length,
source_connection_id_length, include_version,
- include_diversification_nonce, packet_number_length, 0u);
+ include_diversification_nonce, packet_number_length,
+ retry_token_length_length, length_length, 0u);
}
QuicConfig DefaultQuicConfig() {
@@ -1104,12 +1117,52 @@
(*server_connection)->AdvanceTime(connection_start_time);
}
+QuicStreamId GetNthClientInitiatedBidirectionalStreamId(
+ QuicTransportVersion version,
+ int n) {
+ return QuicUtils::GetFirstBidirectionalStreamId(version,
+ Perspective::IS_CLIENT) +
+ // + 1 because spdy_session contains headers stream.
+ QuicUtils::StreamIdDelta(version) * (n + 1);
+}
+
+QuicStreamId GetNthServerInitiatedBidirectionalStreamId(
+ QuicTransportVersion version,
+ int n) {
+ return QuicUtils::GetFirstBidirectionalStreamId(version,
+ Perspective::IS_SERVER) +
+ QuicUtils::StreamIdDelta(version) * n;
+}
+
+QuicStreamId GetNthServerInitiatedUnidirectionalStreamId(
+ QuicTransportVersion version,
+ int n) {
+ return QuicUtils::GetFirstUnidirectionalStreamId(version,
+ Perspective::IS_SERVER) +
+ QuicUtils::StreamIdDelta(version) * n;
+}
+
StreamType DetermineStreamType(QuicStreamId id,
QuicTransportVersion version,
+ Perspective perspective,
bool is_incoming,
StreamType default_type) {
- return version == QUIC_VERSION_99 ? QuicUtils::GetStreamType(id, is_incoming)
- : default_type;
+ return version == QUIC_VERSION_99
+ ? QuicUtils::GetStreamType(id, perspective, is_incoming)
+ : default_type;
+}
+
+QuicMemSliceSpan MakeSpan(QuicBufferAllocator* allocator,
+ QuicStringPiece message_data,
+ QuicMemSliceStorage* storage) {
+ if (message_data.length() == 0) {
+ *storage = QuicMemSliceStorage(nullptr, 0, allocator, kMaxPacketSize);
+ return storage->ToSpan();
+ }
+ struct iovec iov = {const_cast<char*>(message_data.data()),
+ message_data.length()};
+ *storage = QuicMemSliceStorage(&iov, 1, allocator, kMaxPacketSize);
+ return storage->ToSpan();
}
} // namespace test
diff --git a/quic/test_tools/quic_test_utils.h b/quic/test_tools/quic_test_utils.h
index 8b52d4f..cf4c167 100644
--- a/quic/test_tools/quic_test_utils.h
+++ b/quic/test_tools/quic_test_utils.h
@@ -25,6 +25,7 @@
#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_simple_buffer_allocator.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h"
@@ -164,6 +165,8 @@
QuicConnectionIdLength destination_connection_id_length,
QuicConnectionIdLength source_connection_id_length,
QuicPacketNumberLength packet_number_length,
+ QuicVariableLengthIntegerLength retry_token_length_length,
+ QuicVariableLengthIntegerLength length_length,
size_t* payload_length);
// Returns QuicConfig set to default values.
@@ -264,6 +267,7 @@
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_METHOD1(OnStreamFrame, bool(const QuicStreamFrame& frame));
MOCK_METHOD1(OnCryptoFrame, bool(const QuicCryptoFrame& frame));
MOCK_METHOD2(OnAckFrameStart, bool(QuicPacketNumber, QuicTime::Delta));
@@ -316,6 +320,7 @@
bool OnUnauthenticatedPublicHeader(const QuicPacketHeader& header) override;
void OnDecryptedPacket(EncryptionLevel level) override {}
bool OnPacketHeader(const QuicPacketHeader& header) override;
+ void OnCoalescedPacket(const QuicEncryptedPacket& packet) override;
bool OnStreamFrame(const QuicStreamFrame& frame) override;
bool OnCryptoFrame(const QuicCryptoFrame& frame) override;
bool OnAckFrameStart(QuicPacketNumber largest_acked,
@@ -358,6 +363,7 @@
~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));
@@ -511,7 +517,7 @@
MOCK_METHOD2(OnStreamReset, void(QuicStreamId, QuicRstStreamErrorCode));
MOCK_METHOD1(SendControlFrame, bool(const QuicFrame& frame));
- MOCK_METHOD2(SendMessage, MessageStatus(QuicMessageId, QuicStringPiece));
+ MOCK_METHOD2(SendMessage, MessageStatus(QuicMessageId, QuicMemSliceSpan));
MOCK_METHOD3(OnConnectionClosed,
void(QuicErrorCode error,
const QuicString& error_details,
@@ -555,6 +561,13 @@
}
MOCK_METHOD1(OnPathResponseFrame, bool(const QuicPathResponseFrame&));
MOCK_METHOD1(OnStopSendingFrame, bool(const QuicStopSendingFrame& frame));
+ MOCK_METHOD3(SendCryptoData,
+ size_t(EncryptionLevel, size_t, QuicStreamOffset));
+ size_t QuicConnection_SendCryptoData(EncryptionLevel level,
+ size_t write_length,
+ QuicStreamOffset offset) {
+ return QuicConnection::SendCryptoData(level, write_length, offset);
+ }
};
class PacketSavingConnection : public MockQuicConnection {
@@ -575,6 +588,7 @@
void SendOrQueuePacket(SerializedPacket* packet) override;
std::vector<std::unique_ptr<QuicEncryptedPacket>> encrypted_packets_;
+ MockClock clock_;
};
class MockQuicSession : public QuicSession {
@@ -668,7 +682,6 @@
QuicCryptoStream* GetMutableCryptoStream() override;
const QuicCryptoStream* GetCryptoStream() const override;
void SetCryptoStream(QuicCryptoStream* crypto_stream);
- const spdy::SpdyHeaderBlock& GetWriteHeaders() { return write_headers_; }
// From QuicSession.
MOCK_METHOD3(OnConnectionClosed,
@@ -720,22 +733,6 @@
MOCK_METHOD2(OnPriorityFrame,
void(QuicStreamId id, spdy::SpdyPriority priority));
- // Methods taking non-copyable types like SpdyHeaderBlock by value cannot be
- // mocked directly.
- size_t WriteHeaders(QuicStreamId id,
- spdy::SpdyHeaderBlock headers,
- bool fin,
- spdy::SpdyPriority priority,
- QuicReferenceCountedPointer<QuicAckListenerInterface>
- ack_listener) override;
- MOCK_METHOD5(
- WriteHeadersMock,
- size_t(QuicStreamId id,
- const spdy::SpdyHeaderBlock& headers,
- bool fin,
- spdy::SpdyPriority priority,
- const QuicReferenceCountedPointer<QuicAckListenerInterface>&
- ack_listener));
MOCK_METHOD1(OnHeadersHeadOfLineBlocking, void(QuicTime::Delta delta));
MOCK_METHOD4(
OnStreamFrameData,
@@ -745,7 +742,6 @@
private:
std::unique_ptr<QuicCryptoStream> crypto_stream_;
- spdy::SpdyHeaderBlock write_headers_;
};
class TestQuicSpdyServerSession : public QuicServerSessionBase {
@@ -869,7 +865,6 @@
const QuicIpAddress& self_address,
const QuicSocketAddress& peer_address,
PerPacketOptions* options));
- MOCK_CONST_METHOD0(IsWriteBlockedDataBuffered, bool());
MOCK_CONST_METHOD0(IsWriteBlocked, bool());
MOCK_METHOD0(SetWritable, void());
MOCK_CONST_METHOD1(GetMaxPacketSize,
@@ -1008,8 +1003,6 @@
MOCK_METHOD1(OnStreamFrame, void(const QuicStreamFrame&));
- MOCK_METHOD1(OnAckFrame, void(const QuicAckFrame& frame));
-
MOCK_METHOD1(OnStopWaitingFrame, void(const QuicStopWaitingFrame&));
MOCK_METHOD1(OnRstStreamFrame, void(const QuicRstStreamFrame&));
@@ -1177,11 +1170,31 @@
iov->iov_len = static_cast<size_t>(str.size());
}
+// Helper functions for stream ids, to allow test logic to abstract over the
+// HTTP stream numbering scheme (i.e. whether one or two QUIC streams are used
+// per HTTP transaction).
+QuicStreamId GetNthClientInitiatedBidirectionalStreamId(
+ QuicTransportVersion version,
+ int n);
+QuicStreamId GetNthServerInitiatedBidirectionalStreamId(
+ QuicTransportVersion version,
+ int n);
+QuicStreamId GetNthServerInitiatedUnidirectionalStreamId(
+ QuicTransportVersion version,
+ int n);
+
StreamType DetermineStreamType(QuicStreamId id,
QuicTransportVersion version,
+ Perspective perspective,
bool is_incoming,
StreamType default_type);
+// Utility function that stores message_data in |storage| and returns a
+// QuicMemSliceSpan.
+QuicMemSliceSpan MakeSpan(QuicBufferAllocator* allocator,
+ QuicStringPiece message_data,
+ QuicMemSliceStorage* storage);
+
} // namespace test
} // namespace quic
diff --git a/quic/test_tools/quic_unacked_packet_map_peer.cc b/quic/test_tools/quic_unacked_packet_map_peer.cc
new file mode 100644
index 0000000..1ecc65f
--- /dev/null
+++ b/quic/test_tools/quic_unacked_packet_map_peer.cc
@@ -0,0 +1,24 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/test_tools/quic_unacked_packet_map_peer.h"
+
+namespace quic {
+namespace test {
+
+// static
+const QuicStreamFrame& QuicUnackedPacketMapPeer::GetAggregatedStreamFrame(
+ const QuicUnackedPacketMap& unacked_packets) {
+ return unacked_packets.aggregated_stream_frame_;
+}
+
+// static
+void QuicUnackedPacketMapPeer::SetPerspective(
+ QuicUnackedPacketMap* unacked_packets,
+ Perspective perspective) {
+ *const_cast<Perspective*>(&unacked_packets->perspective_) = perspective;
+}
+
+} // namespace test
+} // namespace quic
diff --git a/quic/test_tools/quic_unacked_packet_map_peer.h b/quic/test_tools/quic_unacked_packet_map_peer.h
new file mode 100644
index 0000000..3bba0b6
--- /dev/null
+++ b/quic/test_tools/quic_unacked_packet_map_peer.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_UNACKED_PACKET_MAP_PEER_H_
+#define QUICHE_QUIC_TEST_TOOLS_QUIC_UNACKED_PACKET_MAP_PEER_H_
+
+#include "net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h"
+
+namespace quic {
+namespace test {
+
+class QuicUnackedPacketMapPeer {
+ public:
+ static const QuicStreamFrame& GetAggregatedStreamFrame(
+ const QuicUnackedPacketMap& unacked_packets);
+
+ static void SetPerspective(QuicUnackedPacketMap* unacked_packets,
+ Perspective perspective);
+};
+
+} // namespace test
+} // namespace quic
+
+#endif // QUICHE_QUIC_TEST_TOOLS_QUIC_UNACKED_PACKET_MAP_PEER_H_
diff --git a/quic/test_tools/simple_quic_framer.cc b/quic/test_tools/simple_quic_framer.cc
index 6b0fb66..b5847ac 100644
--- a/quic/test_tools/simple_quic_framer.cc
+++ b/quic/test_tools/simple_quic_framer.cc
@@ -55,6 +55,8 @@
return true;
}
+ void OnCoalescedPacket(const QuicEncryptedPacket& packet) override {}
+
bool OnStreamFrame(const QuicStreamFrame& frame) override {
// Save a copy of the data so it is valid after the packet is processed.
QuicString* string_data =
@@ -68,8 +70,13 @@
}
bool OnCryptoFrame(const QuicCryptoFrame& frame) override {
- // TODO(nharper): Implement this.
- return false;
+ // Save a copy of the data so it is valid after the packet is processed.
+ QuicString* string_data =
+ new QuicString(frame.data_buffer, frame.data_length);
+ crypto_data_.push_back(QuicWrapUnique(string_data));
+ crypto_frames_.push_back(QuicMakeUnique<QuicCryptoFrame>(
+ frame.level, frame.offset, QuicStringPiece(*string_data)));
+ return true;
}
bool OnAckFrameStart(QuicPacketNumber largest_acked,
@@ -181,7 +188,7 @@
}
bool OnMessageFrame(const QuicMessageFrame& frame) override {
- message_frames_.push_back(frame);
+ message_frames_.emplace_back(frame.data, frame.message_length);
return true;
}
@@ -222,6 +229,9 @@
const std::vector<std::unique_ptr<QuicStreamFrame>>& stream_frames() const {
return stream_frames_;
}
+ const std::vector<std::unique_ptr<QuicCryptoFrame>>& crypto_frames() const {
+ return crypto_frames_;
+ }
const std::vector<QuicStopWaitingFrame>& stop_waiting_frames() const {
return stop_waiting_frames_;
}
@@ -258,6 +268,7 @@
std::vector<QuicPaddingFrame> padding_frames_;
std::vector<QuicPingFrame> ping_frames_;
std::vector<std::unique_ptr<QuicStreamFrame>> stream_frames_;
+ std::vector<std::unique_ptr<QuicCryptoFrame>> crypto_frames_;
std::vector<QuicRstStreamFrame> rst_stream_frames_;
std::vector<QuicGoAwayFrame> goaway_frames_;
std::vector<QuicStreamIdBlockedFrame> stream_id_blocked_frames_;
@@ -274,6 +285,7 @@
std::vector<QuicNewTokenFrame> new_token_frames_;
std::vector<QuicMessageFrame> message_frames_;
std::vector<std::unique_ptr<QuicString>> stream_data_;
+ std::vector<std::unique_ptr<QuicString>> crypto_data_;
EncryptionLevel last_decrypted_level_;
};
@@ -325,7 +337,8 @@
rst_stream_frames().size() + stop_waiting_frames().size() +
path_challenge_frames().size() + path_response_frames().size() +
stream_frames().size() + ping_frames().size() +
- connection_close_frames().size() + padding_frames().size();
+ connection_close_frames().size() + padding_frames().size() +
+ crypto_frames().size();
}
const std::vector<QuicAckFrame>& SimpleQuicFramer::ack_frames() const {
@@ -364,6 +377,11 @@
return visitor_->stream_frames();
}
+const std::vector<std::unique_ptr<QuicCryptoFrame>>&
+SimpleQuicFramer::crypto_frames() const {
+ return visitor_->crypto_frames();
+}
+
const std::vector<QuicRstStreamFrame>& SimpleQuicFramer::rst_stream_frames()
const {
return visitor_->rst_stream_frames();
diff --git a/quic/test_tools/simple_quic_framer.h b/quic/test_tools/simple_quic_framer.h
index da2f4e5..2edf9d3 100644
--- a/quic/test_tools/simple_quic_framer.h
+++ b/quic/test_tools/simple_quic_framer.h
@@ -47,6 +47,7 @@
const std::vector<QuicGoAwayFrame>& goaway_frames() const;
const std::vector<QuicRstStreamFrame>& rst_stream_frames() const;
const std::vector<std::unique_ptr<QuicStreamFrame>>& stream_frames() const;
+ const std::vector<std::unique_ptr<QuicCryptoFrame>>& crypto_frames() const;
const std::vector<QuicPaddingFrame>& padding_frames() const;
const QuicVersionNegotiationPacket* version_negotiation_packet() const;
EncryptionLevel last_decrypted_level() const;
diff --git a/quic/test_tools/simple_session_notifier.cc b/quic/test_tools/simple_session_notifier.cc
index 75c55f4..c56831e 100644
--- a/quic/test_tools/simple_session_notifier.cc
+++ b/quic/test_tools/simple_session_notifier.cc
@@ -81,6 +81,17 @@
state.fin_outstanding = fin;
}
+size_t SimpleSessionNotifier::WriteCryptoData(EncryptionLevel level,
+ QuicByteCount data_length,
+ QuicStreamOffset offset) {
+ crypto_state_[level].bytes_total += data_length;
+ size_t bytes_written =
+ connection_->SendCryptoData(level, data_length, offset);
+ crypto_state_[level].bytes_sent += bytes_written;
+ crypto_bytes_transferred_[level].Add(offset, offset + bytes_written);
+ return bytes_written;
+}
+
void SimpleSessionNotifier::WriteOrBufferRstStream(
QuicStreamId id,
QuicRstStreamErrorCode error,
@@ -103,6 +114,7 @@
void SimpleSessionNotifier::NeuterUnencryptedData() {
for (const auto& interval : crypto_bytes_transferred_[ENCRYPTION_NONE]) {
+ // TODO(nharper): Handle CRYPTO frame case.
QuicStreamFrame stream_frame(
QuicUtils::GetCryptoStreamId(connection_->transport_version()), false,
interval.min(), interval.max() - interval.min());
@@ -120,6 +132,7 @@
return;
}
// Write new data.
+ // TODO(nharper): Write CRYPTO frames.
for (const auto& pair : stream_map_) {
const auto& state = pair.second;
if (!StreamHasBufferedData(pair.first)) {
@@ -175,6 +188,19 @@
bool SimpleSessionNotifier::OnFrameAcked(const QuicFrame& frame,
QuicTime::Delta /*ack_delay_time*/) {
QUIC_DVLOG(1) << "Acking " << frame;
+ if (frame.type == CRYPTO_FRAME) {
+ StreamState* state = &crypto_state_[frame.crypto_frame->level];
+ QuicStreamOffset offset = frame.crypto_frame->offset;
+ QuicByteCount data_length = frame.crypto_frame->data_length;
+ QuicIntervalSet<QuicStreamOffset> newly_acked(offset, offset + data_length);
+ newly_acked.Difference(state->bytes_acked);
+ if (newly_acked.Empty()) {
+ return false;
+ }
+ state->bytes_acked.Add(offset, offset + data_length);
+ state->pending_retransmissions.Difference(offset, offset + data_length);
+ return true;
+ }
if (frame.type != STREAM_FRAME) {
return OnControlFrameAcked(frame);
}
@@ -201,6 +227,20 @@
void SimpleSessionNotifier::OnFrameLost(const QuicFrame& frame) {
QUIC_DVLOG(1) << "Losting " << frame;
+ if (frame.type == CRYPTO_FRAME) {
+ StreamState* state = &crypto_state_[frame.crypto_frame->level];
+ QuicStreamOffset offset = frame.crypto_frame->offset;
+ QuicByteCount data_length = frame.crypto_frame->data_length;
+ QuicIntervalSet<QuicStreamOffset> bytes_lost(offset, offset + data_length);
+ bytes_lost.Difference(state->bytes_acked);
+ if (bytes_lost.Empty()) {
+ return;
+ }
+ for (const auto& lost : bytes_lost) {
+ state->pending_retransmissions.Add(lost.min(), lost.max());
+ }
+ return;
+ }
if (frame.type != STREAM_FRAME) {
OnControlFrameLost(frame);
return;
@@ -229,6 +269,21 @@
connection_, QuicConnection::SEND_ACK_IF_QUEUED);
connection_->SetTransmissionType(type);
for (const QuicFrame& frame : frames) {
+ if (frame.type == CRYPTO_FRAME) {
+ const StreamState& state = crypto_state_[frame.crypto_frame->level];
+ QuicIntervalSet<QuicStreamOffset> retransmission(
+ frame.crypto_frame->offset,
+ frame.crypto_frame->offset + frame.crypto_frame->data_length);
+ retransmission.Difference(state.bytes_acked);
+ for (const auto& interval : retransmission) {
+ QuicStreamOffset offset = interval.min();
+ QuicByteCount length = interval.max() - interval.min();
+ size_t consumed = connection_->SendCryptoData(frame.crypto_frame->level,
+ length, offset);
+ // CRYPTO frames should never be write blocked.
+ DCHECK_EQ(consumed, length);
+ }
+ }
if (frame.type != STREAM_FRAME) {
if (GetControlFrameId(frame) == kInvalidControlFrameId) {
continue;
@@ -308,6 +363,14 @@
}
bool SimpleSessionNotifier::IsFrameOutstanding(const QuicFrame& frame) const {
+ if (frame.type == CRYPTO_FRAME) {
+ QuicStreamOffset offset = frame.crypto_frame->offset;
+ QuicByteCount data_length = frame.crypto_frame->data_length;
+ bool ret = data_length > 0 &&
+ !crypto_state_[frame.crypto_frame->level].bytes_acked.Contains(
+ offset, offset + data_length);
+ return ret;
+ }
if (frame.type != STREAM_FRAME) {
return IsControlFrameOutstanding(frame);
}
@@ -323,6 +386,20 @@
}
bool SimpleSessionNotifier::HasUnackedCryptoData() const {
+ if (connection_->transport_version() >= QUIC_VERSION_47) {
+ for (size_t i = 0; i < NUM_ENCRYPTION_LEVELS; ++i) {
+ const StreamState& state = crypto_state_[i];
+ if (state.bytes_total > state.bytes_sent) {
+ return true;
+ }
+ QuicIntervalSet<QuicStreamOffset> bytes_to_ack(0, state.bytes_total);
+ bytes_to_ack.Difference(state.bytes_acked);
+ if (!bytes_to_ack.Empty()) {
+ return true;
+ }
+ }
+ return false;
+ }
if (!QuicContainsKey(stream_map_, QuicUtils::GetCryptoStreamId(
connection_->transport_version()))) {
return false;
@@ -406,6 +483,7 @@
}
bool SimpleSessionNotifier::RetransmitLostCryptoData() {
+ // TODO(nharper): Handle CRYPTO frame case.
if (!QuicContainsKey(stream_map_, QuicUtils::GetCryptoStreamId(
connection_->transport_version()))) {
return true;
diff --git a/quic/test_tools/simple_session_notifier.h b/quic/test_tools/simple_session_notifier.h
index 293937f..f7982d2 100644
--- a/quic/test_tools/simple_session_notifier.h
+++ b/quic/test_tools/simple_session_notifier.h
@@ -6,6 +6,7 @@
#define QUICHE_QUIC_TEST_TOOLS_SIMPLE_SESSION_NOTIFIER_H_
#include "testing/gmock/include/gmock/gmock.h"
+#include "net/third_party/quiche/src/quic/core/quic_interval_set.h"
#include "net/third_party/quiche/src/quic/core/session_notifier_interface.h"
namespace quic {
@@ -31,6 +32,11 @@
QuicRstStreamErrorCode error,
QuicStreamOffset bytes_written);
+ // Tries to write CRYPTO data and returns the number of bytes written.
+ size_t WriteCryptoData(EncryptionLevel level,
+ QuicByteCount data_length,
+ QuicStreamOffset offset);
+
// Neuters unencrypted data of crypto stream.
void NeuterUnencryptedData();
@@ -133,6 +139,8 @@
QuicIntervalSet<QuicStreamOffset>
crypto_bytes_transferred_[NUM_ENCRYPTION_LEVELS];
+ StreamState crypto_state_[NUM_ENCRYPTION_LEVELS];
+
QuicConnection* connection_;
};
diff --git a/quic/test_tools/simple_session_notifier_test.cc b/quic/test_tools/simple_session_notifier_test.cc
index 61bc95c..b20fee6 100644
--- a/quic/test_tools/simple_session_notifier_test.cc
+++ b/quic/test_tools/simple_session_notifier_test.cc
@@ -111,8 +111,8 @@
notifier_.WriteOrBufferData(
QuicUtils::GetCryptoStreamId(connection_.transport_version()), 1024,
NO_FIN);
- // Send crypto data [1024, 2048) in ENCRYPTION_INITIAL.
- connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
+ // Send crypto data [1024, 2048) in ENCRYPTION_ZERO_RTT.
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
EXPECT_CALL(connection_, SendStreamData(QuicUtils::GetCryptoStreamId(
connection_.transport_version()),
1024, 1024, NO_FIN))
@@ -144,8 +144,8 @@
notifier_.WriteOrBufferData(
QuicUtils::GetCryptoStreamId(connection_.transport_version()), 1024,
NO_FIN);
- // Send crypto data [1024, 2048) in ENCRYPTION_INITIAL.
- connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
+ // Send crypto data [1024, 2048) in ENCRYPTION_ZERO_RTT.
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
EXPECT_CALL(connection_, SendStreamData(QuicUtils::GetCryptoStreamId(
connection_.transport_version()),
1024, 1024, NO_FIN))
diff --git a/quic/test_tools/simulator/quic_endpoint.cc b/quic/test_tools/simulator/quic_endpoint.cc
index 2867d82..5cd4de1 100644
--- a/quic/test_tools/simulator/quic_endpoint.cc
+++ b/quic/test_tools/simulator/quic_endpoint.cc
@@ -223,6 +223,8 @@
DCHECK_LE(offsets_received_.Size(), 1000u);
}
+void QuicEndpoint::OnCryptoFrame(const QuicCryptoFrame& frame) {}
+
void QuicEndpoint::OnCanWrite() {
if (notifier_ != nullptr) {
notifier_->OnCanWrite();
@@ -311,10 +313,6 @@
return WriteResult(WRITE_STATUS_OK, buf_len);
}
-bool QuicEndpoint::Writer::IsWriteBlockedDataBuffered() const {
- return false;
-}
-
bool QuicEndpoint::Writer::IsWriteBlocked() const {
return is_blocked_;
}
diff --git a/quic/test_tools/simulator/quic_endpoint.h b/quic/test_tools/simulator/quic_endpoint.h
index 600a1d1..e36f384 100644
--- a/quic/test_tools/simulator/quic_endpoint.h
+++ b/quic/test_tools/simulator/quic_endpoint.h
@@ -80,6 +80,7 @@
// Begin QuicConnectionVisitorInterface implementation.
void OnStreamFrame(const QuicStreamFrame& frame) override;
+ void OnCryptoFrame(const QuicCryptoFrame& frame) override;
void OnCanWrite() override;
bool WillingAndAbleToWrite() const override;
bool HasPendingHandshake() const override;
@@ -108,13 +109,13 @@
void OnForwardProgressConfirmed() override {}
bool OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame) override {
return true;
- };
+ }
bool OnStreamIdBlockedFrame(const QuicStreamIdBlockedFrame& frame) override {
return true;
- };
+ }
bool OnStopSendingFrame(const QuicStopSendingFrame& frame) override {
return true;
- };
+ }
// End QuicConnectionVisitorInterface implementation.
@@ -141,7 +142,6 @@
const QuicIpAddress& self_address,
const QuicSocketAddress& peer_address,
PerPacketOptions* options) override;
- bool IsWriteBlockedDataBuffered() const override;
bool IsWriteBlocked() const override;
void SetWritable() override;
QuicByteCount GetMaxPacketSize(
diff --git a/quic/test_tools/simulator/switch.cc b/quic/test_tools/simulator/switch.cc
index d00daf7..638fa20 100644
--- a/quic/test_tools/simulator/switch.cc
+++ b/quic/test_tools/simulator/switch.cc
@@ -4,7 +4,6 @@
#include <cinttypes>
-#include "base/port.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
#include "net/third_party/quiche/src/quic/test_tools/simulator/switch.h"
@@ -17,10 +16,9 @@
SwitchPortNumber port_count,
QuicByteCount queue_capacity) {
for (size_t port_number = 1; port_number <= port_count; port_number++) {
- ports_.emplace_back(
- simulator,
- QuicStringPrintf("%s (port %" PRIuS ")", name.c_str(), port_number),
- this, port_number, queue_capacity);
+ ports_.emplace_back(simulator,
+ QuicStrCat(name, " (port ", port_number, ")"), this,
+ port_number, queue_capacity);
}
}
diff --git a/quic/tools/quic_client_base.cc b/quic/tools/quic_client_base.cc
index f824811..2d8c307 100644
--- a/quic/tools/quic_client_base.cc
+++ b/quic/tools/quic_client_base.cc
@@ -226,6 +226,11 @@
return true;
}
+bool QuicClientBase::ChangeEphemeralPort() {
+ auto current_host = network_helper_->GetLatestClientAddress().host();
+ return MigrateSocketWithSpecifiedPort(current_host, 0 /*any ephemeral port*/);
+}
+
QuicSession* QuicClientBase::session() {
return session_.get();
}
@@ -325,7 +330,7 @@
}
QuicConnectionId QuicClientBase::GenerateNewConnectionId() {
- return QuicUtils::CreateRandomConnectionId(Perspective::IS_CLIENT);
+ return QuicUtils::CreateRandomConnectionId();
}
bool QuicClientBase::CanReconnectWithDifferentVersion(
diff --git a/quic/tools/quic_client_base.h b/quic/tools/quic_client_base.h
index c751bfd..379f097 100644
--- a/quic/tools/quic_client_base.h
+++ b/quic/tools/quic_client_base.h
@@ -10,12 +10,12 @@
#include <string>
-#include "base/macros.h"
#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.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/http/quic_spdy_client_stream.h"
#include "net/third_party/quiche/src/quic/core/quic_config.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_macros.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
@@ -102,7 +102,7 @@
// Wait for events until the handshake is confirmed.
// Returns true if the crypto handshake succeeds, false otherwise.
- bool WaitForCryptoHandshakeConfirmed() ABSL_MUST_USE_RESULT;
+ bool WaitForCryptoHandshakeConfirmed() QUIC_MUST_USE_RESULT;
// Wait up to 50ms, and handle any events which occur.
// Returns true if there are any outstanding requests.
@@ -114,6 +114,9 @@
// Migrate to a new socket (new_host, port) during an active connection.
bool MigrateSocketWithSpecifiedPort(const QuicIpAddress& new_host, int port);
+ // Open a new socket to change to a new ephemeral port.
+ bool ChangeEphemeralPort();
+
QuicSession* session();
bool connected() const;
diff --git a/quic/tools/quic_client_bin.cc b/quic/tools/quic_client_bin.cc
index 629b980..9504c74 100644
--- a/quic/tools/quic_client_bin.cc
+++ b/quic/tools/quic_client_bin.cc
@@ -29,6 +29,9 @@
// IP=`dig www.google.com +short | head -1`
// quic_client www.google.com --host=${IP}
//
+// Send repeated requests and change ephemeral port between requests
+// quic_client www.google.com --num_requests=10
+//
// Try to connect to a host which does not speak QUIC:
// quic_client www.example.com
//
@@ -40,19 +43,21 @@
// --config=quic quic_client
#include <iostream>
+#include <vector>
#include "base/commandlineflags.h"
#include "base/init_google.h"
#include "net/base/ipaddress.h"
#include "net/dns/hostlookup.h"
#include "third_party/absl/flags/flag.h"
-#include "net/third_party/quiche/src/quic/core/crypto/proof_verifier_google3.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_default_proof_providers.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
#include "net/third_party/quiche/src/quic/tools/quic_client.h"
@@ -90,49 +95,84 @@
}
};
-DEFINE_string(host,
- "",
- "The IP or hostname to connect to. If not provided, the host "
- "will be derived from the provided URL.");
-DEFINE_int32(port, 0, "The port to connect to.");
-DEFINE_string(body, "", "If set, send a POST with this body.");
-DEFINE_string(body_hex,
- "",
- "If set, contents are converted from hex to ascii, before "
- "sending as body of a POST. e.g. --body_hex=\"68656c6c6f\"");
-DEFINE_string(headers,
- "",
- "A semicolon separated list of key:value pairs to "
- "add to request headers.");
-DEFINE_bool(quiet, false, "Set to true for a quieter output experience.");
-DEFINE_int32(quic_version,
- -1,
- "QUIC version to speak, e.g. 21. If not set, then all available "
- "versions are offered in the handshake.");
-DEFINE_bool(version_mismatch_ok,
- false,
- "If true, a version mismatch in the handshake is not considered a "
- "failure. Useful for probing a server to determine if it speaks "
- "any version of QUIC.");
-DEFINE_bool(redirect_is_success,
- true,
- "If true, an HTTP response code of 3xx is considered to be a "
- "successful response, otherwise a failure.");
-DEFINE_int32(initial_mtu, 0, "Initial MTU of the connection.");
-DEFINE_string(root_certificate_file,
- "/google/src/head/depot/google3/security/cacerts/"
- "for_connecting_to_google/roots.pem",
- "Path to the root certificate which the server's certificate is "
- "required to chain to.");
-ABSL_FLAG(bool,
- disable_certificate_verification,
- false,
- "If true, don't verify the server certificate.");
-ABSL_FLAG(bool,
- drop_response_body,
- false,
- "If true, drop response body immediately after it is received.");
+DEFINE_QUIC_COMMAND_LINE_FLAG(
+ string,
+ host,
+ "",
+ "The IP or hostname to connect to. If not provided, the host "
+ "will be derived from the provided URL.");
+DEFINE_QUIC_COMMAND_LINE_FLAG(int32_t, port, 0, "The port to connect to.");
+
+DEFINE_QUIC_COMMAND_LINE_FLAG(string,
+ body,
+ "",
+ "If set, send a POST with this body.");
+
+DEFINE_QUIC_COMMAND_LINE_FLAG(
+ string,
+ body_hex,
+ "",
+ "If set, contents are converted from hex to ascii, before "
+ "sending as body of a POST. e.g. --body_hex=\"68656c6c6f\"");
+
+DEFINE_QUIC_COMMAND_LINE_FLAG(
+ string,
+ headers,
+ "",
+ "A semicolon separated list of key:value pairs to "
+ "add to request headers.");
+
+DEFINE_QUIC_COMMAND_LINE_FLAG(bool,
+ quiet,
+ false,
+ "Set to true for a quieter output experience.");
+
+DEFINE_QUIC_COMMAND_LINE_FLAG(
+ int32_t,
+ quic_version,
+ -1,
+ "QUIC version to speak, e.g. 21. If not set, then all available "
+ "versions are offered in the handshake.");
+
+DEFINE_QUIC_COMMAND_LINE_FLAG(
+ bool,
+ version_mismatch_ok,
+ false,
+ "If true, a version mismatch in the handshake is not considered a "
+ "failure. Useful for probing a server to determine if it speaks "
+ "any version of QUIC.");
+
+DEFINE_QUIC_COMMAND_LINE_FLAG(
+ bool,
+ redirect_is_success,
+ true,
+ "If true, an HTTP response code of 3xx is considered to be a "
+ "successful response, otherwise a failure.");
+
+DEFINE_QUIC_COMMAND_LINE_FLAG(int32_t,
+ initial_mtu,
+ 0,
+ "Initial MTU of the connection.");
+
+DEFINE_QUIC_COMMAND_LINE_FLAG(
+ int32_t,
+ num_requests,
+ 1,
+ "How many sequential requests to make on a single connection.");
+
+DEFINE_QUIC_COMMAND_LINE_FLAG(bool,
+ disable_certificate_verification,
+ false,
+ "If true, don't verify the server certificate.");
+
+DEFINE_QUIC_COMMAND_LINE_FLAG(
+ bool,
+ drop_response_body,
+ false,
+ "If true, drop response body immediately after it is received.");
+
+using quic::QuicString;
using quic::QuicStringPiece;
using quic::QuicTextUtils;
using quic::QuicUrl;
@@ -141,20 +181,22 @@
using std::endl;
int main(int argc, char* argv[]) {
- InitGoogle(argv[0], &argc, &argv, true);
+ const char* usage = "Usage: quic_client [options] <url>";
// All non-flag arguments should be interpreted as URLs to fetch.
- if (argc != 2) {
- cerr << "Usage: " << argv[0] << " [optional flags] url" << endl;
- return 1;
+ std::vector<QuicString> urls =
+ quic::QuicParseCommandLineFlags(usage, argc, argv);
+ if (urls.size() != 1) {
+ quic::QuicPrintCommandLineFlagHelp(usage);
+ exit(0);
}
- QuicUrl url(argv[1], "https");
- string host = FLAGS_host;
+ QuicUrl url(urls[0], "https");
+ string host = GetQuicFlag(FLAGS_host);
if (host.empty()) {
host = url.host();
}
- int port = FLAGS_port;
+ int port = GetQuicFlag(FLAGS_port);
if (port == 0) {
port = url.port();
}
@@ -176,23 +218,24 @@
quic::QuicEpollServer epoll_server;
quic::QuicServerId server_id(url.host(), port, false);
quic::ParsedQuicVersionVector versions = quic::CurrentSupportedVersions();
- if (FLAGS_quic_version != -1) {
+ if (GetQuicFlag(FLAGS_quic_version) != -1) {
versions.clear();
versions.push_back(quic::ParsedQuicVersion(
- quic::PROTOCOL_QUIC_CRYPTO,
- static_cast<quic::QuicTransportVersion>(FLAGS_quic_version)));
+ quic::PROTOCOL_QUIC_CRYPTO, static_cast<quic::QuicTransportVersion>(
+ GetQuicFlag(FLAGS_quic_version))));
}
+ const int32_t num_requests(GetQuicFlag(FLAGS_num_requests));
std::unique_ptr<quic::ProofVerifier> proof_verifier;
if (GetQuicFlag(FLAGS_disable_certificate_verification)) {
proof_verifier = quic::QuicMakeUnique<FakeProofVerifier>();
} else {
- proof_verifier = quic::QuicMakeUnique<quic::ProofVerifierGoogle3>(
- FLAGS_root_certificate_file);
+ proof_verifier = quic::CreateDefaultProofVerifier();
}
quic::QuicClient client(quic::QuicSocketAddress(ip_addr, port), server_id,
versions, &epoll_server, std::move(proof_verifier));
+ int32_t initial_mtu = GetQuicFlag(FLAGS_initial_mtu);
client.set_initial_max_packet_length(
- FLAGS_initial_mtu != 0 ? FLAGS_initial_mtu : quic::kDefaultMaxPacketSize);
+ initial_mtu != 0 ? initial_mtu : quic::kDefaultMaxPacketSize);
client.set_drop_response_body(GetQuicFlag(FLAGS_drop_response_body));
if (!client.Initialize()) {
cerr << "Failed to initialize client." << endl;
@@ -206,7 +249,7 @@
<< endl;
// 0: No error.
// 20: Failed to connect due to QUIC_INVALID_VERSION.
- return FLAGS_version_mismatch_ok ? 0 : 20;
+ return GetQuicFlag(FLAGS_version_mismatch_ok) ? 0 : 20;
}
cerr << "Failed to connect to " << host_port
<< ". Error: " << quic::QuicErrorCodeToString(error) << endl;
@@ -215,10 +258,11 @@
cout << "Connected to " << host_port << endl;
// Construct the string body from flags, if provided.
- string body = FLAGS_body;
- if (!FLAGS_body_hex.empty()) {
- DCHECK(FLAGS_body.empty()) << "Only set one of --body and --body_hex.";
- body = QuicTextUtils::HexDecode(FLAGS_body_hex);
+ string body = GetQuicFlag(FLAGS_body);
+ if (!GetQuicFlag(FLAGS_body_hex).empty()) {
+ DCHECK(GetQuicFlag(FLAGS_body).empty())
+ << "Only set one of --body and --body_hex.";
+ body = QuicTextUtils::HexDecode(GetQuicFlag(FLAGS_body_hex));
}
// Construct a GET or POST request for supplied URL.
@@ -229,7 +273,8 @@
header_block[":path"] = url.PathParamsQuery();
// Append any additional headers supplied on the command line.
- for (QuicStringPiece sp : QuicTextUtils::Split(FLAGS_headers, ';')) {
+ for (QuicStringPiece sp :
+ QuicTextUtils::Split(GetQuicFlag(FLAGS_headers), ';')) {
QuicTextUtils::RemoveLeadingAndTrailingWhitespace(&sp);
if (sp.empty()) {
continue;
@@ -243,55 +288,72 @@
// Make sure to store the response, for later output.
client.set_store_response(true);
- // Send the request.
- client.SendRequestAndWaitForResponse(header_block, body, /*fin=*/true);
+ for (int i = 0; i < num_requests; ++i) {
+ // Send the request.
+ client.SendRequestAndWaitForResponse(header_block, body, /*fin=*/true);
- // Print request and response details.
- if (!FLAGS_quiet) {
- cout << "Request:" << endl;
- cout << "headers:" << header_block.DebugString();
- if (!FLAGS_body_hex.empty()) {
- // Print the user provided hex, rather than binary body.
- cout << "body:\n"
- << QuicTextUtils::HexDump(QuicTextUtils::HexDecode(FLAGS_body_hex))
- << endl;
- } else {
- cout << "body: " << body << endl;
- }
- cout << endl;
-
- if (!client.preliminary_response_headers().empty()) {
- cout << "Preliminary response headers: "
- << client.preliminary_response_headers() << endl;
+ // Print request and response details.
+ if (!GetQuicFlag(FLAGS_quiet)) {
+ cout << "Request:" << endl;
+ cout << "headers:" << header_block.DebugString();
+ if (!GetQuicFlag(FLAGS_body_hex).empty()) {
+ // Print the user provided hex, rather than binary body.
+ cout << "body:\n"
+ << QuicTextUtils::HexDump(
+ QuicTextUtils::HexDecode(GetQuicFlag(FLAGS_body_hex)))
+ << endl;
+ } else {
+ cout << "body: " << body << endl;
+ }
cout << endl;
+
+ if (!client.preliminary_response_headers().empty()) {
+ cout << "Preliminary response headers: "
+ << client.preliminary_response_headers() << endl;
+ cout << endl;
+ }
+
+ cout << "Response:" << endl;
+ cout << "headers: " << client.latest_response_headers() << endl;
+ string response_body = client.latest_response_body();
+ if (!GetQuicFlag(FLAGS_body_hex).empty()) {
+ // Assume response is binary data.
+ cout << "body:\n" << QuicTextUtils::HexDump(response_body) << endl;
+ } else {
+ cout << "body: " << response_body << endl;
+ }
+ cout << "trailers: " << client.latest_response_trailers() << endl;
}
- cout << "Response:" << endl;
- cout << "headers: " << client.latest_response_headers() << endl;
- string response_body = client.latest_response_body();
- if (!FLAGS_body_hex.empty()) {
- // Assume response is binary data.
- cout << "body:\n" << QuicTextUtils::HexDump(response_body) << endl;
- } else {
- cout << "body: " << response_body << endl;
- }
- cout << "trailers: " << client.latest_response_trailers() << endl;
- }
-
- size_t response_code = client.latest_response_code();
- if (response_code >= 200 && response_code < 300) {
- cout << "Request succeeded (" << response_code << ")." << endl;
- return 0;
- } else if (response_code >= 300 && response_code < 400) {
- if (FLAGS_redirect_is_success) {
- cout << "Request succeeded (redirect " << response_code << ")." << endl;
- return 0;
- } else {
- cout << "Request failed (redirect " << response_code << ")." << endl;
+ if (!client.connected()) {
+ cerr << "Request caused connection failure. Error: "
+ << quic::QuicErrorCodeToString(client.session()->error()) << endl;
return 1;
}
- } else {
- cerr << "Request failed (" << response_code << ")." << endl;
- return 1;
+
+ size_t response_code = client.latest_response_code();
+ if (response_code >= 200 && response_code < 300) {
+ cout << "Request succeeded (" << response_code << ")." << endl;
+ } else if (response_code >= 300 && response_code < 400) {
+ if (GetQuicFlag(FLAGS_redirect_is_success)) {
+ cout << "Request succeeded (redirect " << response_code << ")." << endl;
+ } else {
+ cout << "Request failed (redirect " << response_code << ")." << endl;
+ return 1;
+ }
+ } else {
+ cerr << "Request failed (" << response_code << ")." << endl;
+ return 1;
+ }
+
+ // Change the ephemeral port if there are more requests to do.
+ if (i + 1 < num_requests) {
+ if (!client.ChangeEphemeralPort()) {
+ cout << "Failed to change ephemeral port." << endl;
+ return 1;
+ }
+ }
}
+
+ return 0;
}
diff --git a/quic/tools/quic_client_epoll_network_helper.cc b/quic/tools/quic_client_epoll_network_helper.cc
index 6a48ad3..f2d22a1 100644
--- a/quic/tools/quic_client_epoll_network_helper.cc
+++ b/quic/tools/quic_client_epoll_network_helper.cc
@@ -78,6 +78,7 @@
} else {
client_address = QuicSocketAddress(QuicIpAddress::Any6(), bind_to_port);
}
+
sockaddr_storage addr = client_address.generic_address();
int rc = bind(fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr));
if (rc < 0) {
diff --git a/quic/tools/quic_client_epoll_network_helper.h b/quic/tools/quic_client_epoll_network_helper.h
index 5871cd0..e0f8cf3 100644
--- a/quic/tools/quic_client_epoll_network_helper.h
+++ b/quic/tools/quic_client_epoll_network_helper.h
@@ -13,16 +13,13 @@
#include <string>
#include "base/macros.h"
-#include "gfe/gfe2/base/epoll_server.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/http/quic_spdy_client_stream.h"
#include "net/third_party/quiche/src/quic/core/quic_config.h"
#include "net/third_party/quiche/src/quic/core/quic_packet_reader.h"
#include "net/third_party/quiche/src/quic/core/quic_process_packet_interface.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_epoll.h"
-#include "net/third_party/quiche/src/quic/tools/quic_spdy_client_base.h"
+#include "net/third_party/quiche/src/quic/tools/quic_client_base.h"
namespace quic {
diff --git a/quic/tools/quic_client_test.cc b/quic/tools/quic_client_test.cc
index 4f139b3..7977f05 100644
--- a/quic/tools/quic_client_test.cc
+++ b/quic/tools/quic_client_test.cc
@@ -4,13 +4,14 @@
#include "net/third_party/quiche/src/quic/tools/quic_client.h"
+#include <dirent.h>
+#include <sys/types.h>
+
#include <memory>
-#include "file/base/path.h"
-#include "file/util/linux_fileops.h"
-#include "gfe/gfe2/base/epoll_server.h"
-#include "net/util/netutil.h"
-#include "testing/base/public/test_utils.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_epoll.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_port_utils.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test_loopback.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
@@ -23,39 +24,44 @@
const char* kPathToFds = "/proc/self/fd";
+QuicString ReadLink(const QuicString& path) {
+ QuicString result(PATH_MAX, '\0');
+ ssize_t result_size = readlink(path.c_str(), &result[0], result.size());
+ CHECK(result_size > 0 && static_cast<size_t>(result_size) < result.size());
+ result.resize(result_size);
+ return result;
+}
+
// Counts the number of open sockets for the current process.
size_t NumOpenSocketFDs() {
- std::vector<QuicString> fd_entries;
- QuicString error_message;
-
- CHECK(file_util::LinuxFileOps::ListDirectoryEntries(kPathToFds, &fd_entries,
- &error_message));
-
size_t socket_count = 0;
- for (const QuicString& entry : fd_entries) {
- if (entry == "." || entry == "..") {
+ dirent* file;
+ std::unique_ptr<DIR, int (*)(DIR*)> fd_directory(opendir(kPathToFds),
+ closedir);
+ while ((file = readdir(fd_directory.get())) != nullptr) {
+ QuicStringPiece name(file->d_name);
+ if (name == "." || name == "..") {
continue;
}
- QuicString fd_path =
- file_util::LinuxFileOps::ReadLink(file::JoinPath(kPathToFds, entry));
+ QuicString fd_path = ReadLink(QuicStrCat(kPathToFds, "/", name));
if (QuicTextUtils::StartsWith(fd_path, "socket:")) {
socket_count++;
}
}
-
return socket_count;
}
// Creates a new QuicClient and Initializes it. Caller is responsible for
// deletion.
-QuicClient* CreateAndInitializeQuicClient(QuicEpollServer* eps, uint16_t port) {
+std::unique_ptr<QuicClient> CreateAndInitializeQuicClient(QuicEpollServer* eps,
+ uint16_t port) {
QuicSocketAddress server_address(QuicSocketAddress(TestLoopback(), port));
QuicServerId server_id("hostname", server_address.port(), false);
ParsedQuicVersionVector versions = AllSupportedVersions();
- QuicClient* client =
- new QuicClient(server_address, server_id, versions, eps,
- crypto_test_utils::ProofVerifierForTesting());
+ auto client =
+ QuicMakeUnique<QuicClient>(server_address, server_id, versions, eps,
+ crypto_test_utils::ProofVerifierForTesting());
EXPECT_TRUE(client->Initialize());
return client;
}
@@ -66,8 +72,12 @@
// Make sure that the QuicClient doesn't leak socket FDs. Doing so could cause
// port exhaustion in long running processes which repeatedly create clients.
- // Record initial number of FDs, after creation of EpollServer.
+ // Record initial number of FDs, after creating EpollServer and creating and
+ // destroying a single client (the latter is needed since initializing
+ // platform dependencies like certificate verifier may open a persistent
+ // socket).
QuicEpollServer eps;
+ CreateAndInitializeQuicClient(&eps, QuicPickUnusedPortOrDie());
size_t number_of_open_fds = NumOpenSocketFDs();
// Create a number of clients, initialize them, and verify this has resulted
@@ -75,7 +85,7 @@
const int kNumClients = 50;
for (int i = 0; i < kNumClients; ++i) {
std::unique_ptr<QuicClient> client(
- CreateAndInitializeQuicClient(&eps, net_util::PickUnusedPortOrDie()));
+ CreateAndInitializeQuicClient(&eps, QuicPickUnusedPortOrDie()));
// Initializing the client will create a new FD.
EXPECT_LT(number_of_open_fds, NumOpenSocketFDs());
@@ -90,7 +100,7 @@
size_t number_of_open_fds = NumOpenSocketFDs();
std::unique_ptr<QuicClient> client(
- CreateAndInitializeQuicClient(&eps, net_util::PickUnusedPortOrDie()));
+ CreateAndInitializeQuicClient(&eps, QuicPickUnusedPortOrDie()));
EXPECT_EQ(number_of_open_fds + 1, NumOpenSocketFDs());
// Create more UDP sockets.
EXPECT_TRUE(QuicClientPeer::CreateUDPSocketAndBind(client.get()));
diff --git a/quic/tools/quic_memory_cache_backend.h b/quic/tools/quic_memory_cache_backend.h
index 1bf9b7c..1417349 100644
--- a/quic/tools/quic_memory_cache_backend.h
+++ b/quic/tools/quic_memory_cache_backend.h
@@ -68,7 +68,6 @@
private:
QuicStringPiece host_;
QuicStringPiece path_;
- QuicMemoryCacheBackend* cache_;
};
QuicMemoryCacheBackend();
diff --git a/quic/tools/quic_memory_cache_backend_test.cc b/quic/tools/quic_memory_cache_backend_test.cc
index 8c621be..be5c374 100644
--- a/quic/tools/quic_memory_cache_backend_test.cc
+++ b/quic/tools/quic_memory_cache_backend_test.cc
@@ -16,7 +16,7 @@
namespace {
typedef QuicBackendResponse Response;
typedef QuicBackendResponse::ServerPushInfo ServerPushInfo;
-}; // namespace
+} // namespace
class QuicMemoryCacheBackendTest : public QuicTest {
protected:
diff --git a/quic/tools/quic_packet_printer_bin.cc b/quic/tools/quic_packet_printer_bin.cc
index 2900ce8..3dd7493 100644
--- a/quic/tools/quic_packet_printer_bin.cc
+++ b/quic/tools/quic_packet_printer_bin.cc
@@ -80,6 +80,9 @@
std::cerr << "OnPacketHeader\n";
return true;
}
+ void OnCoalescedPacket(const QuicEncryptedPacket& packet) override {
+ std::cerr << "OnCoalescedPacket\n";
+ }
bool OnStreamFrame(const QuicStreamFrame& frame) override {
std::cerr << "OnStreamFrame: " << frame;
std::cerr << " data: { "
diff --git a/quic/tools/quic_server.cc b/quic/tools/quic_server.cc
index eaec5d4..006098c 100644
--- a/quic/tools/quic_server.cc
+++ b/quic/tools/quic_server.cc
@@ -147,7 +147,7 @@
QuicDispatcher* QuicServer::CreateQuicDispatcher() {
QuicEpollAlarmFactory alarm_factory(&epoll_server_);
return new QuicSimpleDispatcher(
- config_, &crypto_config_, &version_manager_,
+ &config_, &crypto_config_, &version_manager_,
std::unique_ptr<QuicEpollConnectionHelper>(new QuicEpollConnectionHelper(
&epoll_server_, QuicAllocator::BUFFER_POOL)),
std::unique_ptr<QuicCryptoServerStream::Helper>(
diff --git a/quic/tools/quic_server_bin.cc b/quic/tools/quic_server_bin.cc
index c4c85d3..446d55e 100644
--- a/quic/tools/quic_server_bin.cc
+++ b/quic/tools/quic_server_bin.cc
@@ -5,6 +5,8 @@
// A binary wrapper for QuicServer. It listens forever on --port
// (default 6121) until it's killed or ctrl-cd to death.
+#include <vector>
+
#include "base/commandlineflags.h"
#include "base/init_google.h"
#include "net/httpsconnection/certificates.proto.h"
@@ -15,17 +17,28 @@
#include "net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h"
#include "net/third_party/quiche/src/quic/tools/quic_server.h"
-DEFINE_int32(port, 6121, "The port the quic server will listen on.");
-DEFINE_string(
+DEFINE_QUIC_COMMAND_LINE_FLAG(int32_t,
+ port,
+ 6121,
+ "The port the quic server will listen on.");
+
+DEFINE_QUIC_COMMAND_LINE_FLAG(
+ string,
certificate_dir,
"/google/src/head/depot/google3/net/third_party/quiche/src/quic/core/crypto/testdata",
"The directory containing certificate files.");
-DEFINE_string(intermediate_certificate_name,
- "intermediate.crt",
- "The name of the file containing the intermediate certificate.");
-DEFINE_string(leaf_certificate_name,
- "test.example.com",
- "The name of the file containing the leaf certificate.");
+
+DEFINE_QUIC_COMMAND_LINE_FLAG(
+ string,
+ intermediate_certificate_name,
+ "intermediate.crt",
+ "The name of the file containing the intermediate certificate.");
+
+DEFINE_QUIC_COMMAND_LINE_FLAG(
+ string,
+ leaf_certificate_name,
+ "test.example.com",
+ "The name of the file containing the leaf certificate.");
std::unique_ptr<quic::ProofSource> CreateProofSource(
const string& base_directory,
@@ -49,20 +62,28 @@
}
int main(int argc, char* argv[]) {
- InitGoogle(argv[0], &argc, &argv, true);
-
- quic::QuicMemoryCacheBackend memory_cache_backend;
- if (!FLAGS_quic_response_cache_dir.empty()) {
- memory_cache_backend.InitializeBackend(FLAGS_quic_response_cache_dir);
+ const char* usage = "Usage: quic_server [options]";
+ std::vector<quic::QuicString> non_option_args =
+ quic::QuicParseCommandLineFlags(usage, argc, argv);
+ if (!non_option_args.empty()) {
+ quic::QuicPrintCommandLineFlagHelp(usage);
+ exit(0);
}
- quic::QuicServer server(CreateProofSource(FLAGS_certificate_dir,
- FLAGS_intermediate_certificate_name,
- FLAGS_leaf_certificate_name),
- &memory_cache_backend);
+ quic::QuicMemoryCacheBackend memory_cache_backend;
+ if (!GetQuicFlag(FLAGS_quic_response_cache_dir).empty()) {
+ memory_cache_backend.InitializeBackend(
+ GetQuicFlag(FLAGS_quic_response_cache_dir));
+ }
- if (!server.CreateUDPSocketAndListen(
- quic::QuicSocketAddress(quic::QuicIpAddress::Any6(), FLAGS_port))) {
+ quic::QuicServer server(
+ CreateProofSource(GetQuicFlag(FLAGS_certificate_dir),
+ GetQuicFlag(FLAGS_intermediate_certificate_name),
+ GetQuicFlag(FLAGS_leaf_certificate_name)),
+ &memory_cache_backend);
+
+ if (!server.CreateUDPSocketAndListen(quic::QuicSocketAddress(
+ quic::QuicIpAddress::Any6(), GetQuicFlag(FLAGS_port)))) {
return 1;
}
diff --git a/quic/tools/quic_server_test.cc b/quic/tools/quic_server_test.cc
index f549ad4..7b5cd58 100644
--- a/quic/tools/quic_server_test.cc
+++ b/quic/tools/quic_server_test.cc
@@ -7,7 +7,6 @@
#include <string.h>
#include <sys/socket.h>
-#include "net/util/netutil.h"
#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
#include "net/third_party/quiche/src/quic/core/quic_epoll_alarm_factory.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
@@ -15,6 +14,7 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.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_port_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test_loopback.h"
@@ -35,7 +35,7 @@
class QuicServerTest : public QuicTest {};
TEST_F(QuicServerTest, TestDroppedPackets) {
- int port = net_util::PickUnusedPortOrDie();
+ int port = QuicPickUnusedPortOrDie();
QuicSocketAddress server_address(TestLoopback(), port);
QuicMemoryCacheBackend response_cache;
@@ -78,7 +78,7 @@
class MockQuicSimpleDispatcher : public QuicSimpleDispatcher {
public:
MockQuicSimpleDispatcher(
- const QuicConfig& config,
+ const QuicConfig* config,
const QuicCryptoServerConfig* crypto_config,
QuicVersionManager* version_manager,
std::unique_ptr<QuicConnectionHelperInterface> helper,
@@ -113,7 +113,7 @@
protected:
QuicDispatcher* CreateQuicDispatcher() override {
mock_dispatcher_ = new MockQuicSimpleDispatcher(
- config(), &crypto_config(), version_manager(),
+ &config(), &crypto_config(), version_manager(),
std::unique_ptr<QuicEpollConnectionHelper>(
new QuicEpollConnectionHelper(epoll_server(),
QuicAllocator::BUFFER_POOL)),
@@ -132,7 +132,7 @@
class QuicServerEpollInTest : public QuicTest {
public:
QuicServerEpollInTest()
- : port_(net_util::PickUnusedPortOrDie()),
+ : port_(QuicPickUnusedPortOrDie()),
server_address_(TestLoopback(), port_) {}
void StartListening() {
@@ -203,7 +203,7 @@
TlsServerHandshaker::CreateSslCtx()),
version_manager_(AllSupportedVersions()),
dispatcher_(
- config_,
+ &config_,
&crypto_config_,
&version_manager_,
std::unique_ptr<QuicEpollConnectionHelper>(
diff --git a/quic/tools/quic_simple_crypto_server_stream_helper.cc b/quic/tools/quic_simple_crypto_server_stream_helper.cc
index 567c670..bdd6731 100644
--- a/quic/tools/quic_simple_crypto_server_stream_helper.cc
+++ b/quic/tools/quic_simple_crypto_server_stream_helper.cc
@@ -19,7 +19,7 @@
QuicSimpleCryptoServerStreamHelper::GenerateConnectionIdForReject(
QuicTransportVersion /*version*/,
QuicConnectionId /*connection_id*/) const {
- return QuicUtils::CreateRandomConnectionId(random_, Perspective::IS_SERVER);
+ return QuicUtils::CreateRandomConnectionId(random_);
}
bool QuicSimpleCryptoServerStreamHelper::CanAcceptClientHello(
@@ -27,7 +27,7 @@
const QuicSocketAddress& client_address,
const QuicSocketAddress& peer_address,
const QuicSocketAddress& self_address,
- string* error_details) const {
+ QuicString* error_details) const {
return true;
}
diff --git a/quic/tools/quic_simple_crypto_server_stream_helper_test.cc b/quic/tools/quic_simple_crypto_server_stream_helper_test.cc
index 652f282..4ede588 100644
--- a/quic/tools/quic_simple_crypto_server_stream_helper_test.cc
+++ b/quic/tools/quic_simple_crypto_server_stream_helper_test.cc
@@ -1,3 +1,7 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
#include "net/third_party/quiche/src/quic/tools/quic_simple_crypto_server_stream_helper.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
@@ -14,10 +18,6 @@
QuicSimpleCryptoServerStreamHelper helper(&random);
EXPECT_EQ(QuicUtils::CreateRandomConnectionId(&random),
- helper.GenerateConnectionIdForReject(QUIC_VERSION_35,
- test::TestConnectionId()));
-
- EXPECT_EQ(QuicUtils::CreateRandomConnectionId(&random),
helper.GenerateConnectionIdForReject(QUIC_VERSION_99,
test::TestConnectionId()));
}
diff --git a/quic/tools/quic_simple_dispatcher.cc b/quic/tools/quic_simple_dispatcher.cc
index 166dd0b..942eb0a 100644
--- a/quic/tools/quic_simple_dispatcher.cc
+++ b/quic/tools/quic_simple_dispatcher.cc
@@ -9,7 +9,7 @@
namespace quic {
QuicSimpleDispatcher::QuicSimpleDispatcher(
- const QuicConfig& config,
+ const QuicConfig* config,
const QuicCryptoServerConfig* crypto_config,
QuicVersionManager* version_manager,
std::unique_ptr<QuicConnectionHelperInterface> helper,
diff --git a/quic/tools/quic_simple_dispatcher.h b/quic/tools/quic_simple_dispatcher.h
index 3ee8c0e..6f13d39 100644
--- a/quic/tools/quic_simple_dispatcher.h
+++ b/quic/tools/quic_simple_dispatcher.h
@@ -14,7 +14,7 @@
class QuicSimpleDispatcher : public QuicDispatcher {
public:
QuicSimpleDispatcher(
- const QuicConfig& config,
+ const QuicConfig* config,
const QuicCryptoServerConfig* crypto_config,
QuicVersionManager* version_manager,
std::unique_ptr<QuicConnectionHelperInterface> helper,
diff --git a/quic/tools/quic_simple_server_session.h b/quic/tools/quic_simple_server_session.h
index d459da6..45c97d0 100644
--- a/quic/tools/quic_simple_server_session.h
+++ b/quic/tools/quic_simple_server_session.h
@@ -7,7 +7,10 @@
#ifndef QUICHE_QUIC_TOOLS_QUIC_SIMPLE_SERVER_SESSION_H_
#define QUICHE_QUIC_TOOLS_QUIC_SIMPLE_SERVER_SESSION_H_
+#include <stdint.h>
+
#include <list>
+#include <memory>
#include <set>
#include <string>
#include <utility>
diff --git a/quic/tools/quic_simple_server_session_test.cc b/quic/tools/quic_simple_server_session_test.cc
index 1ba330d..832a611 100644
--- a/quic/tools/quic_simple_server_session_test.cc
+++ b/quic/tools/quic_simple_server_session_test.cc
@@ -40,6 +40,7 @@
using testing::_;
using testing::AtLeast;
using testing::InSequence;
+using testing::Invoke;
using testing::Return;
using testing::StrictMock;
@@ -119,7 +120,15 @@
: MockQuicConnection(helper,
alarm_factory,
perspective,
- supported_versions) {}
+ supported_versions) {
+ auto consume_all_data = [](QuicStreamId id, size_t write_length,
+ QuicStreamOffset offset,
+ StreamSendingState state) {
+ return QuicConsumedData(write_length, state != NO_FIN);
+ };
+ ON_CALL(*this, SendStreamData(_, _, _, _))
+ .WillByDefault(Invoke(consume_all_data));
+ }
MOCK_METHOD4(SendStreamData,
QuicConsumedData(QuicStreamId id,
@@ -159,22 +168,6 @@
QuicStreamId promised_stream_id,
const spdy::SpdyHeaderBlock& headers));
- size_t WriteHeaders(QuicStreamId stream_id,
- spdy::SpdyHeaderBlock headers,
- bool fin,
- spdy::SpdyPriority priority,
- QuicReferenceCountedPointer<QuicAckListenerInterface>
- ack_listener) override {
- return WriteHeadersMock(stream_id, headers, fin, priority, ack_listener);
- }
- MOCK_METHOD5(
- WriteHeadersMock,
- size_t(QuicStreamId stream_id,
- const spdy::SpdyHeaderBlock& headers,
- bool fin,
- spdy::SpdyPriority priority,
- const QuicReferenceCountedPointer<QuicAckListenerInterface>&
- ack_listener));
MOCK_METHOD1(SendBlocked, void(QuicStreamId));
};
@@ -232,7 +225,7 @@
->OnSuccessfulVersionNegotiation(supported_versions.front());
visitor_ = QuicConnectionPeer::GetVisitor(connection_);
- if (connection_->transport_version() == QUIC_VERSION_99) {
+ if (IsVersion99()) {
EXPECT_CALL(*connection_, SendControlFrame(_))
.WillRepeatedly(Invoke(
this,
@@ -242,13 +235,17 @@
}
QuicStreamId GetNthClientInitiatedBidirectionalId(int n) {
- return QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId(
- *session_, n);
+ return GetNthClientInitiatedBidirectionalStreamId(
+ connection_->transport_version(), n);
}
QuicStreamId GetNthServerInitiatedUnidirectionalId(int n) {
- return QuicSpdySessionPeer::GetNthServerInitiatedUnidirectionalStreamId(
- *session_, n);
+ return quic::test::GetNthServerInitiatedUnidirectionalStreamId(
+ connection_->transport_version(), n);
+ }
+
+ bool IsVersion99() const {
+ return connection_->transport_version() == QUIC_VERSION_99;
}
void InjectStopSending(QuicStreamId stream_id,
@@ -256,7 +253,7 @@
// Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
// RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes
// a one-way close.
- if (connection_->transport_version() != QUIC_VERSION_99) {
+ if (!IsVersion99()) {
// Only needed for version 99/IETF QUIC.
return;
}
@@ -284,9 +281,9 @@
QuicConnectionVisitorInterface* visitor_;
};
-INSTANTIATE_TEST_CASE_P(Tests,
- QuicSimpleServerSessionTest,
- ::testing::ValuesIn(AllSupportedVersions()));
+INSTANTIATE_TEST_SUITE_P(Tests,
+ QuicSimpleServerSessionTest,
+ ::testing::ValuesIn(AllSupportedVersions()));
TEST_P(QuicSimpleServerSessionTest, CloseStreamDueToReset) {
// Open a stream, then reset it.
@@ -302,9 +299,12 @@
QUIC_ERROR_PROCESSING_STREAM, 0);
EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
EXPECT_CALL(*connection_, SendControlFrame(_));
- EXPECT_CALL(*connection_,
- OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
- QUIC_RST_ACKNOWLEDGEMENT));
+ if (!IsVersion99()) {
+ // For version 99, this is covered in InjectStopSending()
+ EXPECT_CALL(*connection_,
+ OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
+ QUIC_RST_ACKNOWLEDGEMENT));
+ }
visitor_->OnRstStream(rst1);
// Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
// RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes
@@ -327,12 +327,13 @@
GetNthClientInitiatedBidirectionalId(0),
QUIC_ERROR_PROCESSING_STREAM, 0);
EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
- if (connection_->transport_version() != QUIC_VERSION_99) {
+ if (!IsVersion99()) {
EXPECT_CALL(*connection_, SendControlFrame(_));
+ // For version 99, this is covered in InjectStopSending()
+ EXPECT_CALL(*connection_,
+ OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
+ QUIC_RST_ACKNOWLEDGEMENT));
}
- EXPECT_CALL(*connection_,
- OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
- QUIC_RST_ACKNOWLEDGEMENT));
visitor_->OnRstStream(rst1);
// Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
// RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes
@@ -367,12 +368,13 @@
GetNthClientInitiatedBidirectionalId(0),
QUIC_ERROR_PROCESSING_STREAM, 0);
EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
- if (connection_->transport_version() != QUIC_VERSION_99) {
+ if (!IsVersion99()) {
EXPECT_CALL(*connection_, SendControlFrame(_));
+ // For version 99, this is covered in InjectStopSending()
+ EXPECT_CALL(*connection_,
+ OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
+ QUIC_RST_ACKNOWLEDGEMENT));
}
- EXPECT_CALL(*connection_,
- OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
- QUIC_RST_ACKNOWLEDGEMENT));
visitor_->OnRstStream(rst);
// Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
// RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes
@@ -541,7 +543,7 @@
protected:
const size_t kStreamFlowControlWindowSize = 32 * 1024; // 32KB.
- QuicSimpleServerSessionServerPushTest() : QuicSimpleServerSessionTest() {
+ QuicSimpleServerSessionServerPushTest() {
// Reset stream level flow control window to be 32KB.
QuicConfigPeer::SetReceivedInitialStreamFlowControlWindow(
&config_, kStreamFlowControlWindowSize);
@@ -550,10 +552,6 @@
// control blocks it.
QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow(
&config_, kInitialSessionFlowControlWindowForTest);
- // Enable server push.
- QuicTagVector copt;
- copt.push_back(kSPSH);
- QuicConfigPeer::SetReceivedConnectionOptions(&config_, copt);
ParsedQuicVersionVector supported_versions = SupportedVersions(GetParam());
connection_ = new StrictMock<MockQuicConnectionWithSendStreamData>(
@@ -566,7 +564,7 @@
->OnSuccessfulVersionNegotiation(supported_versions.front());
// Needed to make new session flow control window and server push work.
- if (connection_->transport_version() == QUIC_VERSION_99) {
+ if (IsVersion99()) {
EXPECT_CALL(*connection_, SendControlFrame(_))
.WillRepeatedly(Invoke(this, &QuicSimpleServerSessionServerPushTest::
ClearMaxStreamIdControlFrame));
@@ -619,7 +617,7 @@
QuicString body(body_size, 'a');
QuicString data;
header_length = 0;
- if (connection_->transport_version() == QUIC_VERSION_99) {
+ if (VersionHasDataFrameHeader(connection_->transport_version())) {
HttpEncoder encoder;
std::unique_ptr<char[]> buffer;
header_length =
@@ -640,14 +638,11 @@
stream_id, _));
if (i <= kMaxStreamsForTest) {
// |kMaxStreamsForTest| promised responses should be sent.
- EXPECT_CALL(*session_,
- WriteHeadersMock(stream_id, _, false,
- QuicStream::kDefaultPriority, _));
// Since flow control window is smaller than response body, not the
// whole body will be sent.
- if (connection_->transport_version() == QUIC_VERSION_99) {
- EXPECT_CALL(*connection_, SendStreamData(stream_id, _, 0, NO_FIN))
- .WillOnce(Return(QuicConsumedData(header_length, false)));
+ if (VersionHasDataFrameHeader(connection_->transport_version())) {
+ EXPECT_CALL(*connection_,
+ SendStreamData(stream_id, header_length, 0, NO_FIN));
}
EXPECT_CALL(*connection_,
SendStreamData(stream_id, _, header_length, NO_FIN))
@@ -661,26 +656,34 @@
request_headers);
return header_length;
}
+
+ void ConsumeHeadersStreamData() {
+ QuicStreamId headers_stream_id =
+ QuicUtils::GetHeadersStreamId(connection_->transport_version());
+ EXPECT_CALL(*connection_, SendStreamData(headers_stream_id, _, _, _))
+ .Times(AtLeast(1));
+ }
};
-INSTANTIATE_TEST_CASE_P(Tests,
- QuicSimpleServerSessionServerPushTest,
- ::testing::ValuesIn(AllSupportedVersions()));
+INSTANTIATE_TEST_SUITE_P(Tests,
+ QuicSimpleServerSessionServerPushTest,
+ ::testing::ValuesIn(AllSupportedVersions()));
+// Tests that given more than kMaxStreamsForTest resources, all their
+// PUSH_PROMISE's will be sent out and only kMaxStreamsForTest streams will be
+// opened and send push response.
TEST_P(QuicSimpleServerSessionServerPushTest, TestPromisePushResources) {
- // Tests that given more than kMaxOpenStreamForTest resources, all their
- // PUSH_PROMISE's will be sent out and only |kMaxOpenStreamForTest| streams
- // will be opened and send push response.
-
+ ConsumeHeadersStreamData();
size_t num_resources = kMaxStreamsForTest + 5;
PromisePushResources(num_resources);
EXPECT_EQ(kMaxStreamsForTest, session_->GetNumOpenOutgoingStreams());
}
+// Tests that after promised stream queued up, when an opened stream is marked
+// draining, a queued promised stream will become open and send push response.
TEST_P(QuicSimpleServerSessionServerPushTest,
HandlePromisedPushRequestsAfterStreamDraining) {
- // Tests that after promised stream queued up, when an opened stream is marked
- // draining, a queued promised stream will become open and send push response.
+ ConsumeHeadersStreamData();
size_t num_resources = kMaxStreamsForTest + 1;
QuicByteCount header_length = PromisePushResources(num_resources);
QuicStreamId next_out_going_stream_id =
@@ -688,12 +691,9 @@
// After an open stream is marked draining, a new stream is expected to be
// created and a response sent on the stream.
- EXPECT_CALL(*session_, WriteHeadersMock(next_out_going_stream_id, _, false,
- QuicStream::kDefaultPriority, _));
- if (connection_->transport_version() == QUIC_VERSION_99) {
- EXPECT_CALL(*connection_,
- SendStreamData(next_out_going_stream_id, _, 0, NO_FIN))
- .WillOnce(Return(QuicConsumedData(header_length, false)));
+ if (VersionHasDataFrameHeader(connection_->transport_version())) {
+ EXPECT_CALL(*connection_, SendStreamData(next_out_going_stream_id,
+ header_length, 0, NO_FIN));
}
EXPECT_CALL(*connection_, SendStreamData(next_out_going_stream_id, _,
header_length, NO_FIN))
@@ -701,7 +701,7 @@
kStreamFlowControlWindowSize - header_length, false)));
EXPECT_CALL(*session_, SendBlocked(next_out_going_stream_id));
- if (connection_->transport_version() == QUIC_VERSION_99) {
+ if (IsVersion99()) {
// The PromisePushedResources call, above, will have used all available
// stream ids. For version 99, stream ids are not made available until
// a MAX_STREAM_ID frame is received. This emulates the reception of one.
@@ -716,15 +716,16 @@
EXPECT_EQ(kMaxStreamsForTest, session_->GetNumOpenOutgoingStreams());
}
+// Tests that after all resources are promised, a RST frame from client can
+// prevent a promised resource to be send out.
TEST_P(QuicSimpleServerSessionServerPushTest,
ResetPromisedStreamToCancelServerPush) {
- // Tests that after all resources are promised, a RST frame from client can
- // prevent a promised resource to be send out.
+ ConsumeHeadersStreamData();
// Having two extra resources to be send later. One of them will be reset, so
// when opened stream become close, only one will become open.
size_t num_resources = kMaxStreamsForTest + 2;
- if (connection_->transport_version() == QUIC_VERSION_99) {
+ if (IsVersion99()) {
// V99 will send out a stream-id-blocked frame when the we desired to exceed
// the limit. This will clear the frames so that they do not block the later
// rst-stream frame.
@@ -753,22 +754,17 @@
QuicStreamId stream_not_reset =
GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest);
InSequence s;
- EXPECT_CALL(*session_, WriteHeadersMock(stream_not_reset, _, false,
- QuicStream::kDefaultPriority, _));
- if (connection_->transport_version() == QUIC_VERSION_99) {
- EXPECT_CALL(*connection_, SendStreamData(stream_not_reset, _, 0, NO_FIN))
- .WillOnce(Return(QuicConsumedData(header_length, false)));
+ if (VersionHasDataFrameHeader(connection_->transport_version())) {
+ EXPECT_CALL(*connection_,
+ SendStreamData(stream_not_reset, header_length, 0, NO_FIN));
}
EXPECT_CALL(*connection_,
SendStreamData(stream_not_reset, _, header_length, NO_FIN))
.WillOnce(Return(QuicConsumedData(
kStreamFlowControlWindowSize - header_length, false)));
EXPECT_CALL(*session_, SendBlocked(stream_not_reset));
- EXPECT_CALL(*session_, WriteHeadersMock(stream_got_reset, _, false,
- QuicStream::kDefaultPriority, _))
- .Times(0);
- if (connection_->transport_version() == QUIC_VERSION_99) {
+ if (IsVersion99()) {
// The PromisePushedResources call, above, will have used all available
// stream ids. For version 99, stream ids are not made available until
// a MAX_STREAM_ID frame is received. This emulates the reception of one.
@@ -781,12 +777,13 @@
session_->StreamDraining(GetNthServerInitiatedUnidirectionalId(1));
}
+// Tests that closing a open outgoing stream can trigger a promised resource in
+// the queue to be send out.
TEST_P(QuicSimpleServerSessionServerPushTest,
CloseStreamToHandleMorePromisedStream) {
- // Tests that closing a open outgoing stream can trigger a promised resource
- // in the queue to be send out.
+ ConsumeHeadersStreamData();
size_t num_resources = kMaxStreamsForTest + 1;
- if (connection_->transport_version() == QUIC_VERSION_99) {
+ if (IsVersion99()) {
// V99 will send out a stream-id-blocked frame when the we desired to exceed
// the limit. This will clear the frames so that they do not block the later
// rst-stream frame.
@@ -803,13 +800,14 @@
QuicStreamId stream_got_reset = GetNthServerInitiatedUnidirectionalId(0);
EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
EXPECT_CALL(*connection_, SendControlFrame(_));
- EXPECT_CALL(*connection_,
- OnStreamReset(stream_got_reset, QUIC_RST_ACKNOWLEDGEMENT));
- EXPECT_CALL(*session_, WriteHeadersMock(stream_to_open, _, false,
- QuicStream::kDefaultPriority, _));
- if (connection_->transport_version() == QUIC_VERSION_99) {
- EXPECT_CALL(*connection_, SendStreamData(stream_to_open, _, 0, NO_FIN))
- .WillOnce(Return(QuicConsumedData(header_length, false)));
+ if (!IsVersion99()) {
+ // For version 99, this is covered in InjectStopSending()
+ EXPECT_CALL(*connection_,
+ OnStreamReset(stream_got_reset, QUIC_RST_ACKNOWLEDGEMENT));
+ }
+ if (VersionHasDataFrameHeader(connection_->transport_version())) {
+ EXPECT_CALL(*connection_,
+ SendStreamData(stream_to_open, header_length, 0, NO_FIN));
}
EXPECT_CALL(*connection_,
SendStreamData(stream_to_open, _, header_length, NO_FIN))
@@ -819,7 +817,7 @@
EXPECT_CALL(*session_, SendBlocked(stream_to_open));
QuicRstStreamFrame rst(kInvalidControlFrameId, stream_got_reset,
QUIC_STREAM_CANCELLED, 0);
- if (connection_->transport_version() == QUIC_VERSION_99) {
+ if (IsVersion99()) {
// The PromisePushedResources call, above, will have used all available
// stream ids. For version 99, stream ids are not made available until
// a MAX_STREAM_ID frame is received. This emulates the reception of one.
diff --git a/quic/tools/quic_simple_server_stream.cc b/quic/tools/quic_simple_server_stream.cc
index 1f70a8a..2ae2dbf 100644
--- a/quic/tools/quic_simple_server_stream.cc
+++ b/quic/tools/quic_simple_server_stream.cc
@@ -291,7 +291,7 @@
QUIC_DLOG(INFO) << "Stream " << id()
<< " writing body (fin = false) with size: " << body.size();
if (!body.empty()) {
- WriteOrBufferBody(body, /*fin=*/false, nullptr);
+ WriteOrBufferBody(body, /*fin=*/false);
}
}
@@ -321,7 +321,7 @@
QUIC_DLOG(INFO) << "Stream " << id() << " writing body (fin = " << send_fin
<< ") with size: " << body.size();
if (!body.empty() || send_fin) {
- WriteOrBufferBody(body, send_fin, nullptr);
+ WriteOrBufferBody(body, send_fin);
}
if (send_fin) {
// Nothing else to send.
diff --git a/quic/tools/quic_simple_server_stream.h b/quic/tools/quic_simple_server_stream.h
index 8939a2c..2e6826f 100644
--- a/quic/tools/quic_simple_server_stream.h
+++ b/quic/tools/quic_simple_server_stream.h
@@ -15,10 +15,6 @@
namespace quic {
-namespace test {
-class QuicSimpleServerStreamPeer;
-} // namespace test
-
// All this does right now is aggregate data, and on fin, send an HTTP
// response.
class QuicSimpleServerStream : public QuicSpdyServerStreamBase,
@@ -93,14 +89,12 @@
const QuicString& body() { return body_; }
- private:
- friend class test::QuicSimpleServerStreamPeer;
-
// The parsed headers received from the client.
spdy::SpdyHeaderBlock request_headers_;
int64_t content_length_;
QuicString body_;
+ private:
QuicSimpleServerBackend* quic_simple_server_backend_; // Not owned.
};
diff --git a/quic/tools/quic_simple_server_stream_test.cc b/quic/tools/quic_simple_server_stream_test.cc
index 4e9e68d..a13c9a2 100644
--- a/quic/tools/quic_simple_server_stream_test.cc
+++ b/quic/tools/quic_simple_server_stream_test.cc
@@ -32,50 +32,51 @@
using testing::Invoke;
using testing::Return;
using testing::StrictMock;
+using testing::ValuesIn;
namespace quic {
namespace test {
-size_t kFakeFrameLen = 60;
+const size_t kFakeFrameLen = 60;
+const size_t kErrorLength = strlen(QuicSimpleServerStream::kErrorResponseBody);
+const size_t kDataFrameHeaderLength = 2;
-class QuicSimpleServerStreamPeer : public QuicSimpleServerStream {
+class TestStream : public QuicSimpleServerStream {
public:
- QuicSimpleServerStreamPeer(
- QuicStreamId stream_id,
- QuicSpdySession* session,
- StreamType type,
- QuicSimpleServerBackend* quic_simple_server_backend)
+ TestStream(QuicStreamId stream_id,
+ QuicSpdySession* session,
+ StreamType type,
+ QuicSimpleServerBackend* quic_simple_server_backend)
: QuicSimpleServerStream(stream_id,
session,
type,
quic_simple_server_backend) {}
- ~QuicSimpleServerStreamPeer() override = default;
+ ~TestStream() override = default;
- using QuicSimpleServerStream::SendErrorResponse;
- using QuicSimpleServerStream::SendResponse;
+ MOCK_METHOD1(WriteHeadersMock, void(bool fin));
+
+ size_t WriteHeaders(spdy::SpdyHeaderBlock header_block,
+ bool fin,
+ QuicReferenceCountedPointer<QuicAckListenerInterface>
+ ack_listener) override {
+ WriteHeadersMock(fin);
+ return 0;
+ }
+
+ // Expose protected QuicSimpleServerStream methods.
+ void DoSendResponse() { SendResponse(); }
+ void DoSendErrorResponse() { SendErrorResponse(); }
spdy::SpdyHeaderBlock* mutable_headers() { return &request_headers_; }
void set_body(QuicString body) { body_ = std::move(body); }
+ const QuicString& body() const { return body_; }
+ int content_length() const { return content_length_; }
- static void SendResponse(QuicSimpleServerStream* stream) {
- stream->SendResponse();
- }
-
- static void SendErrorResponse(QuicSimpleServerStream* stream) {
- stream->SendErrorResponse();
- }
-
- static const QuicString& body(QuicSimpleServerStream* stream) {
- return stream->body_;
- }
-
- static int content_length(QuicSimpleServerStream* stream) {
- return stream->content_length_;
- }
-
- static spdy::SpdyHeaderBlock& headers(QuicSimpleServerStream* stream) {
- return stream->request_headers_;
+ QuicStringPiece GetHeader(QuicStringPiece key) const {
+ auto it = request_headers_.find(key);
+ DCHECK(it != request_headers_.end());
+ return it->second;
}
};
@@ -85,7 +86,7 @@
public:
const size_t kMaxStreamsForTest = 100;
- explicit MockQuicSimpleServerSession(
+ MockQuicSimpleServerSession(
QuicConnection* connection,
MockQuicSessionVisitor* owner,
MockQuicCryptoServerStreamHelper* helper,
@@ -103,7 +104,7 @@
QuicSessionPeer::SetMaxOpenIncomingStreams(this, kMaxStreamsForTest);
QuicSessionPeer::SetMaxOpenOutgoingStreams(this, kMaxStreamsForTest);
ON_CALL(*this, WritevData(_, _, _, _, _))
- .WillByDefault(testing::Return(QuicConsumedData(0, false)));
+ .WillByDefault(Invoke(MockQuicSession::ConsumeData));
}
MockQuicSimpleServerSession(const MockQuicSimpleServerSession&) = delete;
@@ -129,24 +130,6 @@
const QuicHeaderList& header_list));
MOCK_METHOD2(OnStreamHeadersPriority,
void(QuicStreamId stream_id, spdy::SpdyPriority priority));
- // Methods taking non-copyable types like SpdyHeaderBlock by value cannot be
- // mocked directly.
- size_t WriteHeaders(QuicStreamId id,
- spdy::SpdyHeaderBlock headers,
- bool fin,
- spdy::SpdyPriority priority,
- QuicReferenceCountedPointer<QuicAckListenerInterface>
- ack_listener) override {
- return WriteHeadersMock(id, headers, fin, priority, ack_listener);
- }
- MOCK_METHOD5(
- WriteHeadersMock,
- size_t(QuicStreamId id,
- const spdy::SpdyHeaderBlock& headers,
- bool fin,
- spdy::SpdyPriority priority,
- const QuicReferenceCountedPointer<QuicAckListenerInterface>&
- ack_listener));
MOCK_METHOD3(SendRstStream,
void(QuicStreamId stream_id,
QuicRstStreamErrorCode error,
@@ -198,8 +181,7 @@
&compressed_certs_cache_,
&memory_cache_backend_),
quic_response_(new QuicBackendResponse),
- body_("hello world"),
- is_version_99_(connection_->transport_version() == QUIC_VERSION_99) {
+ body_("hello world") {
connection_->set_visitor(&session_);
header_list_.OnHeaderBlockStart();
header_list_.OnHeader(":authority", "www.google.com");
@@ -216,23 +198,29 @@
kInitialStreamFlowControlWindowForTest);
session_.config()->SetInitialSessionFlowControlWindowToSend(
kInitialSessionFlowControlWindowForTest);
- stream_ = new QuicSimpleServerStreamPeer(
- QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId(
- session_, 0),
+ stream_ = new StrictMock<TestStream>(
+ GetNthClientInitiatedBidirectionalStreamId(
+ connection_->transport_version(), 0),
&session_, BIDIRECTIONAL, &memory_cache_backend_);
// Register stream_ in dynamic_stream_map_ and pass ownership to session_.
session_.ActivateStream(QuicWrapUnique(stream_));
connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
}
- const QuicString& StreamBody() {
- return QuicSimpleServerStreamPeer::body(stream_);
- }
+ const QuicString& StreamBody() { return stream_->body(); }
QuicString StreamHeadersValue(const QuicString& key) {
return (*stream_->mutable_headers())[key].as_string();
}
+ bool IsVersion99() const {
+ return connection_->transport_version() == QUIC_VERSION_99;
+ }
+
+ bool HasFrameHeader() const {
+ return VersionHasDataFrameHeader(connection_->transport_version());
+ }
+
spdy::SpdyHeaderBlock response_headers_;
MockQuicConnectionHelper helper_;
MockAlarmFactory alarm_factory_;
@@ -243,28 +231,26 @@
QuicCompressedCertsCache compressed_certs_cache_;
QuicMemoryCacheBackend memory_cache_backend_;
StrictMock<MockQuicSimpleServerSession> session_;
- QuicSimpleServerStreamPeer* stream_; // Owned by session_.
+ StrictMock<TestStream>* stream_; // Owned by session_.
std::unique_ptr<QuicBackendResponse> quic_response_;
QuicString body_;
QuicHeaderList header_list_;
HttpEncoder encoder_;
- bool is_version_99_;
};
-INSTANTIATE_TEST_CASE_P(Tests,
- QuicSimpleServerStreamTest,
- ::testing::ValuesIn(AllSupportedVersions()));
+INSTANTIATE_TEST_SUITE_P(Tests,
+ QuicSimpleServerStreamTest,
+ ValuesIn(AllSupportedVersions()));
TEST_P(QuicSimpleServerStreamTest, TestFraming) {
EXPECT_CALL(session_, WritevData(_, _, _, _, _))
- .Times(AnyNumber())
.WillRepeatedly(Invoke(MockQuicSession::ConsumeData));
stream_->OnStreamHeaderList(false, kFakeFrameLen, header_list_);
std::unique_ptr<char[]> buffer;
QuicByteCount header_length =
encoder_.SerializeDataFrameHeader(body_.length(), &buffer);
QuicString header = QuicString(buffer.get(), header_length);
- QuicString data = is_version_99_ ? header + body_ : body_;
+ QuicString data = HasFrameHeader() ? header + body_ : body_;
stream_->OnStreamFrame(
QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, data));
EXPECT_EQ("11", StreamHeadersValue("content-length"));
@@ -275,7 +261,6 @@
TEST_P(QuicSimpleServerStreamTest, TestFramingOnePacket) {
EXPECT_CALL(session_, WritevData(_, _, _, _, _))
- .Times(AnyNumber())
.WillRepeatedly(Invoke(MockQuicSession::ConsumeData));
stream_->OnStreamHeaderList(false, kFakeFrameLen, header_list_);
@@ -283,7 +268,7 @@
QuicByteCount header_length =
encoder_.SerializeDataFrameHeader(body_.length(), &buffer);
QuicString header = QuicString(buffer.get(), header_length);
- QuicString data = is_version_99_ ? header + body_ : body_;
+ QuicString data = HasFrameHeader() ? header + body_ : body_;
stream_->OnStreamFrame(
QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, data));
EXPECT_EQ("11", StreamHeadersValue("content-length"));
@@ -294,7 +279,6 @@
TEST_P(QuicSimpleServerStreamTest, SendQuicRstStreamNoErrorInStopReading) {
EXPECT_CALL(session_, WritevData(_, _, _, _, _))
- .Times(AnyNumber())
.WillRepeatedly(Invoke(MockQuicSession::ConsumeData));
EXPECT_FALSE(stream_->fin_received());
@@ -308,18 +292,16 @@
}
TEST_P(QuicSimpleServerStreamTest, TestFramingExtraData) {
- testing::InSequence seq;
+ InSequence seq;
QuicString large_body = "hello world!!!!!!";
// We'll automatically write out an error (headers + body)
- EXPECT_CALL(session_, WriteHeadersMock(_, _, _, _, _));
- if (is_version_99_) {
- EXPECT_CALL(session_, WritevData(_, _, _, _, _))
- .WillOnce(Invoke(MockQuicSession::ConsumeData));
+ EXPECT_CALL(*stream_, WriteHeadersMock(false));
+ if (HasFrameHeader()) {
+ EXPECT_CALL(session_, WritevData(_, _, kDataFrameHeaderLength, _, NO_FIN));
}
+ EXPECT_CALL(session_, WritevData(_, _, kErrorLength, _, FIN));
- EXPECT_CALL(session_, WritevData(_, _, _, _, _))
- .WillOnce(Invoke(MockQuicSession::ConsumeData));
EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0);
stream_->OnStreamHeaderList(false, kFakeFrameLen, header_list_);
@@ -327,7 +309,7 @@
QuicByteCount header_length =
encoder_.SerializeDataFrameHeader(body_.length(), &buffer);
QuicString header = QuicString(buffer.get(), header_length);
- QuicString data = is_version_99_ ? header + body_ : body_;
+ QuicString data = HasFrameHeader() ? header + body_ : body_;
stream_->OnStreamFrame(
QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, data));
@@ -336,7 +318,7 @@
header_length =
encoder_.SerializeDataFrameHeader(large_body.length(), &buffer);
header = QuicString(buffer.get(), header_length);
- QuicString data2 = is_version_99_ ? header + large_body : large_body;
+ QuicString data2 = HasFrameHeader() ? header + large_body : large_body;
stream_->OnStreamFrame(
QuicStreamFrame(stream_->id(), /*fin=*/true, data.size(), data2));
EXPECT_EQ("11", StreamHeadersValue("content-length"));
@@ -367,18 +349,13 @@
stream_->set_fin_received(true);
InSequence s;
- EXPECT_CALL(session_, WriteHeadersMock(stream_->id(), _, false, _, _));
- if (is_version_99_) {
- EXPECT_CALL(session_, WritevData(_, _, _, _, _))
- .Times(1)
- .WillOnce(Return(QuicConsumedData(header_length, false)));
+ EXPECT_CALL(*stream_, WriteHeadersMock(false));
+ if (HasFrameHeader()) {
+ EXPECT_CALL(session_, WritevData(_, _, header_length, _, NO_FIN));
}
- EXPECT_CALL(session_, WritevData(_, _, _, _, _))
- .Times(1)
- .WillOnce(Return(QuicConsumedData(
- strlen(QuicSimpleServerStream::kErrorResponseBody), true)));
+ EXPECT_CALL(session_, WritevData(_, _, kErrorLength, _, FIN));
- QuicSimpleServerStreamPeer::SendResponse(stream_);
+ stream_->DoSendResponse();
EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
EXPECT_TRUE(stream_->write_side_closed());
}
@@ -407,27 +384,22 @@
stream_->set_fin_received(true);
InSequence s;
- EXPECT_CALL(session_, WriteHeadersMock(stream_->id(), _, false, _, _));
- if (is_version_99_) {
- EXPECT_CALL(session_, WritevData(_, _, _, _, _))
- .Times(1)
- .WillOnce(Return(QuicConsumedData(header_length, false)));
+ EXPECT_CALL(*stream_, WriteHeadersMock(false));
+ if (HasFrameHeader()) {
+ EXPECT_CALL(session_, WritevData(_, _, header_length, _, NO_FIN));
}
- EXPECT_CALL(session_, WritevData(_, _, _, _, _))
- .Times(1)
- .WillOnce(Return(QuicConsumedData(
- strlen(QuicSimpleServerStream::kErrorResponseBody), true)));
+ EXPECT_CALL(session_, WritevData(_, _, kErrorLength, _, FIN));
- QuicSimpleServerStreamPeer::SendResponse(stream_);
+ stream_->DoSendResponse();
EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
EXPECT_TRUE(stream_->write_side_closed());
}
TEST_P(QuicSimpleServerStreamTest, SendPushResponseWith404Response) {
// Create a new promised stream with even id().
- QuicSimpleServerStreamPeer* promised_stream = new QuicSimpleServerStreamPeer(
- QuicSpdySessionPeer::GetNthServerInitiatedUnidirectionalStreamId(session_,
- 0),
+ auto promised_stream = new StrictMock<TestStream>(
+ GetNthServerInitiatedUnidirectionalStreamId(
+ connection_->transport_version(), 0),
&session_, WRITE_UNIDIRECTIONAL, &memory_cache_backend_);
session_.ActivateStream(QuicWrapUnique(promised_stream));
@@ -451,7 +423,7 @@
EXPECT_CALL(session_,
SendRstStream(promised_stream->id(), QUIC_STREAM_CANCELLED, 0));
- QuicSimpleServerStreamPeer::SendResponse(promised_stream);
+ promised_stream->DoSendResponse();
}
TEST_P(QuicSimpleServerStreamTest, SendResponseWithValidHeaders) {
@@ -476,17 +448,13 @@
stream_->set_fin_received(true);
InSequence s;
- EXPECT_CALL(session_, WriteHeadersMock(stream_->id(), _, false, _, _));
- if (is_version_99_) {
- EXPECT_CALL(session_, WritevData(_, _, _, _, _))
- .Times(1)
- .WillOnce(Return(QuicConsumedData(header_length, false)));
+ EXPECT_CALL(*stream_, WriteHeadersMock(false));
+ if (HasFrameHeader()) {
+ EXPECT_CALL(session_, WritevData(_, _, header_length, _, NO_FIN));
}
- EXPECT_CALL(session_, WritevData(_, _, _, _, _))
- .Times(1)
- .WillOnce(Return(QuicConsumedData(body.length(), true)));
+ EXPECT_CALL(session_, WritevData(_, _, body.length(), _, FIN));
- QuicSimpleServerStreamPeer::SendResponse(stream_);
+ stream_->DoSendResponse();
EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
EXPECT_TRUE(stream_->write_side_closed());
}
@@ -518,23 +486,17 @@
stream_->set_fin_received(true);
InSequence s;
- EXPECT_CALL(
- session_,
- PromisePushResourcesMock(
- host + request_path, _,
- QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId(
- session_, 0),
- _));
- EXPECT_CALL(session_, WriteHeadersMock(stream_->id(), _, false, _, _));
- if (is_version_99_) {
- EXPECT_CALL(session_, WritevData(_, _, _, _, _))
- .Times(1)
- .WillOnce(Return(QuicConsumedData(header_length, false)));
+ EXPECT_CALL(session_, PromisePushResourcesMock(
+ host + request_path, _,
+ GetNthClientInitiatedBidirectionalStreamId(
+ connection_->transport_version(), 0),
+ _));
+ EXPECT_CALL(*stream_, WriteHeadersMock(false));
+ if (HasFrameHeader()) {
+ EXPECT_CALL(session_, WritevData(_, _, header_length, _, NO_FIN));
}
- EXPECT_CALL(session_, WritevData(_, _, _, _, _))
- .Times(1)
- .WillOnce(Return(QuicConsumedData(body.length(), true)));
- QuicSimpleServerStreamPeer::SendResponse(stream_);
+ EXPECT_CALL(session_, WritevData(_, _, body.length(), _, FIN));
+ stream_->DoSendResponse();
EXPECT_EQ(*request_headers, session_.original_request_headers_);
}
@@ -557,13 +519,12 @@
// Create a stream with even stream id and test against this stream.
const QuicStreamId kServerInitiatedStreamId =
- QuicSpdySessionPeer::GetNthServerInitiatedUnidirectionalStreamId(session_,
- 0);
+ GetNthServerInitiatedUnidirectionalStreamId(
+ connection_->transport_version(), 0);
// Create a server initiated stream and pass it to session_.
- QuicSimpleServerStreamPeer* server_initiated_stream =
- new QuicSimpleServerStreamPeer(kServerInitiatedStreamId, &session_,
- WRITE_UNIDIRECTIONAL,
- &memory_cache_backend_);
+ auto server_initiated_stream =
+ new StrictMock<TestStream>(kServerInitiatedStreamId, &session_,
+ WRITE_UNIDIRECTIONAL, &memory_cache_backend_);
session_.ActivateStream(QuicWrapUnique(server_initiated_stream));
const QuicString kHost = "www.foo.com";
@@ -586,26 +547,18 @@
// Call PushResponse() should trigger stream to fetch response from cache
// and send it back.
- EXPECT_CALL(session_,
- WriteHeadersMock(kServerInitiatedStreamId, _, false,
- server_initiated_stream->priority(), _));
-
InSequence s;
- if (is_version_99_) {
- EXPECT_CALL(session_, WritevData(_, kServerInitiatedStreamId, _, _, _))
- .Times(1)
- .WillOnce(Return(QuicConsumedData(header_length, false)));
+ EXPECT_CALL(*server_initiated_stream, WriteHeadersMock(false));
+
+ if (HasFrameHeader()) {
+ EXPECT_CALL(session_, WritevData(_, kServerInitiatedStreamId, header_length,
+ _, NO_FIN));
}
- EXPECT_CALL(session_, WritevData(_, kServerInitiatedStreamId, _, _, _))
- .Times(1)
- .WillOnce(Return(QuicConsumedData(kBody.size(), true)));
+ EXPECT_CALL(session_,
+ WritevData(_, kServerInitiatedStreamId, kBody.size(), _, FIN));
server_initiated_stream->PushResponse(std::move(headers));
- EXPECT_EQ(kPath, QuicSimpleServerStreamPeer::headers(
- server_initiated_stream)[":path"]
- .as_string());
- EXPECT_EQ("GET", QuicSimpleServerStreamPeer::headers(
- server_initiated_stream)[":method"]
- .as_string());
+ EXPECT_EQ(kPath, server_initiated_stream->GetHeader(":path"));
+ EXPECT_EQ("GET", server_initiated_stream->GetHeader(":method"));
}
TEST_P(QuicSimpleServerStreamTest, TestSendErrorResponse) {
@@ -614,17 +567,13 @@
stream_->set_fin_received(true);
InSequence s;
- EXPECT_CALL(session_, WriteHeadersMock(_, _, _, _, _));
- if (is_version_99_) {
- EXPECT_CALL(session_, WritevData(_, _, _, _, _))
- .Times(1)
- .WillOnce(Return(QuicConsumedData(2, false)));
+ EXPECT_CALL(*stream_, WriteHeadersMock(false));
+ if (HasFrameHeader()) {
+ EXPECT_CALL(session_, WritevData(_, _, kDataFrameHeaderLength, _, NO_FIN));
}
- EXPECT_CALL(session_, WritevData(_, _, _, _, _))
- .Times(1)
- .WillOnce(Return(QuicConsumedData(3, true)));
+ EXPECT_CALL(session_, WritevData(_, _, kErrorLength, _, FIN));
- QuicSimpleServerStreamPeer::SendErrorResponse(stream_);
+ stream_->DoSendErrorResponse();
EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
EXPECT_TRUE(stream_->write_side_closed());
}
@@ -636,9 +585,8 @@
// \000 is a way to write the null byte when followed by a literal digit.
header_list_.OnHeader("content-length", QuicStringPiece("11\00012", 5));
- EXPECT_CALL(session_, WriteHeadersMock(_, _, _, _, _));
+ EXPECT_CALL(*stream_, WriteHeadersMock(false));
EXPECT_CALL(session_, WritevData(_, _, _, _, _))
- .Times(AnyNumber())
.WillRepeatedly(Invoke(MockQuicSession::ConsumeData));
stream_->OnStreamHeaderList(true, kFakeFrameLen, header_list_);
@@ -654,9 +602,8 @@
// \000 is a way to write the null byte when followed by a literal digit.
header_list_.OnHeader("content-length", QuicStringPiece("\00012", 3));
- EXPECT_CALL(session_, WriteHeadersMock(_, _, _, _, _));
+ EXPECT_CALL(*stream_, WriteHeadersMock(false));
EXPECT_CALL(session_, WritevData(_, _, _, _, _))
- .Times(AnyNumber())
.WillRepeatedly(Invoke(MockQuicSession::ConsumeData));
stream_->OnStreamHeaderList(true, kFakeFrameLen, header_list_);
@@ -672,7 +619,7 @@
stream_->OnStreamHeaderList(false, kFakeFrameLen, header_list_);
- EXPECT_EQ(11, QuicSimpleServerStreamPeer::content_length(stream_));
+ EXPECT_EQ(11, stream_->content_length());
EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
EXPECT_FALSE(stream_->reading_stopped());
EXPECT_FALSE(stream_->write_side_closed());
@@ -688,7 +635,7 @@
QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream_->id(),
QUIC_STREAM_CANCELLED, 1234);
stream_->OnStreamReset(rst_frame);
- if (connection_->transport_version() == QUIC_VERSION_99) {
+ if (IsVersion99()) {
// For V99 receiving a RST_STREAM causes a 1-way close; the test requires
// a full close. A CloseWriteSide closes the other half of the stream.
// Everything should then work properly.
diff --git a/quic/tools/quic_tcp_like_trace_converter.h b/quic/tools/quic_tcp_like_trace_converter.h
index 6c9a241..4329805 100644
--- a/quic/tools/quic_tcp_like_trace_converter.h
+++ b/quic/tools/quic_tcp_like_trace_converter.h
@@ -8,9 +8,10 @@
#include <vector>
#include "net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h"
+#include "net/third_party/quiche/src/quic/core/quic_interval.h"
+#include "net/third_party/quiche/src/quic/core/quic_interval_set.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_interval.h"
namespace quic {
diff --git a/spdy/core/hpack/hpack_constants.h b/spdy/core/hpack/hpack_constants.h
index 3f4026b..d3f9d8d 100644
--- a/spdy/core/hpack/hpack_constants.h
+++ b/spdy/core/hpack/hpack_constants.h
@@ -12,7 +12,8 @@
#include "net/third_party/quiche/src/spdy/platform/api/spdy_export.h"
// All section references below are to
-// http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-08
+// https://httpwg.org/specs/rfc7540.html and
+// https://httpwg.org/specs/rfc7541.html.
namespace spdy {
@@ -42,7 +43,7 @@
class HpackHuffmanTable;
class HpackStaticTable;
-// Defined in RFC 7540, 6.5.2.
+// RFC 7540, 6.5.2: Initial value for SETTINGS_HEADER_TABLE_SIZE.
const uint32_t kDefaultHeaderTableSizeSetting = 4096;
// RFC 7541, 5.2: Flag for a string literal that is stored unmodified (i.e.,
@@ -69,11 +70,11 @@
// varint-encoded table size with a 5-bit prefix.
const HpackPrefix kHeaderTableSizeUpdateOpcode = {0b001, 3};
-// Symbol code table from RFC 7541, "Appendix C. Huffman Code".
+// RFC 7541, Appendix B: Huffman Code.
SPDY_EXPORT_PRIVATE const std::vector<HpackHuffmanSymbol>&
HpackHuffmanCodeVector();
-// Static table from RFC 7541, "Appendix B. Static Table Definition".
+// RFC 7541, Appendix A: Static Table Definition.
SPDY_EXPORT_PRIVATE const std::vector<HpackStaticEntry>&
HpackStaticTableVector();
@@ -87,7 +88,7 @@
// threads. This function is thread-safe.
SPDY_EXPORT_PRIVATE const HpackStaticTable& ObtainHpackStaticTable();
-// Pseudo-headers start with a colon. (HTTP2 8.1.2.1., HPACK 3.1.)
+// RFC 7541, 8.1.2.1: Pseudo-headers start with a colon.
const char kPseudoHeaderPrefix = ':';
} // namespace spdy
diff --git a/spdy/core/hpack/hpack_decoder_adapter_test.cc b/spdy/core/hpack/hpack_decoder_adapter_test.cc
index 765c2ea..9c94126 100644
--- a/spdy/core/hpack/hpack_decoder_adapter_test.cc
+++ b/spdy/core/hpack/hpack_decoder_adapter_test.cc
@@ -259,15 +259,13 @@
size_t bytes_passed_in_;
};
-INSTANTIATE_TEST_CASE_P(
- NoHandler,
- HpackDecoderAdapterTest,
+INSTANTIATE_TEST_SUITE_P(
+ NoHandler, HpackDecoderAdapterTest,
::testing::Combine(::testing::Values(START_WITHOUT_HANDLER, NO_START),
::testing::Bool()));
-INSTANTIATE_TEST_CASE_P(
- WithHandler,
- HpackDecoderAdapterTest,
+INSTANTIATE_TEST_SUITE_P(
+ WithHandler, HpackDecoderAdapterTest,
::testing::Combine(::testing::Values(START_WITH_HANDLER),
::testing::Bool()));
diff --git a/spdy/core/hpack/hpack_encoder_test.cc b/spdy/core/hpack/hpack_encoder_test.cc
index 8ead1c2..7d7d37d 100644
--- a/spdy/core/hpack/hpack_encoder_test.cc
+++ b/spdy/core/hpack/hpack_encoder_test.cc
@@ -207,7 +207,8 @@
bool use_incremental_;
};
-INSTANTIATE_TEST_CASE_P(HpackEncoderTests, HpackEncoderTest, ::testing::Bool());
+INSTANTIATE_TEST_SUITE_P(HpackEncoderTests, HpackEncoderTest,
+ ::testing::Bool());
TEST_P(HpackEncoderTest, SingleDynamicIndex) {
encoder_.SetHeaderListener(
diff --git a/spdy/core/hpack/hpack_round_trip_test.cc b/spdy/core/hpack/hpack_round_trip_test.cc
index 4b3a848..bd4d6ee 100644
--- a/spdy/core/hpack/hpack_round_trip_test.cc
+++ b/spdy/core/hpack/hpack_round_trip_test.cc
@@ -78,11 +78,9 @@
HpackDecoderAdapter decoder_;
};
-INSTANTIATE_TEST_CASE_P(Tests,
- HpackRoundTripTest,
- ::testing::Values(ALL_INPUT,
- ONE_BYTE,
- ZERO_THEN_ONE_BYTE));
+INSTANTIATE_TEST_SUITE_P(Tests, HpackRoundTripTest,
+ ::testing::Values(ALL_INPUT, ONE_BYTE,
+ ZERO_THEN_ONE_BYTE));
TEST_P(HpackRoundTripTest, ResponseFixtures) {
{
diff --git a/spdy/core/spdy_framer_test.cc b/spdy/core/spdy_framer_test.cc
index a08d7d7..3841172 100644
--- a/spdy/core/spdy_framer_test.cc
+++ b/spdy/core/spdy_framer_test.cc
@@ -615,9 +615,8 @@
Http2DecoderAdapter deframer_;
};
-INSTANTIATE_TEST_CASE_P(SpdyFramerTests,
- SpdyFramerTest,
- ::testing::Values(USE, NOT_USE));
+INSTANTIATE_TEST_SUITE_P(SpdyFramerTests, SpdyFramerTest,
+ ::testing::Values(USE, NOT_USE));
// Test that we can encode and decode a SpdyHeaderBlock in serialized form.
TEST_P(SpdyFramerTest, HeaderBlockInBuffer) {