Interop 105 first round of changes c2
diff --git a/quic/core/http/end_to_end_test.cc b/quic/core/http/end_to_end_test.cc index d2b133d..23e4422 100644 --- a/quic/core/http/end_to_end_test.cc +++ b/quic/core/http/end_to_end_test.cc
@@ -611,6 +611,7 @@ } TEST_P(EndToEndTest, SimpleRequestResponseForcedVersionNegotiation) { + SetQuicReloadableFlag(quic_use_parse_public_header, true); client_supported_versions_.insert(client_supported_versions_.begin(), QuicVersionReservedForNegotiation()); ASSERT_TRUE(Initialize()); @@ -623,6 +624,7 @@ } TEST_P(EndToEndTestWithTls, ForcedVersionNegotiation) { + SetQuicReloadableFlag(quic_use_parse_public_header, true); client_supported_versions_.insert(client_supported_versions_.begin(), QuicVersionReservedForNegotiation()); ASSERT_TRUE(Initialize()); @@ -2583,6 +2585,7 @@ QuicFramer::BuildVersionNegotiationPacket( incorrect_connection_id, EmptyQuicConnectionId(), VersionHasIetfInvariantHeader(client_connection->transport_version()), + client_connection->version().HasLengthPrefixedConnectionIds(), server_supported_versions_)); testing::NiceMock<MockQuicConnectionDebugVisitor> visitor; client_connection->set_debug_visitor(&visitor);
diff --git a/quic/core/http/quic_spdy_session_test.cc b/quic/core/http/quic_spdy_session_test.cc index 2042f88..b4cfedd 100644 --- a/quic/core/http/quic_spdy_session_test.cc +++ b/quic/core/http/quic_spdy_session_test.cc
@@ -1794,8 +1794,7 @@ session_.OnStreamFrame(data1); EXPECT_EQ(1u, session_.GetNumOpenIncomingStreams()); QuicStream* stream = session_.GetOrCreateStream(stream_id1); - EXPECT_EQ(1u, stream->flow_controller()->bytes_consumed()); - EXPECT_EQ(1u, session_.flow_controller()->bytes_consumed()); + EXPECT_EQ(7u, stream->flow_controller()->bytes_consumed()); char unoptimized_type[] = {0x80, 0x00, 0x00, 0x01}; data = std::string(unoptimized_type, 4) + "header"; @@ -1805,8 +1804,7 @@ session_.OnStreamFrame(data2); EXPECT_EQ(2u, session_.GetNumOpenIncomingStreams()); stream = session_.GetOrCreateStream(stream_id2); - EXPECT_EQ(4u, stream->flow_controller()->bytes_consumed()); - EXPECT_EQ(5u, session_.flow_controller()->bytes_consumed()); + EXPECT_EQ(10u, stream->flow_controller()->bytes_consumed()); } TEST_P(QuicSpdySessionTestClient, Http3ServerPushOutofOrderFrame) {
diff --git a/quic/core/http/quic_spdy_stream.cc b/quic/core/http/quic_spdy_stream.cc index 11cc233..d4c0211 100644 --- a/quic/core/http/quic_spdy_stream.cc +++ b/quic/core/http/quic_spdy_stream.cc
@@ -47,7 +47,7 @@ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); } - bool OnPriorityFrameStart(Http3FrameLengths /*frame_lengths*/) override { + bool OnPriorityFrameStart(Http3FrameLengths /*frame_length*/) override { CloseConnectionOnWrongFrame("Priority"); return false; } @@ -72,7 +72,7 @@ return false; } - bool OnSettingsFrameStart(Http3FrameLengths /*frame_lengths*/) override { + bool OnSettingsFrameStart(Http3FrameLengths /*frame_length*/) override { CloseConnectionOnWrongFrame("Settings"); return false; } @@ -88,8 +88,8 @@ return false; } - bool OnDataFrameStart(Http3FrameLengths frame_lengths) override { - return stream_->OnDataFrameStart(frame_lengths); + bool OnDataFrameStart(Http3FrameLengths frame_length) override { + return stream_->OnDataFrameStart(frame_length); } bool OnDataFramePayload(QuicStringPiece payload) override { @@ -142,18 +142,16 @@ return false; } - bool OnUnknownFrameStart(uint64_t /* frame_type */, - Http3FrameLengths /* frame_length */) override { - // TODO(b/137554973): Consume frame header. - return true; + bool OnUnknownFrameStart(uint64_t frame_type, + Http3FrameLengths frame_length) override { + return stream_->OnUnknownFrameStart(frame_type, frame_length); } - bool OnUnknownFramePayload(QuicStringPiece /* payload */) override { - // TODO(b/137554973): Consume frame payload. - return true; + bool OnUnknownFramePayload(QuicStringPiece payload) override { + return stream_->OnUnknownFramePayload(payload); } - bool OnUnknownFrameEnd() override { return true; } + bool OnUnknownFrameEnd() override { return stream_->OnUnknownFrameEnd(); } private: void CloseConnectionOnWrongFrame(std::string frame_type) { @@ -184,7 +182,6 @@ trailers_decompressed_(false), trailers_consumed_(false), priority_sent_(false), - headers_bytes_to_be_marked_consumed_(0), http_decoder_visitor_(QuicMakeUnique<HttpDecoderVisitor>(this)), decoder_(http_decoder_visitor_.get()), body_buffer_(sequencer()), @@ -221,7 +218,6 @@ trailers_decompressed_(false), trailers_consumed_(false), priority_sent_(false), - headers_bytes_to_be_marked_consumed_(0), http_decoder_visitor_(QuicMakeUnique<HttpDecoderVisitor>(this)), decoder_(http_decoder_visitor_.get()), body_buffer_(sequencer()), @@ -398,12 +394,6 @@ } size_t bytes_read = body_buffer_.ReadBody(iov, iov_len); - if (VersionUsesQpack(transport_version())) { - // Maybe all DATA frame bytes have been read and some trailing HEADERS had - // already been processed, in which case MarkConsumed() should be called. - MaybeMarkHeadersBytesConsumed(); - } - return bytes_read; } @@ -422,12 +412,6 @@ return; } body_buffer_.MarkBodyConsumed(num_bytes); - - if (VersionUsesQpack(transport_version())) { - // Maybe all DATA frame bytes have been read and some trailing HEADERS had - // already been processed, in which case MarkConsumed() should be called. - MaybeMarkHeadersBytesConsumed(); - } } bool QuicSpdyStream::IsDoneReading() const { @@ -759,7 +743,7 @@ spdy_session_ = nullptr; } -bool QuicSpdyStream::OnDataFrameStart(Http3FrameLengths frame_lengths) { +bool QuicSpdyStream::OnDataFrameStart(Http3FrameLengths frame_length) { DCHECK(VersionHasDataFrameHeader(transport_version())); if (!headers_decompressed_ || trailers_decompressed_) { // TODO(b/124216424): Change error code to HTTP_UNEXPECTED_FRAME. @@ -769,7 +753,8 @@ return false; } - body_buffer_.OnDataHeader(frame_lengths); + body_buffer_.OnConsumableBytes(frame_length.header_length); + return true; } @@ -777,6 +762,7 @@ DCHECK(VersionHasDataFrameHeader(transport_version())); body_buffer_.OnDataPayload(payload); + return true; } @@ -822,16 +808,6 @@ } } -void QuicSpdyStream::MaybeMarkHeadersBytesConsumed() { - DCHECK(VersionUsesQpack(transport_version())); - - if (!body_buffer_.HasBytesToRead() && !reading_stopped() && - headers_bytes_to_be_marked_consumed_ > 0) { - sequencer()->MarkConsumed(headers_bytes_to_be_marked_consumed_); - headers_bytes_to_be_marked_consumed_ = 0; - } -} - QuicByteCount QuicSpdyStream::GetNumFrameHeadersInInterval( QuicStreamOffset offset, QuicByteCount data_length) const { @@ -857,6 +833,8 @@ return false; } + body_buffer_.OnConsumableBytes(frame_length.header_length); + if (headers_decompressed_) { trailers_length_ = frame_length; } else { @@ -868,10 +846,6 @@ id(), spdy_session_->qpack_decoder(), this, spdy_session_->max_inbound_header_list_size()); - // Do not call MaybeMarkHeadersBytesConsumed() yet, because - // HEADERS frame header bytes might not have been parsed completely. - headers_bytes_to_be_marked_consumed_ += frame_length.header_length; - return true; } @@ -880,8 +854,7 @@ const bool success = qpack_decoded_headers_accumulator_->Decode(payload); - headers_bytes_to_be_marked_consumed_ += payload.size(); - MaybeMarkHeadersBytesConsumed(); + body_buffer_.OnConsumableBytes(payload.size()); if (!success) { // TODO(124216424): Use HTTP_QPACK_DECOMPRESSION_FAILED error code. @@ -919,6 +892,23 @@ return !sequencer()->IsClosed() && !reading_stopped(); } +bool QuicSpdyStream::OnUnknownFrameStart(uint64_t /* frame_type */, + Http3FrameLengths frame_length) { + // Ignore unknown frames, but consume frame header. + body_buffer_.OnConsumableBytes(frame_length.header_length); + return true; +} + +bool QuicSpdyStream::OnUnknownFramePayload(QuicStringPiece payload) { + // Ignore unknown frames, but consume frame payload. + body_buffer_.OnConsumableBytes(payload.size()); + return true; +} + +bool QuicSpdyStream::OnUnknownFrameEnd() { + return true; +} + void QuicSpdyStream::ProcessDecodedHeaders(const QuicHeaderList& headers) { const QuicByteCount frame_length = headers_decompressed_ ? trailers_length_.payload_length
diff --git a/quic/core/http/quic_spdy_stream.h b/quic/core/http/quic_spdy_stream.h index 9cd7827..d2fe9a1 100644 --- a/quic/core/http/quic_spdy_stream.h +++ b/quic/core/http/quic_spdy_stream.h
@@ -254,14 +254,13 @@ bool OnHeadersFrameStart(Http3FrameLengths frame_length); bool OnHeadersFramePayload(QuicStringPiece payload); bool OnHeadersFrameEnd(); + bool OnUnknownFrameStart(uint64_t frame_type, Http3FrameLengths frame_length); + bool OnUnknownFramePayload(QuicStringPiece payload); + bool OnUnknownFrameEnd(); // Called internally when headers are decoded. void ProcessDecodedHeaders(const QuicHeaderList& headers); - // Call QuicStreamSequencer::MarkConsumed() with - // |headers_bytes_to_be_marked_consumed_| if appropriate. - void MaybeMarkHeadersBytesConsumed(); - // Given the interval marked by [|offset|, |offset| + |data_length|), return // the number of frame header bytes contained in it. QuicByteCount GetNumFrameHeadersInInterval(QuicStreamOffset offset, @@ -294,9 +293,6 @@ // True if the stream has already sent an priority frame. bool priority_sent_; - // Number of bytes consumed while decoding HEADERS frames that cannot be - // marked consumed in QuicStreamSequencer until later. - QuicByteCount headers_bytes_to_be_marked_consumed_; // The parsed trailers received from the peer. spdy::SpdyHeaderBlock received_trailers_;
diff --git a/quic/core/http/quic_spdy_stream_body_buffer.cc b/quic/core/http/quic_spdy_stream_body_buffer.cc index c0a77b2..61d37c9 100644 --- a/quic/core/http/quic_spdy_stream_body_buffer.cc +++ b/quic/core/http/quic_spdy_stream_body_buffer.cc
@@ -3,31 +3,117 @@ // found in the LICENSE file. #include "net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_buffer.h" + +#include <utility> + +#include "net/third_party/quiche/src/quic/core/quic_stream_sequencer.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" namespace quic { +QuicSpdyStreamBodyBuffer::QuicSpdyStreamConsumeManager:: + QuicSpdyStreamConsumeManager(ConsumeFunction consume_function) + : consume_function_(std::move(consume_function)) {} + +void QuicSpdyStreamBodyBuffer::QuicSpdyStreamConsumeManager::OnConsumableBytes( + QuicByteCount length) { + DCHECK_NE(0u, length); + + if (fragments_.empty()) { + consume_function_(length); + return; + } + + DCHECK(!fragments_.front().consumable); + fragments_.push_back({length, /* consumable = */ true}); +} + +void QuicSpdyStreamBodyBuffer::QuicSpdyStreamConsumeManager::OnDataPayload( + QuicByteCount length) { + DCHECK_NE(0u, length); + + fragments_.push_back({length, /* consumable = */ false}); +} + +void QuicSpdyStreamBodyBuffer::QuicSpdyStreamConsumeManager::ConsumeData( + QuicByteCount length) { + if (length == 0) { + return; + } + + DCHECK(!fragments_.empty()); + DCHECK(!fragments_.front().consumable); + + QuicByteCount remaining_length = length; + QuicByteCount bytes_to_consume = 0; + + do { + const Fragment& fragment = fragments_.front(); + + if (fragment.consumable) { + bytes_to_consume += fragment.length; + fragments_.pop_front(); + continue; + } + + if (remaining_length == 0) { + break; + } + + if (fragment.length <= remaining_length) { + bytes_to_consume += fragment.length; + remaining_length -= fragment.length; + fragments_.pop_front(); + // Continue iterating even if |remaining_length| to make sure consumable + // bytes on the front of the queue are consumed. + continue; + } + + bytes_to_consume += remaining_length; + QuicByteCount new_fragement_length = fragment.length - remaining_length; + remaining_length = 0; + fragments_.pop_front(); + fragments_.push_front({new_fragement_length, /* consumable = */ false}); + break; + } while (!fragments_.empty()); + + DCHECK_EQ(0u, remaining_length); + if (!fragments_.empty()) { + DCHECK(!fragments_.front().consumable); + } + + consume_function_(bytes_to_consume); +} + QuicSpdyStreamBodyBuffer::QuicSpdyStreamBodyBuffer( QuicStreamSequencer* sequencer) + : QuicSpdyStreamBodyBuffer(std::bind(&QuicStreamSequencer::MarkConsumed, + sequencer, + std::placeholders::_1)) {} + +QuicSpdyStreamBodyBuffer::QuicSpdyStreamBodyBuffer( + ConsumeFunction consume_function) : bytes_remaining_(0), total_body_bytes_readable_(0), total_body_bytes_received_(0), - total_payload_lengths_(0), - sequencer_(sequencer) {} + consume_manager_(std::move(consume_function)) {} QuicSpdyStreamBodyBuffer::~QuicSpdyStreamBodyBuffer() {} -void QuicSpdyStreamBodyBuffer::OnDataHeader(Http3FrameLengths frame_lengths) { - frame_meta_.push_back(frame_lengths); - total_payload_lengths_ += frame_lengths.payload_length; +void QuicSpdyStreamBodyBuffer::OnConsumableBytes(QuicByteCount length) { + DCHECK_NE(0u, length); + + consume_manager_.OnConsumableBytes(length); } void QuicSpdyStreamBodyBuffer::OnDataPayload(QuicStringPiece payload) { DCHECK(!payload.empty()); + + consume_manager_.OnDataPayload(payload.length()); + bodies_.push_back(payload); total_body_bytes_received_ += payload.length(); total_body_bytes_readable_ += payload.length(); - DCHECK_LE(total_body_bytes_received_, total_payload_lengths_); } void QuicSpdyStreamBodyBuffer::MarkBodyConsumed(size_t num_bytes) { @@ -56,18 +142,11 @@ remaining = 0; } } - // Consume headers. - while (bytes_remaining_ < num_bytes) { - if (frame_meta_.empty()) { - QUIC_BUG << "Faild to consume because frame header buffer is empty."; - return; - } - auto meta = frame_meta_.front(); - frame_meta_.pop_front(); - bytes_remaining_ += meta.payload_length; - sequencer_->MarkConsumed(meta.header_length); - } - sequencer_->MarkConsumed(num_bytes); + + // Consume DATA frame payloads and optionally other data (like DATA frame + // headers). + consume_manager_.ConsumeData(num_bytes); + // Update accountings. bytes_remaining_ -= num_bytes; total_body_bytes_readable_ -= num_bytes;
diff --git a/quic/core/http/quic_spdy_stream_body_buffer.h b/quic/core/http/quic_spdy_stream_body_buffer.h index 2485aac..36418e9 100644 --- a/quic/core/http/quic_spdy_stream_body_buffer.h +++ b/quic/core/http/quic_spdy_stream_body_buffer.h
@@ -5,34 +5,90 @@ #ifndef QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_STREAM_BODY_BUFFER_H_ #define QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_STREAM_BODY_BUFFER_H_ +#include <functional> +#include <list> + #include "net/third_party/quiche/src/quic/core/http/http_decoder.h" -#include "net/third_party/quiche/src/quic/core/quic_stream_sequencer.h" #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_iovec.h" namespace quic { -// Buffer decoded body for QuicSpdyStream. It also talks to the sequencer to -// consume data. +class QuicStreamSequencer; + +// Keep references to decoded body (DATA frame payload) fragments, and manage +// calling QuicStreamSequencer::MarkConsumed() for all data received on the +// stream. class QUIC_EXPORT_PRIVATE QuicSpdyStreamBodyBuffer { + private: + using ConsumeFunction = std::function<void(size_t)>; + + // Class that calls QuicStreamSequencer::MarkConsumed() appropriately as DATA + // frame payload is consumed by higher layers. + class QUIC_EXPORT_PRIVATE QuicSpdyStreamConsumeManager { + public: + explicit QuicSpdyStreamConsumeManager(ConsumeFunction consume_function); + ~QuicSpdyStreamConsumeManager() = default; + + // Called when data that could immediately be marked consumed with the + // sequencer (provided that all previous DATA frame payloads are consumed) + // is received. + void OnConsumableBytes(QuicByteCount length); + + // Called when DATA frame payload is received. This cannot be marked + // consumed with the sequencer until higher layers consume it and + // ConsumeData() is called. |length| must be positive. + void OnDataPayload(QuicByteCount length); + + // Called when some amount of DATA frame payload is consumed by higher + // layers. |length| bytes of DATA payload as well as all interleaving and + // immediately following consumable data are marked consumed with the + // sequencer. Must not be called with larger |length| than total currently + // unconsumed DATA payload. + void ConsumeData(QuicByteCount length); + + private: + struct Fragment { + QuicByteCount length; + bool consumable; + }; + + // Queue of data fragments. + // The front of the queue must not be consumable (otherwise it should be + // immediately consumed). Fragments must not be empty. + std::list<Fragment> fragments_; + + ConsumeFunction consume_function_; + }; + public: // QuicSpdyStreamBodyBuffer doesn't own the sequencer and the sequencer can // outlive the buffer. explicit QuicSpdyStreamBodyBuffer(QuicStreamSequencer* sequencer); + // Used for tests. + explicit QuicSpdyStreamBodyBuffer(ConsumeFunction consume_function); + ~QuicSpdyStreamBodyBuffer(); - // Add metadata of the frame to accountings. - // Called when QuicSpdyStream receives data frame header. - void OnDataHeader(Http3FrameLengths frame_lengths); + // One of the following two methods must be called every time data is received + // on the request stream. - // Add new data payload to buffer. - // Called when QuicSpdyStream received data payload. - // Data pointed by payload must be alive until consumed by - // QuicStreamSequencer::MarkConsumed(). + // Called when data that could immediately be marked consumed with the + // sequencer (provided that all previous DATA frame payloads are consumed) is + // received. |length| must be positive. + void OnConsumableBytes(QuicByteCount length); + + // Called when DATA frame payload is received. |payload| is added to the + // buffer. The data pointed to by |payload| is kept alive until a + // MarkBodyConsumed() or ReadBody() call consumes it. Data must be owned by + // QuicStreamSequencer. |payload| must not be empty. void OnDataPayload(QuicStringPiece payload); - // Take |num_bytes| as the body size, calculate header sizes accordingly, and - // consume the right amount of data in the stream sequencer. + // Consume |num_bytes| of DATA frame payload, and an other interleaved or + // immediately succeeding consumable bytes. void MarkBodyConsumed(size_t num_bytes); // Fill up to |iov_len| with bodies available in buffer. No data is consumed. @@ -41,9 +97,9 @@ // Returns the number of iov used. int PeekBody(iovec* iov, size_t iov_len) const; - // Copies from buffer into |iov| up to |iov_len|, and consume data in - // sequencer. |iov.iov_base| and |iov.iov_len| are preassigned and will not be - // changed. + // Copies from buffer into |iov| up to |iov_len|, and calls + // QuicSpdyStreamConsumeManager::ConsumeData() with number of bytes read. + // |iov.iov_base| and |iov.iov_len| are preassigned and will not be changed. // Returns the number of bytes read. size_t ReadBody(const struct iovec* iov, size_t iov_len); @@ -56,18 +112,14 @@ private: // Storage for decoded data. QuicDeque<QuicStringPiece> bodies_; - // Storage for header lengths. - QuicDeque<Http3FrameLengths> frame_meta_; // Bytes in the first available data frame that are not consumed yet. QuicByteCount bytes_remaining_; // Total available body data in the stream. QuicByteCount total_body_bytes_readable_; // Total bytes read from the stream excluding headers. QuicByteCount total_body_bytes_received_; - // Total length of payloads tracked by frame_meta_. - QuicByteCount total_payload_lengths_; - // Stream sequencer that directly manages data in the stream. - QuicStreamSequencer* sequencer_; + // Consume manager that talks to the stream sequencer. + QuicSpdyStreamConsumeManager consume_manager_; }; } // namespace quic
diff --git a/quic/core/http/quic_spdy_stream_body_buffer_test.cc b/quic/core/http/quic_spdy_stream_body_buffer_test.cc index 6e8e20d..37265f4 100644 --- a/quic/core/http/quic_spdy_stream_body_buffer_test.cc +++ b/quic/core/http/quic_spdy_stream_body_buffer_test.cc
@@ -20,60 +20,47 @@ namespace { -class MockStream : public QuicStreamSequencer::StreamInterface { +class MockConsumer { public: - MOCK_METHOD0(OnFinRead, void()); - MOCK_METHOD0(OnDataAvailable, void()); - MOCK_METHOD2(CloseConnectionWithDetails, - void(QuicErrorCode error, const std::string& details)); - MOCK_METHOD1(Reset, void(QuicRstStreamErrorCode error)); - MOCK_METHOD0(OnCanWrite, void()); - MOCK_METHOD1(AddBytesConsumed, void(QuicByteCount bytes)); - - QuicStreamId id() const override { return 1; } - - const QuicSocketAddress& PeerAddressOfLatestPacket() const override { - return peer_address_; - } - - protected: - QuicSocketAddress peer_address_ = - QuicSocketAddress(QuicIpAddress::Any4(), 65535); -}; - -class MockSequencer : public QuicStreamSequencer { - public: - explicit MockSequencer(MockStream* stream) : QuicStreamSequencer(stream) {} - virtual ~MockSequencer() = default; MOCK_METHOD1(MarkConsumed, void(size_t num_bytes_consumed)); }; class QuicSpdyStreamBodyBufferTest : public QuicTest { public: QuicSpdyStreamBodyBufferTest() - : sequencer_(&stream_), body_buffer_(&sequencer_) {} + : body_buffer_(std::bind(&MockConsumer::MarkConsumed, + &consumer_, + std::placeholders::_1)) {} protected: - MockStream stream_; - MockSequencer sequencer_; + testing::StrictMock<MockConsumer> consumer_; QuicSpdyStreamBodyBuffer body_buffer_; HttpEncoder encoder_; }; -TEST_F(QuicSpdyStreamBodyBufferTest, ReceiveBodies) { +TEST_F(QuicSpdyStreamBodyBufferTest, HasBytesToRead) { + const QuicByteCount header_length = 3; std::string body(1024, 'a'); + + EXPECT_CALL(consumer_, MarkConsumed(header_length)); + body_buffer_.OnConsumableBytes(header_length); + EXPECT_FALSE(body_buffer_.HasBytesToRead()); - body_buffer_.OnDataHeader(Http3FrameLengths(3, 1024)); - body_buffer_.OnDataPayload(QuicStringPiece(body)); - EXPECT_EQ(1024u, body_buffer_.total_body_bytes_received()); + EXPECT_EQ(0u, body_buffer_.total_body_bytes_received()); + + body_buffer_.OnDataPayload(body); EXPECT_TRUE(body_buffer_.HasBytesToRead()); + EXPECT_EQ(1024u, body_buffer_.total_body_bytes_received()); } TEST_F(QuicSpdyStreamBodyBufferTest, PeekBody) { + const QuicByteCount header_length = 3; std::string body(1024, 'a'); - body_buffer_.OnDataHeader(Http3FrameLengths(3, 1024)); - body_buffer_.OnDataPayload(QuicStringPiece(body)); - EXPECT_EQ(1024u, body_buffer_.total_body_bytes_received()); + + EXPECT_CALL(consumer_, MarkConsumed(header_length)); + body_buffer_.OnConsumableBytes(header_length); + body_buffer_.OnDataPayload(body); + iovec vec; EXPECT_EQ(1, body_buffer_.PeekBody(&vec, 1)); EXPECT_EQ(1024u, vec.iov_len); @@ -81,67 +68,59 @@ QuicStringPiece(static_cast<const char*>(vec.iov_base), 1024)); } -// Buffer only receives 1 frame. Stream consumes less or equal than a frame. +// Buffer receives one frame. Stream consumes payload in fragments. TEST_F(QuicSpdyStreamBodyBufferTest, MarkConsumedPartialSingleFrame) { testing::InSequence seq; + + const QuicByteCount header_length = 3; std::string body(1024, 'a'); - std::unique_ptr<char[]> buffer; - QuicByteCount header_length = - encoder_.SerializeDataFrameHeader(body.length(), &buffer); - std::string header = std::string(buffer.get(), header_length); - Http3FrameLengths lengths(header_length, 1024); - std::string data = header + body; - QuicStreamFrame frame(1, false, 0, data); - sequencer_.OnStreamFrame(frame); - body_buffer_.OnDataHeader(lengths); - body_buffer_.OnDataPayload(QuicStringPiece(body)); - EXPECT_CALL(stream_, AddBytesConsumed(header_length)); - EXPECT_CALL(stream_, AddBytesConsumed(1024)); - body_buffer_.MarkBodyConsumed(1024); + + EXPECT_CALL(consumer_, MarkConsumed(header_length)); + body_buffer_.OnConsumableBytes(header_length); + body_buffer_.OnDataPayload(body); + + EXPECT_CALL(consumer_, MarkConsumed(512)); + body_buffer_.MarkBodyConsumed(512); + + EXPECT_CALL(consumer_, MarkConsumed(512)); + body_buffer_.MarkBodyConsumed(512); } -// Buffer received 2 frames. Stream consumes multiple times. +// Buffer receives two frames. Stream consumes multiple times. TEST_F(QuicSpdyStreamBodyBufferTest, MarkConsumedMultipleFrames) { testing::InSequence seq; - // 1st frame. + + const QuicByteCount header_length1 = 3; std::string body1(1024, 'a'); - std::unique_ptr<char[]> buffer; - QuicByteCount header_length1 = - encoder_.SerializeDataFrameHeader(body1.length(), &buffer); - std::string header1 = std::string(buffer.get(), header_length1); - Http3FrameLengths lengths1(header_length1, 1024); - std::string data1 = header1 + body1; - QuicStreamFrame frame1(1, false, 0, data1); - sequencer_.OnStreamFrame(frame1); - body_buffer_.OnDataHeader(lengths1); - body_buffer_.OnDataPayload(QuicStringPiece(body1)); - // 2nd frame. + EXPECT_CALL(consumer_, MarkConsumed(header_length1)); + body_buffer_.OnConsumableBytes(header_length1); + body_buffer_.OnDataPayload(body1); + + const QuicByteCount header_length2 = 3; std::string body2(2048, 'b'); - QuicByteCount header_length2 = - encoder_.SerializeDataFrameHeader(body2.length(), &buffer); - std::string header2 = std::string(buffer.get(), header_length2); - Http3FrameLengths lengths2(header_length2, 2048); - std::string data2 = header2 + body2; - QuicStreamFrame frame2(1, false, data1.length(), data2); - sequencer_.OnStreamFrame(frame2); - body_buffer_.OnDataHeader(lengths2); - body_buffer_.OnDataPayload(QuicStringPiece(body2)); + body_buffer_.OnConsumableBytes(header_length2); + body_buffer_.OnDataPayload(body2); - EXPECT_CALL(stream_, AddBytesConsumed(header_length1)); - EXPECT_CALL(stream_, AddBytesConsumed(512)); + // Consume part of the first frame payload. + EXPECT_CALL(consumer_, MarkConsumed(512)); body_buffer_.MarkBodyConsumed(512); - EXPECT_CALL(stream_, AddBytesConsumed(header_length2)); - EXPECT_CALL(stream_, AddBytesConsumed(2048)); + + // Consume rest of the first frame and some of the second. + EXPECT_CALL(consumer_, MarkConsumed(header_length2 + 2048)); body_buffer_.MarkBodyConsumed(2048); - EXPECT_CALL(stream_, AddBytesConsumed(512)); + + // Consume rest of the second frame. + EXPECT_CALL(consumer_, MarkConsumed(512)); body_buffer_.MarkBodyConsumed(512); } TEST_F(QuicSpdyStreamBodyBufferTest, MarkConsumedMoreThanBuffered) { + const QuicByteCount header_length = 3; + EXPECT_CALL(consumer_, MarkConsumed(header_length)); + body_buffer_.OnConsumableBytes(header_length); + std::string body(1024, 'a'); - Http3FrameLengths lengths(3, 1024); - body_buffer_.OnDataHeader(lengths); body_buffer_.OnDataPayload(body); EXPECT_QUIC_BUG( body_buffer_.MarkBodyConsumed(2048), @@ -149,24 +128,18 @@ "enough bytes available. Total bytes readable are: 1024"); } -// Buffer receives 1 frame. Stream read from the buffer. +// Buffer receives one frame. Stream reads from the buffer. TEST_F(QuicSpdyStreamBodyBufferTest, ReadSingleBody) { testing::InSequence seq; + + const QuicByteCount header_length = 3; std::string body(1024, 'a'); - std::unique_ptr<char[]> buffer; - QuicByteCount header_length = - encoder_.SerializeDataFrameHeader(body.length(), &buffer); - std::string header = std::string(buffer.get(), header_length); - Http3FrameLengths lengths(header_length, 1024); - std::string data = header + body; - QuicStreamFrame frame(1, false, 0, data); - sequencer_.OnStreamFrame(frame); - body_buffer_.OnDataHeader(lengths); + + EXPECT_CALL(consumer_, MarkConsumed(header_length)); + body_buffer_.OnConsumableBytes(header_length); body_buffer_.OnDataPayload(QuicStringPiece(body)); - EXPECT_CALL(stream_, AddBytesConsumed(header_length)); - EXPECT_CALL(stream_, AddBytesConsumed(1024)); - + EXPECT_CALL(consumer_, MarkConsumed(1024)); char base[1024]; iovec iov = {&base[0], 1024}; EXPECT_EQ(1024u, body_buffer_.ReadBody(&iov, 1)); @@ -175,37 +148,24 @@ QuicStringPiece(static_cast<const char*>(iov.iov_base), 1024)); } -// Buffer receives 2 frames, stream read from the buffer multiple times. +// Buffer receives two frames. Stream reads from the buffer multiple times. TEST_F(QuicSpdyStreamBodyBufferTest, ReadMultipleBody) { testing::InSequence seq; - // 1st frame. + + const QuicByteCount header_length1 = 3; std::string body1(1024, 'a'); - std::unique_ptr<char[]> buffer; - QuicByteCount header_length1 = - encoder_.SerializeDataFrameHeader(body1.length(), &buffer); - std::string header1 = std::string(buffer.get(), header_length1); - Http3FrameLengths lengths1(header_length1, 1024); - std::string data1 = header1 + body1; - QuicStreamFrame frame1(1, false, 0, data1); - sequencer_.OnStreamFrame(frame1); - body_buffer_.OnDataHeader(lengths1); - body_buffer_.OnDataPayload(QuicStringPiece(body1)); - // 2nd frame. + EXPECT_CALL(consumer_, MarkConsumed(header_length1)); + body_buffer_.OnConsumableBytes(header_length1); + body_buffer_.OnDataPayload(body1); + + const QuicByteCount header_length2 = 3; std::string body2(2048, 'b'); - QuicByteCount header_length2 = - encoder_.SerializeDataFrameHeader(body2.length(), &buffer); - std::string header2 = std::string(buffer.get(), header_length2); - Http3FrameLengths lengths2(header_length2, 2048); - std::string data2 = header2 + body2; - QuicStreamFrame frame2(1, false, data1.length(), data2); - sequencer_.OnStreamFrame(frame2); - body_buffer_.OnDataHeader(lengths2); - body_buffer_.OnDataPayload(QuicStringPiece(body2)); + body_buffer_.OnConsumableBytes(header_length2); + body_buffer_.OnDataPayload(body2); - // First read of 512 bytes. - EXPECT_CALL(stream_, AddBytesConsumed(header_length1)); - EXPECT_CALL(stream_, AddBytesConsumed(512)); + // Read part of the first frame payload. + EXPECT_CALL(consumer_, MarkConsumed(512)); char base[512]; iovec iov = {&base[0], 512}; EXPECT_EQ(512u, body_buffer_.ReadBody(&iov, 1)); @@ -213,9 +173,8 @@ EXPECT_EQ(body1.substr(0, 512), QuicStringPiece(static_cast<const char*>(iov.iov_base), 512)); - // Second read of 2048 bytes. - EXPECT_CALL(stream_, AddBytesConsumed(header_length2)); - EXPECT_CALL(stream_, AddBytesConsumed(2048)); + // Read rest of the first frame and some of the second. + EXPECT_CALL(consumer_, MarkConsumed(header_length2 + 2048)); char base2[2048]; iovec iov2 = {&base2[0], 2048}; EXPECT_EQ(2048u, body_buffer_.ReadBody(&iov2, 1)); @@ -223,8 +182,8 @@ EXPECT_EQ(body1.substr(512, 512) + body2.substr(0, 1536), QuicStringPiece(static_cast<const char*>(iov2.iov_base), 2048)); - // Third read of the rest 512 bytes. - EXPECT_CALL(stream_, AddBytesConsumed(512)); + // Read rest of the second frame. + EXPECT_CALL(consumer_, MarkConsumed(512)); char base3[512]; iovec iov3 = {&base3[0], 512}; EXPECT_EQ(512u, body_buffer_.ReadBody(&iov3, 1));
diff --git a/quic/core/http/quic_spdy_stream_test.cc b/quic/core/http/quic_spdy_stream_test.cc index f9777ec..03a1719 100644 --- a/quic/core/http/quic_spdy_stream_test.cc +++ b/quic/core/http/quic_spdy_stream_test.cc
@@ -2088,8 +2088,7 @@ HeadersFrame(QuicTextUtils::HexDecode("00002a94e703626172")); // All HEADERS frame bytes are consumed even if the frame is not received - // completely (as long as at least some of the payload is received, which is - // an implementation detail that should not be tested). + // completely. OnStreamFrame(QuicStringPiece(headers).substr(0, headers.size() - 1)); EXPECT_EQ(headers.size() - 1, NewlyConsumedBytes()); @@ -2103,17 +2102,22 @@ // DATA frame. QuicStringPiece data_payload(kDataFramePayload); - std::string data_frame = DataFrame(data_payload); + std::unique_ptr<char[]> data_buffer; + QuicByteCount data_frame_header_length = + encoder_.SerializeDataFrameHeader(data_payload.size(), &data_buffer); + QuicStringPiece data_frame_header(data_buffer.get(), + data_frame_header_length); + std::string data_frame = QuicStrCat(data_frame_header, data_payload); - // DATA frame is not consumed because payload has to be buffered. - // TODO(bnc): Consume frame header as soon as possible. + // DATA frame header is consumed. + // DATA frame payload is not consumed because payload has to be buffered. OnStreamFrame(data_frame); - EXPECT_EQ(0u, NewlyConsumedBytes()); + EXPECT_EQ(data_frame_header_length, NewlyConsumedBytes()); // Consume all but last byte of data. EXPECT_EQ(data_payload.substr(0, data_payload.size() - 1), ReadFromStream(data_payload.size() - 1)); - EXPECT_EQ(data_frame.size() - 1, NewlyConsumedBytes()); + EXPECT_EQ(data_payload.size() - 1, NewlyConsumedBytes()); // Trailing HEADERS frame with QPACK encoded // single header field "custom-key: custom-value". @@ -2320,6 +2324,27 @@ EXPECT_EQ(0u, stream_->sequencer()->NumBytesConsumed()); } +// Regression test for b/137554973: unknown frames should be consumed. +TEST_P(QuicSpdyStreamTest, ConsumeUnknownFrame) { + if (!VersionUsesQpack(GetParam().transport_version)) { + return; + } + + Initialize(kShouldProcessData); + + std::string unknown_frame = QuicTextUtils::HexDecode( + "21" // reserved frame type + "03" // payload length + "666f6f"); // payload "foo" + + EXPECT_EQ(0u, stream_->flow_controller()->bytes_consumed()); + + stream_->OnStreamFrame(QuicStreamFrame(stream_->id(), /* fin = */ false, + /* offset = */ 0, unknown_frame)); + + EXPECT_EQ(unknown_frame.size(), stream_->flow_controller()->bytes_consumed()); +} + } // namespace } // namespace test } // namespace quic
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc index 22ee18a..b983a94 100644 --- a/quic/core/quic_connection.cc +++ b/quic/core/quic_connection.cc
@@ -247,6 +247,7 @@ max_tracked_packets_(GetQuicFlag(FLAGS_quic_max_tracked_packet_count)), pending_version_negotiation_packet_(false), send_ietf_version_negotiation_packet_(false), + send_version_negotiation_packet_with_prefixed_lengths_(false), idle_timeout_connection_close_behavior_( ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET), close_connection_after_five_rtos_(false), @@ -1452,9 +1453,11 @@ } } -void QuicConnection::SendVersionNegotiationPacket(bool ietf_quic) { +void QuicConnection::SendVersionNegotiationPacket(bool ietf_quic, + bool has_length_prefix) { pending_version_negotiation_packet_ = true; send_ietf_version_negotiation_packet_ = ietf_quic; + send_version_negotiation_packet_with_prefixed_lengths_ = has_length_prefix; if (HandleWriteBlocked()) { return; @@ -1466,7 +1469,7 @@ << "}, " << (ietf_quic ? "" : "!") << "ietf_quic"; std::unique_ptr<QuicEncryptedPacket> version_packet( packet_generator_.SerializeVersionNegotiationPacket( - ietf_quic, framer_.supported_versions())); + ietf_quic, has_length_prefix, framer_.supported_versions())); QUIC_DVLOG(2) << ENDPOINT << "Sending version negotiation packet: {" << ParsedQuicVersionVectorToString(framer_.supported_versions()) << "}, " << (ietf_quic ? "" : "!") << "ietf_quic:" << std::endl @@ -1865,7 +1868,9 @@ DCHECK(!writer_->IsWriteBlocked()); if (pending_version_negotiation_packet_) { - SendVersionNegotiationPacket(send_ietf_version_negotiation_packet_); + SendVersionNegotiationPacket( + send_ietf_version_negotiation_packet_, + send_version_negotiation_packet_with_prefixed_lengths_); } QUIC_CLIENT_HISTOGRAM_COUNTS("QuicSession.NumQueuedPacketsBeforeWrite",
diff --git a/quic/core/quic_connection.h b/quic/core/quic_connection.h index 59a3656..45d31be 100644 --- a/quic/core/quic_connection.h +++ b/quic/core/quic_connection.h
@@ -980,7 +980,7 @@ const QuicStopWaitingFrame& stop_waiting); // Sends a version negotiation packet to the peer. - void SendVersionNegotiationPacket(bool ietf_quic); + void SendVersionNegotiationPacket(bool ietf_quic, bool has_length_prefix); // Clears any accumulated frames from the last received packet. void ClearLastFrames(); @@ -1217,6 +1217,7 @@ bool pending_version_negotiation_packet_; // Used when pending_version_negotiation_packet_ is true. bool send_ietf_version_negotiation_packet_; + bool send_version_negotiation_packet_with_prefixed_lengths_; // When packets could not be sent because the socket was not writable, // they are added to this list. All corresponding frames are in
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc index ee7b651..f0152cd 100644 --- a/quic/core/quic_connection_test.cc +++ b/quic/core/quic_connection_test.cc
@@ -6774,16 +6774,20 @@ } TEST_P(QuicConnectionTest, ClientHandlesVersionNegotiation) { - // Start out with an unsupported version. - QuicConnectionPeer::GetFramer(&connection_) - ->set_version_for_tests(QuicVersionReservedForNegotiation()); + // All supported versions except the one the connection supports. + ParsedQuicVersionVector versions; + for (auto version : AllSupportedVersions()) { + if (version != connection_.version()) { + versions.push_back(version); + } + } // Send a version negotiation packet. std::unique_ptr<QuicEncryptedPacket> encrypted( QuicFramer::BuildVersionNegotiationPacket( connection_id_, EmptyQuicConnectionId(), VersionHasIetfInvariantHeader(connection_.transport_version()), - AllSupportedVersions())); + connection_.version().HasLengthPrefixedConnectionIds(), versions)); std::unique_ptr<QuicReceivedPacket> received( ConstructReceivedPacket(*encrypted, QuicTime::Zero())); EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF)) @@ -6804,6 +6808,7 @@ QuicFramer::BuildVersionNegotiationPacket( connection_id_, EmptyQuicConnectionId(), VersionHasIetfInvariantHeader(connection_.transport_version()), + connection_.version().HasLengthPrefixedConnectionIds(), AllSupportedVersions())); std::unique_ptr<QuicReceivedPacket> received( ConstructReceivedPacket(*encrypted, QuicTime::Zero()));
diff --git a/quic/core/quic_constants.h b/quic/core/quic_constants.h index 442fb09..77b0b8a 100644 --- a/quic/core/quic_constants.h +++ b/quic/core/quic_constants.h
@@ -13,6 +13,8 @@ #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +// useless comment. + // Definitions of constant values used throughout the QUIC code. namespace quic {
diff --git a/quic/core/quic_crypto_stream_test.cc b/quic/core/quic_crypto_stream_test.cc index dd4450e..4117786 100644 --- a/quic/core/quic_crypto_stream_test.cc +++ b/quic/core/quic_crypto_stream_test.cc
@@ -519,10 +519,13 @@ SCOPED_TRACE(version); QuicByteCount expected_overhead = 48; if (VersionHasIetfInvariantHeader(version)) { - expected_overhead = 52; + expected_overhead += 4; } if (QuicVersionHasLongHeaderLengths(version)) { - expected_overhead = 55; + expected_overhead += 3; + } + if (VersionHasLengthPrefixedConnectionIds(version)) { + expected_overhead += 1; } EXPECT_EQ(expected_overhead, QuicCryptoStream::CryptoMessageFramingOverhead( version, TestConnectionId()));
diff --git a/quic/core/quic_dispatcher.cc b/quic/core/quic_dispatcher.cc index c6ee816..7522703 100644 --- a/quic/core/quic_dispatcher.cc +++ b/quic/core/quic_dispatcher.cc
@@ -228,11 +228,25 @@ QuicStringPiece(packet.data(), packet.length())); ReceivedPacketInfo packet_info(self_address, peer_address, packet); std::string detailed_error; - const QuicErrorCode error = QuicFramer::ProcessPacketDispatcher( - packet, expected_server_connection_id_length_, &packet_info.form, - &packet_info.version_flag, &packet_info.version_label, - &packet_info.destination_connection_id, &packet_info.source_connection_id, - &detailed_error); + QuicErrorCode error; + if (!GetQuicReloadableFlag(quic_use_parse_public_header)) { + error = QuicFramer::ProcessPacketDispatcher( + packet, expected_server_connection_id_length_, &packet_info.form, + &packet_info.version_flag, &packet_info.version_label, + &packet_info.destination_connection_id, + &packet_info.source_connection_id, &detailed_error); + } else { + QUIC_RELOADABLE_FLAG_COUNT(quic_use_parse_public_header); + bool retry_token_present; + QuicStringPiece retry_token; + error = QuicFramer::ParsePublicHeaderDispatcher( + packet, expected_server_connection_id_length_, &packet_info.form, + &packet_info.version_flag, &packet_info.use_length_prefix, + &packet_info.version_label, &packet_info.version, + &packet_info.destination_connection_id, + &packet_info.source_connection_id, &retry_token_present, &retry_token, + &detailed_error); + } if (error != QUIC_NO_ERROR) { // Packet has framing error. SetLastError(error); @@ -319,7 +333,8 @@ << " to time-wait list."; StatelesslyTerminateConnection( server_connection_id, packet_info.form, packet_info.version_flag, - packet_info.version, QUIC_HANDSHAKE_FAILED, "Reject connection", + packet_info.use_length_prefix, packet_info.version, + QUIC_HANDSHAKE_FAILED, "Reject connection", quic::QuicTimeWaitListManager::SEND_STATELESS_RESET); DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait( @@ -396,9 +411,12 @@ packet_info.source_connection_id; time_wait_list_manager()->SendVersionNegotiationPacket( server_connection_id, client_connection_id, - packet_info.form != GOOGLE_QUIC_PACKET, GetSupportedVersions(), - packet_info.self_address, packet_info.peer_address, - GetPerPacketContext()); + packet_info.form != GOOGLE_QUIC_PACKET, + packet_info.form != GOOGLE_QUIC_PACKET && + !QuicVersionLabelUses4BitConnectionIdLength( + packet_info.version_label), + GetSupportedVersions(), packet_info.self_address, + packet_info.peer_address, GetPerPacketContext()); } return true; } @@ -454,7 +472,8 @@ QUIC_CODE_COUNT(quic_reject_fate_time_wait); StatelesslyTerminateConnection( server_connection_id, packet_info->form, packet_info->version_flag, - packet_info->version, QUIC_HANDSHAKE_FAILED, "Reject connection", + packet_info->use_length_prefix, packet_info->version, + QUIC_HANDSHAKE_FAILED, "Reject connection", quic::QuicTimeWaitListManager::SEND_STATELESS_RESET); DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait( @@ -521,7 +540,9 @@ VersionHasIetfInvariantHeader(connection->transport_version()) ? IETF_QUIC_LONG_HEADER_PACKET : GOOGLE_QUIC_PACKET, - /*version_flag=*/true, connection->version(), QUIC_HANDSHAKE_FAILED, + /*version_flag=*/true, + connection->version().HasLengthPrefixedConnectionIds(), + connection->version(), QUIC_HANDSHAKE_FAILED, "Connection is closed by server before handshake confirmed", // Although it is our intention to send termination packets, the // |action| argument is not used by this call to @@ -665,6 +686,7 @@ QuicConnectionId server_connection_id, PacketHeaderFormat format, bool version_flag, + bool use_length_prefix, ParsedQuicVersion version, QuicErrorCode error_code, const std::string& error_details, @@ -707,7 +729,7 @@ std::vector<std::unique_ptr<QuicEncryptedPacket>> termination_packets; termination_packets.push_back(QuicFramer::BuildVersionNegotiationPacket( server_connection_id, EmptyQuicConnectionId(), - /*ietf_quic=*/format != GOOGLE_QUIC_PACKET, + /*ietf_quic=*/format != GOOGLE_QUIC_PACKET, use_length_prefix, /*versions=*/{})); time_wait_list_manager()->AddConnectionIdToTimeWait( server_connection_id, /*ietf_quic=*/format != GOOGLE_QUIC_PACKET, @@ -728,8 +750,10 @@ server_connection_id, early_arrived_packets.ietf_quic ? IETF_QUIC_LONG_HEADER_PACKET : GOOGLE_QUIC_PACKET, - /*version_flag=*/true, early_arrived_packets.version, - QUIC_HANDSHAKE_FAILED, "Packets buffered for too long", + /*version_flag=*/true, + early_arrived_packets.version.HasLengthPrefixedConnectionIds(), + early_arrived_packets.version, QUIC_HANDSHAKE_FAILED, + "Packets buffered for too long", quic::QuicTimeWaitListManager::SEND_STATELESS_RESET); } @@ -820,7 +844,8 @@ QUIC_CODE_COUNT(quic_reject_stop_accepting_new_connections); StatelesslyTerminateConnection( packet_info->destination_connection_id, packet_info->form, - /*version_flag=*/true, packet_info->version, QUIC_HANDSHAKE_FAILED, + /*version_flag=*/true, packet_info->use_length_prefix, + packet_info->version, QUIC_HANDSHAKE_FAILED, "Stop accepting new connections", quic::QuicTimeWaitListManager::SEND_STATELESS_RESET); // Time wait list will reject the packet correspondingly.
diff --git a/quic/core/quic_dispatcher.h b/quic/core/quic_dispatcher.h index cfaafa0..091e727 100644 --- a/quic/core/quic_dispatcher.h +++ b/quic/core/quic_dispatcher.h
@@ -254,6 +254,7 @@ QuicConnectionId server_connection_id, PacketHeaderFormat format, bool version_flag, + bool use_length_prefix, ParsedQuicVersion version, QuicErrorCode error_code, const std::string& error_details,
diff --git a/quic/core/quic_dispatcher_test.cc b/quic/core/quic_dispatcher_test.cc index b18bddb..0ac5d56 100644 --- a/quic/core/quic_dispatcher_test.cc +++ b/quic/core/quic_dispatcher_test.cc
@@ -524,13 +524,14 @@ } TEST_F(QuicDispatcherTest, StatelessVersionNegotiation) { + SetQuicReloadableFlag(quic_use_parse_public_header, true); CreateTimeWaitListManager(); QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0); EXPECT_CALL( *time_wait_list_manager_, - SendVersionNegotiationPacket(TestConnectionId(1), _, _, _, _, _, _)) + SendVersionNegotiationPacket(TestConnectionId(1), _, _, _, _, _, _, _)) .Times(1); // Pad the CHLO message with enough data to make the packet large enough // to trigger version negotiation. @@ -543,13 +544,14 @@ TEST_F(QuicDispatcherTest, StatelessVersionNegotiationWithClientConnectionId) { SetQuicRestartFlag(quic_do_not_override_connection_id, true); + SetQuicReloadableFlag(quic_use_parse_public_header, true); CreateTimeWaitListManager(); QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0); EXPECT_CALL(*time_wait_list_manager_, - SendVersionNegotiationPacket(TestConnectionId(1), - TestConnectionId(2), _, _, _, _, _)) + SendVersionNegotiationPacket( + TestConnectionId(1), TestConnectionId(2), _, _, _, _, _, _)) .Times(1); // Pad the CHLO message with enough data to make the packet large enough // to trigger version negotiation. @@ -567,7 +569,7 @@ EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0); EXPECT_CALL(*time_wait_list_manager_, - SendVersionNegotiationPacket(_, _, _, _, _, _, _)) + SendVersionNegotiationPacket(_, _, _, _, _, _, _, _)) .Times(0); std::string chlo = SerializeCHLO() + std::string(1200, 'a'); // Truncate to 1100 bytes of payload which results in a packet just @@ -583,6 +585,7 @@ // Disabling CHLO size validation allows the dispatcher to send version // negotiation packets in response to a CHLO that is otherwise too small. TEST_F(QuicDispatcherTest, VersionNegotiationWithoutChloSizeValidation) { + SetQuicReloadableFlag(quic_use_parse_public_header, true); crypto_config_.set_validate_chlo_size(false); CreateTimeWaitListManager(); @@ -590,7 +593,7 @@ EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0); EXPECT_CALL(*time_wait_list_manager_, - SendVersionNegotiationPacket(_, _, _, _, _, _, _)) + SendVersionNegotiationPacket(_, _, _, _, _, _, _, _)) .Times(1); std::string chlo = SerializeCHLO() + std::string(1200, 'a'); // Truncate to 1100 bytes of payload which results in a packet just @@ -927,6 +930,8 @@ } TEST_F(QuicDispatcherTest, SupportedTransportVersionsChangeInFlight) { + SetQuicRestartFlag(quic_dispatcher_hands_chlo_extractor_one_version, true); + SetQuicReloadableFlag(quic_use_parse_public_header, true); static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u, "Supported versions out of sync"); SetQuicReloadableFlag(quic_disable_version_39, false); @@ -994,7 +999,7 @@ QuicTime::Zero()); EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0); EXPECT_CALL(*time_wait_list_manager_, - SendVersionNegotiationPacket(_, _, _, _, _, _, _)) + SendVersionNegotiationPacket(_, _, _, _, _, _, _, _)) .Times(1); dispatcher_->ProcessPacket(server_address_, client_address, packet); }
diff --git a/quic/core/quic_framer.cc b/quic/core/quic_framer.cc index e9d6fa9..56e7d28 100644 --- a/quic/core/quic_framer.cc +++ b/quic/core/quic_framer.cc
@@ -408,6 +408,7 @@ } bool AppendIetfConnectionIds(bool version_flag, + bool use_length_prefix, QuicConnectionId destination_connection_id, QuicConnectionId source_connection_id, QuicDataWriter* writer) { @@ -415,6 +416,11 @@ return writer->WriteConnectionId(destination_connection_id); } + if (use_length_prefix) { + return writer->WriteLengthPrefixedConnectionId(destination_connection_id) && + writer->WriteLengthPrefixedConnectionId(source_connection_id); + } + // Compute connection ID length byte. uint8_t dcil = GetConnectionIdLengthValue( static_cast<QuicConnectionIdLength>(destination_connection_id.length())); @@ -1399,6 +1405,7 @@ QuicConnectionId server_connection_id, QuicConnectionId client_connection_id, bool ietf_quic, + bool use_length_prefix, const ParsedQuicVersionVector& versions) { ParsedQuicVersionVector wire_versions = versions; if (!GetQuicReloadableFlag(quic_version_negotiation_grease)) { @@ -1431,11 +1438,14 @@ } if (ietf_quic) { return BuildIetfVersionNegotiationPacket( - server_connection_id, client_connection_id, wire_versions); + use_length_prefix, server_connection_id, client_connection_id, + wire_versions); } // The GQUIC encoding does not support encoding client connection IDs. DCHECK(client_connection_id.IsEmpty()); + // The GQUIC encoding does not support length-prefixed connection IDs. + DCHECK(!use_length_prefix); DCHECK(!wire_versions.empty()); size_t len = kPublicFlagsSize + server_connection_id.length() + @@ -1467,10 +1477,15 @@ // static std::unique_ptr<QuicEncryptedPacket> QuicFramer::BuildIetfVersionNegotiationPacket( + bool use_length_prefix, QuicConnectionId server_connection_id, QuicConnectionId client_connection_id, const ParsedQuicVersionVector& versions) { - QUIC_DVLOG(1) << "Building IETF version negotiation packet: " + QUIC_DVLOG(1) << "Building IETF version negotiation packet with" + << (use_length_prefix ? "" : "out") + << " length prefix, server_connection_id " + << server_connection_id << " client_connection_id " + << client_connection_id << " versions " << ParsedQuicVersionVectorToString(versions); DCHECK(client_connection_id.IsEmpty() || GetQuicRestartFlag(quic_do_not_override_connection_id)); @@ -1478,6 +1493,11 @@ size_t len = kPacketHeaderTypeSize + kConnectionIdLengthSize + client_connection_id.length() + server_connection_id.length() + (versions.size() + 1) * kQuicVersionSize; + if (use_length_prefix) { + // When using length-prefixed connection IDs, packets carry two lengths + // instead of one. + len += kConnectionIdLengthSize; + } std::unique_ptr<char[]> buffer(new char[len]); QuicDataWriter writer(len, buffer.get()); @@ -1491,8 +1511,8 @@ return nullptr; } - if (!AppendIetfConnectionIds(true, client_connection_id, server_connection_id, - &writer)) { + if (!AppendIetfConnectionIds(true, use_length_prefix, client_connection_id, + server_connection_id, &writer)) { return nullptr; } @@ -1630,17 +1650,26 @@ const QuicPacketHeader& header) { DCHECK_EQ(Perspective::IS_CLIENT, perspective_); - // Parse Original Destination Connection ID Length. - uint8_t odcil = header.type_byte & 0xf; - if (odcil != 0) { - odcil += kConnectionIdLengthAdjustment; - } - - // Parse Original Destination Connection ID. QuicConnectionId original_destination_connection_id; - if (!reader->ReadConnectionId(&original_destination_connection_id, odcil)) { - set_detailed_error("Unable to read Original Destination ConnectionId."); - return false; + if (version_.HasLengthPrefixedConnectionIds()) { + // Parse Original Destination Connection ID. + if (!reader->ReadLengthPrefixedConnectionId( + &original_destination_connection_id)) { + set_detailed_error("Unable to read Original Destination ConnectionId."); + return false; + } + } else { + // Parse Original Destination Connection ID Length. + uint8_t odcil = header.type_byte & 0xf; + if (odcil != 0) { + odcil += kConnectionIdLengthAdjustment; + } + + // Parse Original Destination Connection ID. + if (!reader->ReadConnectionId(&original_destination_connection_id, odcil)) { + set_detailed_error("Unable to read Original Destination ConnectionId."); + return false; + } } QuicStringPiece retry_token = reader->ReadRemainingPayload(); @@ -1649,42 +1678,6 @@ return true; } -bool QuicFramer::MaybeProcessIetfInitialRetryToken( - QuicDataReader* encrypted_reader, - QuicPacketHeader* header) { - if (!QuicVersionHasLongHeaderLengths(header->version.transport_version) || - header->form != IETF_QUIC_LONG_HEADER_PACKET || - header->long_packet_type != INITIAL) { - return true; - } - uint64_t retry_token_length = 0; - header->retry_token_length_length = encrypted_reader->PeekVarInt62Length(); - if (!encrypted_reader->ReadVarInt62(&retry_token_length)) { - set_detailed_error("Unable to read INITIAL retry token length."); - return RaiseError(QUIC_INVALID_PACKET_HEADER); - } - header->retry_token = encrypted_reader->PeekRemainingPayload(); - // Safety check to avoid spending ressources if malformed. - // At this point header->retry_token contains the rest of the packet - // so its length() is the amount of data remaining in the packet. - if (retry_token_length > header->retry_token.length()) { - set_detailed_error("INITIAL token length longer than packet."); - return RaiseError(QUIC_INVALID_PACKET_HEADER); - } - // Resize retry_token to make it only contain the retry token. - header->retry_token.remove_suffix(header->retry_token.length() - - retry_token_length); - // Advance encrypted_reader by retry_token_length. - uint8_t wasted_byte; - for (uint64_t i = 0; i < retry_token_length; ++i) { - if (!encrypted_reader->ReadUInt8(&wasted_byte)) { - set_detailed_error("Unable to read INITIAL retry token."); - return RaiseError(QUIC_INVALID_PACKET_HEADER); - } - } - return true; -} - // Seeks the current packet to check for a coalesced packet at the end. // If the IETF length field only spans part of the outer packet, // then there is a coalesced packet after this one. @@ -1769,8 +1762,6 @@ size_t buffer_length) { DCHECK_NE(GOOGLE_QUIC_PACKET, header->form); DCHECK(!header->has_possible_stateless_reset_token); - header->retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_0; - header->retry_token = QuicStringPiece(); header->length_length = VARIABLE_LENGTH_INTEGER_LENGTH_0; header->remaining_packet_length = 0; if (header->form == IETF_QUIC_SHORT_HEADER_PACKET && @@ -1787,10 +1778,6 @@ } } - if (!MaybeProcessIetfInitialRetryToken(encrypted_reader, header)) { - return false; - } - if (!MaybeProcessIetfLength(encrypted_reader, header)) { return false; } @@ -2218,7 +2205,7 @@ // Append connection ID. if (!AppendIetfConnectionIds( - header.version_flag, + header.version_flag, version_.HasLengthPrefixedConnectionIds(), header.destination_connection_id_included != CONNECTION_ID_ABSENT ? header.destination_connection_id : EmptyQuicConnectionId(), @@ -2550,7 +2537,7 @@ QuicPacketHeader* header) { uint8_t type; if (!reader->ReadBytes(&type, 1)) { - set_detailed_error("Unable to read type."); + set_detailed_error("Unable to read first byte."); return false; } header->type_byte = type; @@ -2704,6 +2691,78 @@ bool QuicFramer::ProcessIetfPacketHeader(QuicDataReader* reader, QuicPacketHeader* header) { + if (version_.HasLengthPrefixedConnectionIds()) { + uint8_t expected_destination_connection_id_length = + perspective_ == Perspective::IS_CLIENT + ? expected_client_connection_id_length_ + : expected_server_connection_id_length_; + QuicVersionLabel version_label; + bool has_length_prefix; + std::string detailed_error; + QuicErrorCode parse_result = QuicFramer::ParsePublicHeader( + reader, expected_destination_connection_id_length, + VersionHasIetfInvariantHeader(version_.transport_version), + &header->type_byte, &header->form, &header->version_flag, + &has_length_prefix, &version_label, &header->version, + &header->destination_connection_id, &header->source_connection_id, + &header->long_packet_type, &header->retry_token_length_length, + &header->retry_token, &detailed_error); + if (parse_result != QUIC_NO_ERROR) { + set_detailed_error(detailed_error); + return false; + } + header->destination_connection_id_included = CONNECTION_ID_PRESENT; + header->source_connection_id_included = + header->version_flag ? CONNECTION_ID_PRESENT : CONNECTION_ID_ABSENT; + if (header->source_connection_id_included == CONNECTION_ID_ABSENT) { + DCHECK(header->source_connection_id.IsEmpty()); + if (perspective_ == Perspective::IS_CLIENT) { + header->source_connection_id = last_serialized_server_connection_id_; + } else { + header->source_connection_id = last_serialized_client_connection_id_; + } + } + if (header->version_flag && + header->version.transport_version > QUIC_VERSION_44 && + !(header->type_byte & FLAGS_FIXED_BIT)) { + set_detailed_error("Fixed bit is 0 in long header."); + return false; + } + if (!header->version_flag && version_.transport_version > QUIC_VERSION_44 && + !(header->type_byte & FLAGS_FIXED_BIT)) { + set_detailed_error("Fixed bit is 0 in short header."); + return false; + } + if (!header->version_flag) { + if (!version_.HasHeaderProtection() && + !GetShortHeaderPacketNumberLength( + transport_version(), header->type_byte, + infer_packet_header_type_from_version_, + &header->packet_number_length)) { + set_detailed_error("Failed to get short header packet number length."); + return false; + } + return true; + } + if (header->long_packet_type == RETRY) { + if (!version().SupportsRetry()) { + set_detailed_error("RETRY not supported in this version."); + return false; + } + if (perspective_ == Perspective::IS_SERVER) { + set_detailed_error("Client-initiated RETRY is invalid."); + return false; + } + return true; + } + if (!header->version.HasHeaderProtection()) { + header->packet_number_length = GetLongHeaderPacketNumberLength( + header->version.transport_version, header->type_byte); + } + + return true; + } + if (!ProcessIetfHeaderTypeByte(reader, header)) { return false; } @@ -2737,13 +2796,13 @@ // Read connection ID. if (!reader->ReadConnectionId(&header->destination_connection_id, destination_connection_id_length)) { - set_detailed_error("Unable to read Destination ConnectionId."); + set_detailed_error("Unable to read destination connection ID."); return false; } if (!reader->ReadConnectionId(&header->source_connection_id, source_connection_id_length)) { - set_detailed_error("Unable to read Source ConnectionId."); + set_detailed_error("Unable to read source connection ID."); return false; } @@ -6208,6 +6267,7 @@ QuicConnectionId* destination_connection_id, QuicConnectionId* source_connection_id, std::string* detailed_error) { + DCHECK(!GetQuicReloadableFlag(quic_use_parse_public_header)); QuicDataReader reader(packet.data(), packet.length()); *source_connection_id = EmptyQuicConnectionId(); @@ -6280,6 +6340,262 @@ } // static +QuicErrorCode QuicFramer::ParsePublicHeaderDispatcher( + const QuicEncryptedPacket& packet, + uint8_t expected_destination_connection_id_length, + PacketHeaderFormat* format, + bool* version_present, + bool* has_length_prefix, + QuicVersionLabel* version_label, + ParsedQuicVersion* parsed_version, + QuicConnectionId* destination_connection_id, + QuicConnectionId* source_connection_id, + bool* retry_token_present, + QuicStringPiece* retry_token, + std::string* detailed_error) { + QuicDataReader reader(packet.data(), packet.length()); + if (reader.IsDoneReading()) { + *detailed_error = "Unable to read first byte."; + return QUIC_INVALID_PACKET_HEADER; + } + const uint8_t first_byte = reader.PeekByte(); + const bool ietf_format = QuicUtils::IsIetfPacketHeader(first_byte); + uint8_t unused_first_byte; + QuicVariableLengthIntegerLength retry_token_length_length; + QuicLongHeaderType unused_log_packet_type; + const QuicErrorCode error_code = ParsePublicHeader( + &reader, expected_destination_connection_id_length, ietf_format, + &unused_first_byte, format, version_present, has_length_prefix, + version_label, parsed_version, destination_connection_id, + source_connection_id, &unused_log_packet_type, &retry_token_length_length, + retry_token, detailed_error); + *retry_token_present = + retry_token_length_length != VARIABLE_LENGTH_INTEGER_LENGTH_0; + return error_code; +} + +// static +QuicErrorCode QuicFramer::ParsePublicHeaderGoogleQuic( + QuicDataReader* reader, + uint8_t* first_byte, + PacketHeaderFormat* format, + bool* version_present, + QuicVersionLabel* version_label, + QuicConnectionId* destination_connection_id, + std::string* detailed_error) { + *format = GOOGLE_QUIC_PACKET; + *version_present = (*first_byte & PACKET_PUBLIC_FLAGS_VERSION) != 0; + uint8_t destination_connection_id_length = 0; + if ((*first_byte & PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID) != 0) { + destination_connection_id_length = kQuicDefaultConnectionIdLength; + } + if (!reader->ReadConnectionId(destination_connection_id, + destination_connection_id_length)) { + *detailed_error = "Unable to read ConnectionId."; + return QUIC_INVALID_PACKET_HEADER; + } + if (*version_present && !ProcessVersionLabel(reader, version_label)) { + *detailed_error = "Unable to read protocol version."; + return QUIC_INVALID_PACKET_HEADER; + } + return QUIC_NO_ERROR; +} + +namespace { + +inline bool PacketHasLengthPrefixedConnectionIds( + const QuicDataReader& reader, + ParsedQuicVersion parsed_version, + QuicVersionLabel version_label, + uint8_t first_byte) { + if (parsed_version.transport_version != QUIC_VERSION_UNSUPPORTED) { + return parsed_version.HasLengthPrefixedConnectionIds(); + } + + // Received unsupported version, check known old unsupported versions. + if (QuicVersionLabelUses4BitConnectionIdLength(version_label)) { + return false; + } + + // Received unknown version, check connection ID length byte. + if (reader.IsDoneReading()) { + // This check is required to safely peek the connection ID length byte. + return true; + } + const uint8_t connection_id_length_byte = reader.PeekByte(); + + // Check for packets produced by older versions of + // QuicFramer::WriteClientVersionNegotiationProbePacket + if (first_byte == 0xc0 && (connection_id_length_byte & 0x0f) == 0 && + connection_id_length_byte >= 0x50 && version_label == 0xcabadaba) { + return false; + } + + return true; +} + +inline bool ParseLongHeaderConnectionIds( + QuicDataReader* reader, + bool has_length_prefix, + QuicConnectionId* destination_connection_id, + QuicConnectionId* source_connection_id, + std::string* detailed_error) { + if (has_length_prefix) { + if (!reader->ReadLengthPrefixedConnectionId(destination_connection_id)) { + *detailed_error = "Unable to read destination connection ID."; + return false; + } + if (!reader->ReadLengthPrefixedConnectionId(source_connection_id)) { + *detailed_error = "Unable to read source connection ID."; + return false; + } + } else { + // Parse connection ID lengths. + uint8_t connection_id_lengths_byte; + if (!reader->ReadUInt8(&connection_id_lengths_byte)) { + *detailed_error = "Unable to read connection ID lengths."; + return false; + } + uint8_t destination_connection_id_length = + (connection_id_lengths_byte & kDestinationConnectionIdLengthMask) >> 4; + if (destination_connection_id_length != 0) { + destination_connection_id_length += kConnectionIdLengthAdjustment; + } + uint8_t source_connection_id_length = + connection_id_lengths_byte & kSourceConnectionIdLengthMask; + if (source_connection_id_length != 0) { + source_connection_id_length += kConnectionIdLengthAdjustment; + } + + // Read destination connection ID. + if (!reader->ReadConnectionId(destination_connection_id, + destination_connection_id_length)) { + *detailed_error = "Unable to read destination connection ID."; + return false; + } + + // Read source connection ID. + if (!reader->ReadConnectionId(source_connection_id, + source_connection_id_length)) { + *detailed_error = "Unable to read source connection ID."; + return false; + } + } + return true; +} + +} // namespace + +// static +QuicErrorCode QuicFramer::ParsePublicHeader( + QuicDataReader* reader, + uint8_t expected_destination_connection_id_length, + bool ietf_format, + uint8_t* first_byte, + PacketHeaderFormat* format, + bool* version_present, + bool* has_length_prefix, + QuicVersionLabel* version_label, + ParsedQuicVersion* parsed_version, + QuicConnectionId* destination_connection_id, + QuicConnectionId* source_connection_id, + QuicLongHeaderType* long_packet_type, + QuicVariableLengthIntegerLength* retry_token_length_length, + QuicStringPiece* retry_token, + std::string* detailed_error) { + *version_present = false; + *has_length_prefix = false; + *version_label = 0; + *parsed_version = UnsupportedQuicVersion(); + *source_connection_id = EmptyQuicConnectionId(); + *long_packet_type = INVALID_PACKET_TYPE; + *retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_0; + *retry_token = QuicStringPiece(); + *detailed_error = ""; + + if (!reader->ReadUInt8(first_byte)) { + *detailed_error = "Unable to read first byte."; + return QUIC_INVALID_PACKET_HEADER; + } + + if (!ietf_format) { + return ParsePublicHeaderGoogleQuic( + reader, first_byte, format, version_present, version_label, + destination_connection_id, detailed_error); + } + + *format = GetIetfPacketHeaderFormat(*first_byte); + + if (*format == IETF_QUIC_SHORT_HEADER_PACKET) { + // Read destination connection ID using + // expected_destination_connection_id_length to determine its length. + if (!reader->ReadConnectionId(destination_connection_id, + expected_destination_connection_id_length)) { + *detailed_error = "Unable to read destination connection ID."; + return QUIC_INVALID_PACKET_HEADER; + } + return QUIC_NO_ERROR; + } + + DCHECK_EQ(IETF_QUIC_LONG_HEADER_PACKET, *format); + *version_present = true; + if (!ProcessVersionLabel(reader, version_label)) { + *detailed_error = "Unable to read protocol version."; + return QUIC_INVALID_PACKET_HEADER; + } + + if (*version_label == 0) { + *long_packet_type = VERSION_NEGOTIATION; + } + + // Parse version. + *parsed_version = ParseQuicVersionLabel(*version_label); + + // Figure out which IETF QUIC invariants this packet follows. + *has_length_prefix = PacketHasLengthPrefixedConnectionIds( + *reader, *parsed_version, *version_label, *first_byte); + + // Parse connection IDs. + if (!ParseLongHeaderConnectionIds(reader, *has_length_prefix, + destination_connection_id, + source_connection_id, detailed_error)) { + return QUIC_INVALID_PACKET_HEADER; + } + + if (parsed_version->transport_version == QUIC_VERSION_UNSUPPORTED) { + // Skip parsing of long packet type and retry token for unknown versions. + return QUIC_NO_ERROR; + } + + // Parse long packet type. + if (!GetLongHeaderType(parsed_version->transport_version, *first_byte, + long_packet_type)) { + *detailed_error = "Unable to parse long packet type."; + return QUIC_INVALID_PACKET_HEADER; + } + + if (!parsed_version->SupportsRetry() || *long_packet_type != INITIAL) { + // Retry token is only present on initial packets for some versions. + return QUIC_NO_ERROR; + } + + *retry_token_length_length = reader->PeekVarInt62Length(); + uint64_t retry_token_length; + if (!reader->ReadVarInt62(&retry_token_length)) { + *retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_0; + *detailed_error = "Unable to read retry token length."; + return QUIC_INVALID_PACKET_HEADER; + } + + if (!reader->ReadStringPiece(retry_token, retry_token_length)) { + *detailed_error = "Unable to read retry token."; + return QUIC_INVALID_PACKET_HEADER; + } + + return QUIC_NO_ERROR; +} + +// static bool QuicFramer::WriteClientVersionNegotiationProbePacket( char* packet_bytes, QuicByteCount packet_length, @@ -6300,14 +6616,17 @@ QUIC_BUG << "Invalid connection_id_length"; return false; } + const bool use_length_prefix = + GetQuicFlag(FLAGS_quic_prober_uses_length_prefixed_connection_ids); + const uint8_t last_version_byte = use_length_prefix ? 0xda : 0xba; // clang-format off - static const unsigned char packet_start_bytes[] = { + const unsigned char packet_start_bytes[] = { // IETF long header with fixed bit set, type initial, all-0 encrypted bits. 0xc0, // Version, part of the IETF space reserved for negotiation. // This intentionally differs from QuicVersionReservedForNegotiation() // to allow differentiating them over the wire. - 0xca, 0xba, 0xda, 0xba, + 0xca, 0xba, 0xda, last_version_byte, }; // clang-format on static_assert(sizeof(packet_start_bytes) == 5, "bad packet_start_bytes size"); @@ -6319,8 +6638,9 @@ QuicConnectionId destination_connection_id(destination_connection_id_bytes, destination_connection_id_length); - if (!AppendIetfConnectionIds(/*version_flag=*/true, destination_connection_id, - EmptyQuicConnectionId(), &writer)) { + if (!AppendIetfConnectionIds( + /*version_flag=*/true, use_length_prefix, destination_connection_id, + EmptyQuicConnectionId(), &writer)) { QUIC_BUG << "Failed to write connection IDs"; return false; } @@ -6404,35 +6724,50 @@ *detailed_error = "Packet is not a version negotiation packet"; return false; } - uint8_t expected_server_connection_id_length = 0, - destination_connection_id_length = 0, source_connection_id_length = 0; - if (!ProcessAndValidateIetfConnectionIdLength( - &reader, UnsupportedQuicVersion(), Perspective::IS_CLIENT, - /*should_update_expected_server_connection_id_length=*/true, - &expected_server_connection_id_length, - &destination_connection_id_length, &source_connection_id_length, - detailed_error)) { - return false; - } - if (destination_connection_id_length != 0) { - *detailed_error = "Received unexpected destination connection ID length"; - return false; - } + const bool use_length_prefix = + GetQuicFlag(FLAGS_quic_prober_uses_length_prefixed_connection_ids); QuicConnectionId destination_connection_id, source_connection_id; - if (!reader.ReadConnectionId(&destination_connection_id, - destination_connection_id_length)) { - *detailed_error = "Failed to read destination connection ID"; - return false; + if (use_length_prefix) { + if (!reader.ReadLengthPrefixedConnectionId(&destination_connection_id)) { + *detailed_error = "Failed to read destination connection ID"; + return false; + } + if (!reader.ReadLengthPrefixedConnectionId(&source_connection_id)) { + *detailed_error = "Failed to read source connection ID"; + return false; + } + } else { + uint8_t expected_server_connection_id_length = 0, + destination_connection_id_length = 0, + source_connection_id_length = 0; + if (!ProcessAndValidateIetfConnectionIdLength( + &reader, UnsupportedQuicVersion(), Perspective::IS_CLIENT, + /*should_update_expected_server_connection_id_length=*/true, + &expected_server_connection_id_length, + &destination_connection_id_length, &source_connection_id_length, + detailed_error)) { + return false; + } + if (!reader.ReadConnectionId(&destination_connection_id, + destination_connection_id_length)) { + *detailed_error = "Failed to read destination connection ID"; + return false; + } + if (!reader.ReadConnectionId(&source_connection_id, + source_connection_id_length)) { + *detailed_error = "Failed to read source connection ID"; + return false; + } } - if (!reader.ReadConnectionId(&source_connection_id, - source_connection_id_length)) { - *detailed_error = "Failed to read source connection ID"; + + if (destination_connection_id.length() != 0) { + *detailed_error = "Received unexpected destination connection ID length"; return false; } memcpy(source_connection_id_bytes, source_connection_id.data(), - source_connection_id_length); - *source_connection_id_length_out = source_connection_id_length; + source_connection_id.length()); + *source_connection_id_length_out = source_connection_id.length(); return true; }
diff --git a/quic/core/quic_framer.h b/quic/core/quic_framer.h index 2349a77..f19c633 100644 --- a/quic/core/quic_framer.h +++ b/quic/core/quic_framer.h
@@ -387,6 +387,43 @@ QuicConnectionId* source_connection_id, std::string* detailed_error); + // Parses the unencryoted fields in a QUIC header using |reader| as input, + // stores the result in the other parameters. + // |expected_destination_connection_id_length| is only used for short headers. + static QuicErrorCode ParsePublicHeader( + QuicDataReader* reader, + uint8_t expected_destination_connection_id_length, + bool ietf_format, + uint8_t* first_byte, + PacketHeaderFormat* format, + bool* version_present, + bool* has_length_prefix, + QuicVersionLabel* version_label, + ParsedQuicVersion* parsed_version, + QuicConnectionId* destination_connection_id, + QuicConnectionId* source_connection_id, + QuicLongHeaderType* long_packet_type, + QuicVariableLengthIntegerLength* retry_token_length_length, + QuicStringPiece* retry_token, + std::string* detailed_error); + + // Parses the unencryoted fields in |packet| and stores them in the other + // parameters. This can only be called on the server. + // |expected_destination_connection_id_length| is only used for short headers. + static QuicErrorCode ParsePublicHeaderDispatcher( + const QuicEncryptedPacket& packet, + uint8_t expected_destination_connection_id_length, + PacketHeaderFormat* format, + bool* version_present, + bool* has_length_prefix, + QuicVersionLabel* version_label, + ParsedQuicVersion* parsed_version, + QuicConnectionId* destination_connection_id, + QuicConnectionId* source_connection_id, + bool* retry_token_present, + QuicStringPiece* retry_token, + std::string* detailed_error); + // Serializes a packet containing |frames| into |buffer|. // Returns the length of the packet, which must not be longer than // |packet_length|. Returns 0 if it fails to serialize. @@ -437,10 +474,12 @@ QuicConnectionId server_connection_id, QuicConnectionId client_connection_id, bool ietf_quic, + bool use_length_prefix, const ParsedQuicVersionVector& versions); // Returns a new IETF version negotiation packet. static std::unique_ptr<QuicEncryptedPacket> BuildIetfVersionNegotiationPacket( + bool use_length_prefix, QuicConnectionId server_connection_id, QuicConnectionId client_connection_id, const ParsedQuicVersionVector& versions); @@ -678,9 +717,6 @@ bool ProcessRetryPacket(QuicDataReader* reader, const QuicPacketHeader& header); - bool MaybeProcessIetfInitialRetryToken(QuicDataReader* encrypted_reader, - QuicPacketHeader* header); - void MaybeProcessCoalescedPacket(const QuicDataReader& encrypted_reader, uint64_t remaining_bytes_length, const QuicPacketHeader& header); @@ -816,6 +852,15 @@ static AckFrameInfo GetAckFrameInfo(const QuicAckFrame& frame); + static QuicErrorCode ParsePublicHeaderGoogleQuic( + QuicDataReader* reader, + uint8_t* first_byte, + PacketHeaderFormat* format, + bool* version_present, + QuicVersionLabel* version_label, + QuicConnectionId* destination_connection_id, + std::string* detailed_error); + // The Append* methods attempt to write the provided header or frame using the // |writer|, and return true if successful. @@ -945,6 +990,7 @@ void set_error(QuicErrorCode error) { error_ = error; } void set_detailed_error(const char* error) { detailed_error_ = error; } + void set_detailed_error(std::string error) { detailed_error_ = error; } std::string detailed_error_; QuicFramerVisitorInterface* visitor_;
diff --git a/quic/core/quic_framer_test.cc b/quic/core/quic_framer_test.cc index d73c412..e2c106a 100644 --- a/quic/core/quic_framer_test.cc +++ b/quic/core/quic_framer_test.cc
@@ -218,7 +218,7 @@ QUIC_DLOG(INFO) << "QuicFramer Version Mismatch, version: " << received_version; ++version_mismatch_; - return true; + return false; } bool OnUnauthenticatedPublicHeader(const QuicPacketHeader& header) override { @@ -917,11 +917,25 @@ QuicConnectionId destination_connection_id, source_connection_id; QuicVersionLabel version_label; std::string detailed_error; - EXPECT_EQ(QUIC_NO_ERROR, - QuicFramer::ProcessPacketDispatcher( - *encrypted, kQuicDefaultConnectionIdLength, &format, - &version_flag, &version_label, &destination_connection_id, - &source_connection_id, &detailed_error)); + QuicErrorCode error_code; + if (!GetQuicReloadableFlag(quic_use_parse_public_header)) { + error_code = QuicFramer::ProcessPacketDispatcher( + *encrypted, kQuicDefaultConnectionIdLength, &format, &version_flag, + &version_label, &destination_connection_id, &source_connection_id, + &detailed_error); + } else { + bool retry_token_present, use_length_prefix; + QuicStringPiece retry_token; + ParsedQuicVersion parsed_version = UnsupportedQuicVersion(); + error_code = QuicFramer::ParsePublicHeaderDispatcher( + *encrypted, kQuicDefaultConnectionIdLength, &format, &version_flag, + &use_length_prefix, &version_label, &parsed_version, + &destination_connection_id, &source_connection_id, &retry_token_present, + &retry_token, &detailed_error); + EXPECT_FALSE(retry_token_present); + EXPECT_FALSE(use_length_prefix); + } + EXPECT_EQ(QUIC_NO_ERROR, error_code); EXPECT_EQ(GOOGLE_QUIC_PACKET, format); EXPECT_FALSE(version_flag); EXPECT_EQ(kQuicDefaultConnectionIdLength, destination_connection_id.length()); @@ -933,7 +947,7 @@ // clang-format off PacketFragments packet44 = { // type (long header with packet type INITIAL) - {"Unable to read type.", + {"Unable to read first byte.", {0xFF}}, // version tag {"Unable to read protocol version.", @@ -942,7 +956,7 @@ {"Unable to read ConnectionId length.", {0x50}}, // connection_id - {"Unable to read Destination ConnectionId.", + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"Unable to read packet number.", @@ -950,7 +964,7 @@ }; PacketFragments packet46 = { // type (long header with packet type INITIAL) - {"Unable to read type.", + {"Unable to read first byte.", {0xC3}}, // version tag {"Unable to read protocol version.", @@ -959,7 +973,7 @@ {"Unable to read ConnectionId length.", {0x50}}, // connection_id - {"Unable to read Destination ConnectionId.", + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"Unable to read packet number.", @@ -995,11 +1009,24 @@ QuicConnectionId destination_connection_id, source_connection_id; QuicVersionLabel version_label; std::string detailed_error; - EXPECT_EQ(QUIC_NO_ERROR, - QuicFramer::ProcessPacketDispatcher( - *encrypted, kQuicDefaultConnectionIdLength, &format, - &version_flag, &version_label, &destination_connection_id, - &source_connection_id, &detailed_error)); + QuicErrorCode error_code; + if (!GetQuicReloadableFlag(quic_use_parse_public_header)) { + error_code = QuicFramer::ProcessPacketDispatcher( + *encrypted, kQuicDefaultConnectionIdLength, &format, &version_flag, + &version_label, &destination_connection_id, &source_connection_id, + &detailed_error); + } else { + bool retry_token_present, use_length_prefix; + QuicStringPiece retry_token; + ParsedQuicVersion parsed_version = UnsupportedQuicVersion(); + error_code = QuicFramer::ParsePublicHeaderDispatcher( + *encrypted, kQuicDefaultConnectionIdLength, &format, &version_flag, + &use_length_prefix, &version_label, &parsed_version, + &destination_connection_id, &source_connection_id, &retry_token_present, + &retry_token, &detailed_error); + EXPECT_EQ(retry_token_present, framer_.version().SupportsRetry()); + EXPECT_FALSE(use_length_prefix); + } EXPECT_EQ(IETF_QUIC_LONG_HEADER_PACKET, format); EXPECT_TRUE(version_flag); EXPECT_EQ(kQuicDefaultConnectionIdLength, destination_connection_id.length()); @@ -1012,6 +1039,7 @@ // This test requires an IETF long header. return; } + SetQuicReloadableFlag(quic_use_parse_public_header, false); SetQuicRestartFlag(quic_do_not_override_connection_id, true); SetDecrypterLevel(ENCRYPTION_ZERO_RTT); const unsigned char type_byte = @@ -1044,11 +1072,24 @@ QuicConnectionId destination_connection_id, source_connection_id; QuicVersionLabel version_label = 0; std::string detailed_error = ""; - EXPECT_EQ(QUIC_NO_ERROR, - QuicFramer::ProcessPacketDispatcher( - encrypted, kQuicDefaultConnectionIdLength, &format, - &version_flag, &version_label, &destination_connection_id, - &source_connection_id, &detailed_error)); + QuicErrorCode error_code; + if (!GetQuicReloadableFlag(quic_use_parse_public_header)) { + error_code = QuicFramer::ProcessPacketDispatcher( + encrypted, kQuicDefaultConnectionIdLength, &format, &version_flag, + &version_label, &destination_connection_id, &source_connection_id, + &detailed_error); + } else { + bool retry_token_present, use_length_prefix; + QuicStringPiece retry_token; + ParsedQuicVersion parsed_version = UnsupportedQuicVersion(); + error_code = QuicFramer::ParsePublicHeaderDispatcher( + encrypted, kQuicDefaultConnectionIdLength, &format, &version_flag, + &use_length_prefix, &version_label, &parsed_version, + &destination_connection_id, &source_connection_id, &retry_token_present, + &retry_token, &detailed_error); + EXPECT_FALSE(retry_token_present); + EXPECT_FALSE(use_length_prefix); + } EXPECT_EQ("", detailed_error); EXPECT_EQ(IETF_QUIC_LONG_HEADER_PACKET, format); EXPECT_TRUE(version_flag); @@ -1142,7 +1183,7 @@ PacketFragments packet44 = { // type (short header, 4 byte packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0x32}}, // connection_id // packet number @@ -1152,7 +1193,7 @@ PacketFragments packet46 = { // type (short header, 4 byte packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0x43}}, // connection_id // packet number @@ -1162,7 +1203,7 @@ PacketFragments packet_hp = { // type (short header, 4 byte packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0x43}}, // connection_id // packet number @@ -1216,7 +1257,7 @@ PacketFragments packet44 = { // type (long header with packet type ZERO_RTT_PROTECTED) - {"Unable to read type.", + {"Unable to read first byte.", {0xFC}}, // version tag {"Unable to read protocol version.", @@ -1225,7 +1266,7 @@ {"Unable to read ConnectionId length.", {0x50}}, // connection_id - {"Unable to read Destination ConnectionId.", + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"Unable to read packet number.", @@ -1235,7 +1276,7 @@ PacketFragments packet46 = { // type (long header with packet type ZERO_RTT_PROTECTED and 4 bytes // packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0xD3}}, // version tag {"Unable to read protocol version.", @@ -1244,7 +1285,7 @@ {"Unable to read ConnectionId length.", {0x50}}, // connection_id - {"Unable to read Destination ConnectionId.", + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"Unable to read packet number.", @@ -1254,17 +1295,20 @@ PacketFragments packet99 = { // type (long header with packet type ZERO_RTT_PROTECTED and 4 bytes // packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0xD3}}, // version tag {"Unable to read protocol version.", {QUIC_VERSION_BYTES}}, - // connection_id length - {"Unable to read ConnectionId length.", - {0x50}}, - // connection_id - {"Unable to read Destination ConnectionId.", + // destination connection ID length + {"Unable to read destination connection ID.", + {0x08}}, + // destination connection ID + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, + // source connection ID length + {"Unable to read source connection ID.", + {0x00}}, // long header packet length {"Unable to read long header payload length.", {0x04}}, @@ -1315,10 +1359,10 @@ PacketFragments packet44 = { // type (short header, 4 byte packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0x32}}, // connection_id - {"Unable to read Destination ConnectionId.", + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"Unable to read packet number.", @@ -1327,10 +1371,10 @@ PacketFragments packet46 = { // type (short header, 4 byte packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0x43}}, // connection_id - {"Unable to read Destination ConnectionId.", + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"Unable to read packet number.", @@ -1339,10 +1383,10 @@ PacketFragments packet_hp = { // type (short header, 4 byte packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0x43}}, // connection_id - {"Unable to read Destination ConnectionId.", + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", @@ -1390,10 +1434,10 @@ PacketFragments packet44 = { // type (short header, 2 byte packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0x31}}, // connection_id - {"Unable to read Destination ConnectionId.", + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"Unable to read packet number.", @@ -1402,10 +1446,10 @@ PacketFragments packet46 = { // type (short header, 2 byte packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0x41}}, // connection_id - {"Unable to read Destination ConnectionId.", + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"Unable to read packet number.", @@ -1414,10 +1458,10 @@ PacketFragments packet_hp = { // type (short header, 2 byte packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0x41}}, // connection_id - {"Unable to read Destination ConnectionId.", + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", @@ -1473,10 +1517,10 @@ PacketFragments packet44 = { // type (8 byte connection_id and 1 byte packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0x30}}, // connection_id - {"Unable to read Destination ConnectionId.", + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"Unable to read packet number.", @@ -1485,10 +1529,10 @@ PacketFragments packet46 = { // type (8 byte connection_id and 1 byte packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0x40}}, // connection_id - {"Unable to read Destination ConnectionId.", + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"Unable to read packet number.", @@ -1497,10 +1541,10 @@ PacketFragments packet_hp = { // type (8 byte connection_id and 1 byte packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0x40}}, // connection_id - {"Unable to read Destination ConnectionId.", + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", @@ -1677,9 +1721,11 @@ 0xD0, // version tag QUIC_VERSION_BYTES, - // connection_id length - 0x05, - // connection_id + // destination connection ID length + 0x00, + // source connection ID length + 0x08, + // source connection ID 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // long header packet length 0x26, @@ -1775,11 +1821,33 @@ 0x00, 0x00, 0x00, 0x00, 0x00 }; + + unsigned char packet99[] = { + // type (long header, ZERO_RTT_PROTECTED, 4-byte packet number) + 0xD3, + // version tag + 'Q', '0', '0', '0', + // destination connection ID length + 0x08, + // destination connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // source connection ID length + 0x00, + // packet number + 0x12, 0x34, 0x56, 0x78, + + // frame type (padding frame) + 0x00, + 0x00, 0x00, 0x00, 0x00 + }; // clang-format on unsigned char* p = packet; size_t p_size = QUIC_ARRAYSIZE(packet); - if (framer_.transport_version() > QUIC_VERSION_44) { + if (framer_.transport_version() >= QUIC_VERSION_99) { + p = packet99; + p_size = QUIC_ARRAYSIZE(packet99); + } else if (framer_.transport_version() > QUIC_VERSION_44) { p = packet45; p_size = QUIC_ARRAYSIZE(packet45); } else if (framer_.transport_version() > QUIC_VERSION_43) { @@ -1792,8 +1860,6 @@ ASSERT_TRUE(visitor_.header_.get()); EXPECT_EQ(0, visitor_.frame_count_); EXPECT_EQ(1, visitor_.version_mismatch_); - ASSERT_EQ(1u, visitor_.padding_frames_.size()); - EXPECT_EQ(5, visitor_.padding_frames_[0]->num_padding_bytes); } TEST_P(QuicFramerTest, PaddingFrame) { @@ -2213,9 +2279,11 @@ 0xD3, // version tag QUIC_VERSION_BYTES, - // connection_id length - 0x05, - // connection_id + // destination connection ID length + 0x00, + // source connection ID length + 0x08, + // source connection ID 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, // IETF long header payload length 0x05, @@ -2738,12 +2806,15 @@ // version tag {"", {QUIC_VERSION_BYTES}}, - // connection_id length + // destination connection ID length {"", - {0x50}}, - // connection_id + {0x08}}, + // destination connection ID {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, + // source connection ID length + {"", + {0x00}}, // long header packet length {"", {0x1E}}, @@ -5682,12 +5753,34 @@ {QUIC_VERSION_BYTES, 'Q', '2', '.', '0'}}, }; + + PacketFragments packet99 = { + // type (long header) + {"", + {0x8F}}, + // version tag + {"", + {0x00, 0x00, 0x00, 0x00}}, + {"", + {0x08}}, + // connection_id + {"", + {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, + {"", + {0x00}}, + // Supported versions + {"Unable to read supported version in negotiation.", + {QUIC_VERSION_BYTES, + 'Q', '2', '.', '0'}}, + }; // clang-format on QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); PacketFragments& fragments = - framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet; + framer_.transport_version() >= QUIC_VERSION_99 + ? packet99 + : framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet; std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); @@ -5725,9 +5818,30 @@ QUIC_VERSION_BYTES, 'Q', '2', '.', '0', }; + unsigned char packet2[] = { + // public flags (long header with all ignored bits set) + 0xFF, + // version + 0x00, 0x00, 0x00, 0x00, + // destination connection ID length + 0x08, + // destination connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x11, + // source connection ID length + 0x00, + // supported versions + QUIC_VERSION_BYTES, + 'Q', '2', '.', '0', + }; // clang-format on + unsigned char* p = packet; + size_t p_length = QUIC_ARRAYSIZE(packet); + if (framer_.version().HasLengthPrefixedConnectionIds()) { + p = packet2; + p_length = QUIC_ARRAYSIZE(packet2); + } - QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); + QuicEncryptedPacket encrypted(AsChars(p), p_length, false); EXPECT_FALSE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_INVALID_VERSION_NEGOTIATION_PACKET, framer_.error()); EXPECT_EQ("Server received version negotiation packet.", @@ -5796,9 +5910,34 @@ 'H', 'e', 'l', 'l', 'o', ' ', 't', 'h', 'i', 's', ' ', 'i', 's', ' ', 'R', 'E', 'T', 'R', 'Y', '!', }; + unsigned char packet99[] = { + // public flags (long header with packet type RETRY) + 0xF0, + // version + QUIC_VERSION_BYTES, + // destination connection ID length + 0x00, + // source connection ID length + 0x08, + // source connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x11, + // original destination connection ID length + 0x08, + // original destination connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // retry token + 'H', 'e', 'l', 'l', 'o', ' ', 't', 'h', 'i', 's', + ' ', 'i', 's', ' ', 'R', 'E', 'T', 'R', 'Y', '!', + }; // clang-format on - QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); + unsigned char* p = packet; + size_t p_length = QUIC_ARRAYSIZE(packet); + if (framer_.transport_version() == QUIC_VERSION_99) { + p = packet99; + p_length = QUIC_ARRAYSIZE(packet99); + } + QuicEncryptedPacket encrypted(AsChars(p), p_length, false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); @@ -5828,7 +5967,7 @@ // version QUIC_VERSION_BYTES, // connection ID lengths - 0x05, + 0x00, 0x08, // source connection ID 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x11, // original destination connection ID @@ -6557,10 +6696,12 @@ 0xD3, // version tag QUIC_VERSION_BYTES, - // connection_id length - 0x50, - // connection_id + // destination connection ID length + 0x08, + // destination connection ID 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // source connection ID length + 0x00, // length 0x40, 0x1D, // packet number @@ -6786,10 +6927,28 @@ 0xDA, 0x5A, 0x3A, 0x3A, QUIC_VERSION_BYTES, }; + unsigned char packet99[] = { + // type (long header) + 0xC0, + // version tag + 0x00, 0x00, 0x00, 0x00, + // destination connection ID length + 0x00, + // source connection ID length + 0x08, + // source connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // supported versions + 0xDA, 0x5A, 0x3A, 0x3A, + QUIC_VERSION_BYTES, + }; // clang-format on unsigned char* p = packet; size_t p_size = QUIC_ARRAYSIZE(packet); - if (framer_.transport_version() > QUIC_VERSION_43) { + if (framer_.transport_version() >= QUIC_VERSION_99) { + p = packet99; + p_size = QUIC_ARRAYSIZE(packet99); + } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; p_size = QUIC_ARRAYSIZE(packet44); } @@ -6799,14 +6958,14 @@ QuicFramer::BuildVersionNegotiationPacket( connection_id, EmptyQuicConnectionId(), framer_.transport_version() > QUIC_VERSION_43, + framer_.version().HasLengthPrefixedConnectionIds(), SupportedVersions(GetParam()))); test::CompareCharArraysWithHexError("constructed packet", data->data(), data->length(), AsChars(p), p_size); } TEST_P(QuicFramerTest, BuildVersionNegotiationPacketWithClientConnectionId) { - if (framer_.transport_version() <= QUIC_VERSION_43) { - // The GQUIC encoding does not support encoding client connection IDs. + if (!framer_.version().SupportsClientConnectionIds()) { return; } @@ -6821,11 +6980,11 @@ 0xC0, // version tag 0x00, 0x00, 0x00, 0x00, - // connection ID lengths - 0x55, // client/destination connection ID + 0x08, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x11, // server/source connection ID + 0x08, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // supported versions 0xDA, 0x5A, 0x3A, 0x3A, @@ -6836,9 +6995,9 @@ QuicConnectionId server_connection_id = FramerTestConnectionId(); QuicConnectionId client_connection_id = FramerTestConnectionIdPlusOne(); std::unique_ptr<QuicEncryptedPacket> data( - QuicFramer::BuildVersionNegotiationPacket(server_connection_id, - client_connection_id, true, - SupportedVersions(GetParam()))); + QuicFramer::BuildVersionNegotiationPacket( + server_connection_id, client_connection_id, true, true, + SupportedVersions(GetParam()))); test::CompareCharArraysWithHexError("constructed packet", data->data(), data->length(), AsChars(packet), QUIC_ARRAYSIZE(packet)); @@ -9873,10 +10032,12 @@ 0xD3, // version tag 'Q', '.', '1', '0', - // connection_id length - 0x50, - // connection_id + // destination connection ID length + 0x08, + // destination connection ID 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // source connection ID length + 0x00, // packet number 0x12, 0x34, 0x56, 0x78, @@ -13051,9 +13212,11 @@ // version QUIC_VERSION_BYTES, // destination connection ID length - 0x50, + 0x08, // destination connection ID 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // source connection ID length + 0x00, // long header packet length 0x1E, // packet number @@ -13078,9 +13241,11 @@ // version QUIC_VERSION_BYTES, // destination connection ID length - 0x50, + 0x08, // destination connection ID 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // source connection ID length + 0x00, // long header packet length 0x1E, // packet number @@ -13146,9 +13311,11 @@ // version QUIC_VERSION_BYTES, // destination connection ID length - 0x50, + 0x08, // destination connection ID 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // source connection ID length + 0x00, // long header packet length 0x1E, // packet number @@ -13173,9 +13340,11 @@ // version QUIC_VERSION_BYTES, // destination connection ID length - 0x50, + 0x08, // destination connection ID 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x11, + // source connection ID length + 0x00, // long header packet length 0x1E, // packet number @@ -13229,9 +13398,11 @@ // version QUIC_VERSION_BYTES, // destination connection ID length - 0x50, + 0x08, // destination connection ID 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // source connection ID length + 0x00, // long header packet length 0x1E, // packet number @@ -13327,7 +13498,8 @@ // Make sure we discard the subsequent zeroes. EXPECT_QUIC_PEER_BUG(EXPECT_TRUE(framer_.ProcessPacket(encrypted)), - "Server: Received mismatched coalesced header.*"); + "Server: (Failed to parse received|Received mismatched) " + "coalesced header.*"); } TEST_P(QuicFramerTest, ClientReceivesInvalidVersion) { @@ -13376,10 +13548,10 @@ // clang-format off PacketFragments packet = { // type (8 byte connection_id and 1 byte packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0x40}}, // connection_id - {"Unable to read Destination ConnectionId.", + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, 0x42}}, // packet number {"Unable to read packet number.", @@ -13388,10 +13560,10 @@ PacketFragments packet_with_padding = { // type (8 byte connection_id and 1 byte packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0x40}}, // connection_id - {"Unable to read Destination ConnectionId.", + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, 0x42}}, // packet number {"", @@ -13451,9 +13623,11 @@ // version QUIC_VERSION_BYTES, // destination connection ID length - 0x50, + 0x08, // destination connection ID 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // source connection ID length + 0x00, // long header packet length 0x05, // packet number @@ -13535,7 +13709,7 @@ // clang-format off PacketFragments packet = { // public flags (IETF Retry packet, 0-length original destination CID) - {"Unable to read type.", + {"Unable to read first byte.", {0xf0}}, // version tag {"Unable to read protocol version.", @@ -13549,7 +13723,7 @@ // clang-format off PacketFragments packet45 = { // public flags (IETF Retry packet, 0-length original destination CID) - {"Unable to read type.", + {"Unable to read first byte.", {0xf0}}, // version tag {"Unable to read protocol version.", @@ -13580,7 +13754,7 @@ // clang-format off PacketFragments packet = { // public flags (IETF Retry packet, 0-length original destination CID) - {"Unable to read type.", + {"Unable to read first byte.", {0xf0}}, // version tag {"Unable to read protocol version.", @@ -13677,7 +13851,8 @@ CheckFramingBoundaries(packet, QUIC_INVALID_PACKET_HEADER); } -TEST_P(QuicFramerTest, WriteClientVersionNegotiationProbePacket) { +TEST_P(QuicFramerTest, WriteClientVersionNegotiationProbePacketOld) { + SetQuicFlag(FLAGS_quic_prober_uses_length_prefixed_connection_ids, false); // clang-format off static const char expected_packet[1200] = { // IETF long header with fixed bit set, type initial, all-0 encrypted bits. @@ -13726,17 +13901,18 @@ EXPECT_TRUE(QuicFramer::WriteClientVersionNegotiationProbePacket( packet, sizeof(packet), destination_connection_id_bytes, sizeof(destination_connection_id_bytes))); - test::CompareCharArraysWithHexError("constructed packet", expected_packet, - sizeof(expected_packet), packet, - sizeof(packet)); + test::CompareCharArraysWithHexError("constructed packet", packet, + sizeof(packet), expected_packet, + sizeof(expected_packet)); QuicEncryptedPacket encrypted(reinterpret_cast<const char*>(packet), sizeof(packet), false); // Make sure we fail to parse this packet for the version under test. - EXPECT_FALSE(framer_.ProcessPacket(encrypted)); if (framer_.transport_version() <= QUIC_VERSION_43) { // We can only parse the connection ID with an IETF parser. + EXPECT_FALSE(framer_.ProcessPacket(encrypted)); return; } + EXPECT_TRUE(framer_.ProcessPacket(encrypted)); ASSERT_TRUE(visitor_.header_.get()); QuicConnectionId probe_payload_connection_id( reinterpret_cast<const char*>(destination_connection_id_bytes), @@ -13745,7 +13921,232 @@ visitor_.header_.get()->destination_connection_id); } -TEST_P(QuicFramerTest, ParseServerVersionNegotiationProbeResponse) { +TEST_P(QuicFramerTest, WriteClientVersionNegotiationProbePacket) { + SetQuicFlag(FLAGS_quic_prober_uses_length_prefixed_connection_ids, true); + // clang-format off + static const char expected_packet[1200] = { + // IETF long header with fixed bit set, type initial, all-0 encrypted bits. + 0xc0, + // Version, part of the IETF space reserved for negotiation. + 0xca, 0xba, 0xda, 0xda, + // Destination connection ID length 8. + 0x08, + // 8-byte destination connection ID. + 0x56, 0x4e, 0x20, 0x70, 0x6c, 0x7a, 0x20, 0x21, + // Source connection ID length 0. + 0x00, + // 8 bytes of zeroes followed by 8 bytes of ones to ensure that this does + // not parse with any known version. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + // zeroes to pad to 16 byte boundary. + 0x00, + // A polite greeting in case a human sees this in tcpdump. + 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x61, 0x63, + 0x6b, 0x65, 0x74, 0x20, 0x6f, 0x6e, 0x6c, 0x79, + 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x20, + 0x74, 0x6f, 0x20, 0x74, 0x72, 0x69, 0x67, 0x67, + 0x65, 0x72, 0x20, 0x49, 0x45, 0x54, 0x46, 0x20, + 0x51, 0x55, 0x49, 0x43, 0x20, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6e, 0x65, 0x67, + 0x6f, 0x74, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x20, 0x50, 0x6c, 0x65, 0x61, 0x73, 0x65, + 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x20, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, + 0x4e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x61, 0x63, 0x6b, + 0x65, 0x74, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x77, 0x68, + 0x61, 0x74, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x20, 0x79, 0x6f, 0x75, 0x20, + 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x20, 0x54, 0x68, 0x61, 0x6e, 0x6b, 0x20, 0x79, + 0x6f, 0x75, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x68, + 0x61, 0x76, 0x65, 0x20, 0x61, 0x20, 0x6e, 0x69, + 0x63, 0x65, 0x20, 0x64, 0x61, 0x79, 0x2e, 0x00, + }; + // clang-format on + char packet[1200]; + char destination_connection_id_bytes[] = {0x56, 0x4e, 0x20, 0x70, + 0x6c, 0x7a, 0x20, 0x21}; + EXPECT_TRUE(QuicFramer::WriteClientVersionNegotiationProbePacket( + packet, sizeof(packet), destination_connection_id_bytes, + sizeof(destination_connection_id_bytes))); + test::CompareCharArraysWithHexError("constructed packet", packet, + sizeof(packet), expected_packet, + sizeof(expected_packet)); + QuicEncryptedPacket encrypted(reinterpret_cast<const char*>(packet), + sizeof(packet), false); + if (framer_.transport_version() < QUIC_VERSION_99) { + // We can only parse the connection ID with a v99 parser. + EXPECT_FALSE(framer_.ProcessPacket(encrypted)); + return; + } + EXPECT_TRUE(framer_.ProcessPacket(encrypted)); + ASSERT_TRUE(visitor_.header_.get()); + QuicConnectionId probe_payload_connection_id( + reinterpret_cast<const char*>(destination_connection_id_bytes), + sizeof(destination_connection_id_bytes)); + EXPECT_EQ(probe_payload_connection_id, + visitor_.header_.get()->destination_connection_id); +} + +TEST_P(QuicFramerTest, DispatcherParseOldClientVersionNegotiationProbePacket) { + // clang-format off + static const char packet[1200] = { + // IETF long header with fixed bit set, type initial, all-0 encrypted bits. + 0xc0, + // Version, part of the IETF space reserved for negotiation. + 0xca, 0xba, 0xda, 0xba, + // Destination connection ID length 8, source connection ID length 0. + 0x50, + // 8-byte destination connection ID. + 0x56, 0x4e, 0x20, 0x70, 0x6c, 0x7a, 0x20, 0x21, + // 8 bytes of zeroes followed by 8 bytes of ones to ensure that this does + // not parse with any known version. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + // 2 bytes of zeroes to pad to 16 byte boundary. + 0x00, 0x00, + // A polite greeting in case a human sees this in tcpdump. + 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x61, 0x63, + 0x6b, 0x65, 0x74, 0x20, 0x6f, 0x6e, 0x6c, 0x79, + 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x20, + 0x74, 0x6f, 0x20, 0x74, 0x72, 0x69, 0x67, 0x67, + 0x65, 0x72, 0x20, 0x49, 0x45, 0x54, 0x46, 0x20, + 0x51, 0x55, 0x49, 0x43, 0x20, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6e, 0x65, 0x67, + 0x6f, 0x74, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x20, 0x50, 0x6c, 0x65, 0x61, 0x73, 0x65, + 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x20, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, + 0x4e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x61, 0x63, 0x6b, + 0x65, 0x74, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x77, 0x68, + 0x61, 0x74, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x20, 0x79, 0x6f, 0x75, 0x20, + 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x20, 0x54, 0x68, 0x61, 0x6e, 0x6b, 0x20, 0x79, + 0x6f, 0x75, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x68, + 0x61, 0x76, 0x65, 0x20, 0x61, 0x20, 0x6e, 0x69, + 0x63, 0x65, 0x20, 0x64, 0x61, 0x79, 0x2e, 0x00, + }; + // clang-format on + char expected_destination_connection_id_bytes[] = {0x56, 0x4e, 0x20, 0x70, + 0x6c, 0x7a, 0x20, 0x21}; + QuicConnectionId expected_destination_connection_id( + reinterpret_cast<const char*>(expected_destination_connection_id_bytes), + sizeof(expected_destination_connection_id_bytes)); + + QuicEncryptedPacket encrypted(reinterpret_cast<const char*>(packet), + sizeof(packet)); + PacketHeaderFormat format = GOOGLE_QUIC_PACKET; + bool version_present = false, has_length_prefix = true; + QuicVersionLabel version_label = 33; + ParsedQuicVersion parsed_version = UnsupportedQuicVersion(); + QuicConnectionId destination_connection_id = TestConnectionId(1); + QuicConnectionId source_connection_id = TestConnectionId(2); + bool retry_token_present = true; + QuicStringPiece retry_token; + std::string detailed_error = "foobar"; + QuicErrorCode header_parse_result = QuicFramer::ParsePublicHeaderDispatcher( + encrypted, kQuicDefaultConnectionIdLength, &format, &version_present, + &has_length_prefix, &version_label, &parsed_version, + &destination_connection_id, &source_connection_id, &retry_token_present, + &retry_token, &detailed_error); + EXPECT_EQ(QUIC_NO_ERROR, header_parse_result); + EXPECT_EQ(IETF_QUIC_LONG_HEADER_PACKET, format); + EXPECT_TRUE(version_present); + EXPECT_FALSE(has_length_prefix); + EXPECT_EQ(0xcabadaba, version_label); + EXPECT_EQ(expected_destination_connection_id, destination_connection_id); + EXPECT_EQ(EmptyQuicConnectionId(), source_connection_id); + EXPECT_FALSE(retry_token_present); + EXPECT_EQ("", detailed_error); +} + +TEST_P(QuicFramerTest, DispatcherParseClientVersionNegotiationProbePacket) { + // clang-format off + static const char packet[1200] = { + // IETF long header with fixed bit set, type initial, all-0 encrypted bits. + 0xc0, + // Version, part of the IETF space reserved for negotiation. + 0xca, 0xba, 0xda, 0xba, + // Destination connection ID length 8. + 0x08, + // 8-byte destination connection ID. + 0x56, 0x4e, 0x20, 0x70, 0x6c, 0x7a, 0x20, 0x21, + // Source connection ID length 0. + 0x00, + // 8 bytes of zeroes followed by 8 bytes of ones to ensure that this does + // not parse with any known version. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + // 1 byte of zeroes to pad to 16 byte boundary. + 0x00, + // A polite greeting in case a human sees this in tcpdump. + 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x61, 0x63, + 0x6b, 0x65, 0x74, 0x20, 0x6f, 0x6e, 0x6c, 0x79, + 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x20, + 0x74, 0x6f, 0x20, 0x74, 0x72, 0x69, 0x67, 0x67, + 0x65, 0x72, 0x20, 0x49, 0x45, 0x54, 0x46, 0x20, + 0x51, 0x55, 0x49, 0x43, 0x20, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6e, 0x65, 0x67, + 0x6f, 0x74, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x20, 0x50, 0x6c, 0x65, 0x61, 0x73, 0x65, + 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x20, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, + 0x4e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x61, 0x63, 0x6b, + 0x65, 0x74, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x77, 0x68, + 0x61, 0x74, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x20, 0x79, 0x6f, 0x75, 0x20, + 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x20, 0x54, 0x68, 0x61, 0x6e, 0x6b, 0x20, 0x79, + 0x6f, 0x75, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x68, + 0x61, 0x76, 0x65, 0x20, 0x61, 0x20, 0x6e, 0x69, + 0x63, 0x65, 0x20, 0x64, 0x61, 0x79, 0x2e, 0x00, + }; + // clang-format on + char expected_destination_connection_id_bytes[] = {0x56, 0x4e, 0x20, 0x70, + 0x6c, 0x7a, 0x20, 0x21}; + QuicConnectionId expected_destination_connection_id( + reinterpret_cast<const char*>(expected_destination_connection_id_bytes), + sizeof(expected_destination_connection_id_bytes)); + + QuicEncryptedPacket encrypted(reinterpret_cast<const char*>(packet), + sizeof(packet)); + PacketHeaderFormat format = GOOGLE_QUIC_PACKET; + bool version_present = false, has_length_prefix = false; + QuicVersionLabel version_label = 33; + ParsedQuicVersion parsed_version = UnsupportedQuicVersion(); + QuicConnectionId destination_connection_id = TestConnectionId(1); + QuicConnectionId source_connection_id = TestConnectionId(2); + bool retry_token_present = true; + QuicStringPiece retry_token; + std::string detailed_error = "foobar"; + QuicErrorCode header_parse_result = QuicFramer::ParsePublicHeaderDispatcher( + encrypted, kQuicDefaultConnectionIdLength, &format, &version_present, + &has_length_prefix, &version_label, &parsed_version, + &destination_connection_id, &source_connection_id, &retry_token_present, + &retry_token, &detailed_error); + EXPECT_EQ(QUIC_NO_ERROR, header_parse_result); + EXPECT_EQ(IETF_QUIC_LONG_HEADER_PACKET, format); + EXPECT_TRUE(version_present); + EXPECT_TRUE(has_length_prefix); + EXPECT_EQ(0xcabadaba, version_label); + EXPECT_EQ(expected_destination_connection_id, destination_connection_id); + EXPECT_EQ(EmptyQuicConnectionId(), source_connection_id); + EXPECT_EQ("", detailed_error); +} + +TEST_P(QuicFramerTest, ParseServerVersionNegotiationProbeResponseOld) { + SetQuicFlag(FLAGS_quic_prober_uses_length_prefixed_connection_ids, false); // clang-format off const char packet[] = { // IETF long header with fixed bit set, type initial, all-0 encrypted bits. @@ -13771,8 +14172,39 @@ &parsed_probe_payload_length, &parse_detailed_error)); EXPECT_EQ("", parse_detailed_error); test::CompareCharArraysWithHexError( - "parsed probe", probe_payload_bytes, sizeof(probe_payload_bytes), - parsed_probe_payload_bytes, parsed_probe_payload_length); + "parsed probe", parsed_probe_payload_bytes, parsed_probe_payload_length, + probe_payload_bytes, sizeof(probe_payload_bytes)); +} + +TEST_P(QuicFramerTest, ParseServerVersionNegotiationProbeResponse) { + SetQuicFlag(FLAGS_quic_prober_uses_length_prefixed_connection_ids, true); + // clang-format off + const char packet[] = { + // IETF long header with fixed bit set, type initial, all-0 encrypted bits. + 0xc0, + // Version of 0, indicating version negotiation. + 0x00, 0x00, 0x00, 0x00, + // Destination connection ID length 0, source connection ID length 8. + 0x00, 0x08, + // 8-byte source connection ID. + 0x56, 0x4e, 0x20, 0x70, 0x6c, 0x7a, 0x20, 0x21, + // A few supported versions. + 0xaa, 0xaa, 0xaa, 0xaa, + QUIC_VERSION_BYTES, + }; + // clang-format on + char probe_payload_bytes[] = {0x56, 0x4e, 0x20, 0x70, 0x6c, 0x7a, 0x20, 0x21}; + char parsed_probe_payload_bytes[kQuicMaxConnectionIdLength] = {}; + uint8_t parsed_probe_payload_length = 0; + std::string parse_detailed_error = ""; + EXPECT_TRUE(QuicFramer::ParseServerVersionNegotiationProbeResponse( + reinterpret_cast<const char*>(packet), sizeof(packet), + reinterpret_cast<char*>(parsed_probe_payload_bytes), + &parsed_probe_payload_length, &parse_detailed_error)); + EXPECT_EQ("", parse_detailed_error); + test::CompareCharArraysWithHexError( + "parsed probe", parsed_probe_payload_bytes, parsed_probe_payload_length, + probe_payload_bytes, sizeof(probe_payload_bytes)); } TEST_P(QuicFramerTest, ClientConnectionIdFromLongHeaderToClient) { @@ -13802,9 +14234,34 @@ // padding frame 0x00, }; + unsigned char packet99[] = { + // public flags (long header with packet type HANDSHAKE and + // 4-byte packet number) + 0xE3, + // version + QUIC_VERSION_BYTES, + // destination connection ID length + 0x08, + // destination connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // source connection ID length + 0x00, + // long header packet length + 0x05, + // packet number + 0x12, 0x34, 0x56, 0x00, + // padding frame + 0x00, + }; // clang-format on - const bool parse_success = framer_.ProcessPacket( - QuicEncryptedPacket(AsChars(packet), QUIC_ARRAYSIZE(packet), false)); + unsigned char* p = packet; + size_t p_length = QUIC_ARRAYSIZE(packet); + if (framer_.transport_version() == QUIC_VERSION_99) { + p = packet99; + p_length = QUIC_ARRAYSIZE(packet99); + } + const bool parse_success = + framer_.ProcessPacket(QuicEncryptedPacket(AsChars(p), p_length, false)); if (!QuicUtils::VariableLengthConnectionIdAllowedForVersion( framer_.transport_version())) { EXPECT_FALSE(parse_success); @@ -13855,9 +14312,32 @@ // padding frame 0x00, }; + unsigned char packet99[] = { + // public flags (long header with packet type HANDSHAKE and + // 4-byte packet number) + 0xE3, + // version + QUIC_VERSION_BYTES, + // connection ID lengths + 0x00, 0x08, + // source connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // long header packet length + 0x05, + // packet number + 0x12, 0x34, 0x56, 0x00, + // padding frame + 0x00, + }; // clang-format on - const bool parse_success = framer_.ProcessPacket( - QuicEncryptedPacket(AsChars(packet), QUIC_ARRAYSIZE(packet), false)); + unsigned char* p = packet; + size_t p_length = QUIC_ARRAYSIZE(packet); + if (framer_.transport_version() == QUIC_VERSION_99) { + p = packet99; + p_length = QUIC_ARRAYSIZE(packet99); + } + const bool parse_success = + framer_.ProcessPacket(QuicEncryptedPacket(AsChars(p), p_length, false)); if (!QuicUtils::VariableLengthConnectionIdAllowedForVersion( framer_.transport_version())) { EXPECT_FALSE(parse_success);
diff --git a/quic/core/quic_ietf_framer_test.cc b/quic/core/quic_ietf_framer_test.cc index dbbacdd..f0872b6 100644 --- a/quic/core/quic_ietf_framer_test.cc +++ b/quic/core/quic_ietf_framer_test.cc
@@ -102,7 +102,7 @@ bool OnProtocolVersionMismatch( ParsedQuicVersion /*received_version*/) override { - return true; + return false; } bool OnUnauthenticatedPublicHeader(
diff --git a/quic/core/quic_packet_creator.cc b/quic/core/quic_packet_creator.cc index a8d3291..27c913e 100644 --- a/quic/core/quic_packet_creator.cc +++ b/quic/core/quic_packet_creator.cc
@@ -640,12 +640,13 @@ std::unique_ptr<QuicEncryptedPacket> QuicPacketCreator::SerializeVersionNegotiationPacket( bool ietf_quic, + bool use_length_prefix, const ParsedQuicVersionVector& supported_versions) { DCHECK_EQ(Perspective::IS_SERVER, framer_->perspective()); std::unique_ptr<QuicEncryptedPacket> encrypted = - QuicFramer::BuildVersionNegotiationPacket(server_connection_id_, - client_connection_id_, - ietf_quic, supported_versions); + QuicFramer::BuildVersionNegotiationPacket( + server_connection_id_, client_connection_id_, ietf_quic, + use_length_prefix, supported_versions); DCHECK(encrypted); DCHECK_GE(max_packet_length_, encrypted->length()); return encrypted;
diff --git a/quic/core/quic_packet_creator.h b/quic/core/quic_packet_creator.h index 2c2fffb..affc15c 100644 --- a/quic/core/quic_packet_creator.h +++ b/quic/core/quic_packet_creator.h
@@ -187,6 +187,7 @@ // Creates a version negotiation packet which supports |supported_versions|. std::unique_ptr<QuicEncryptedPacket> SerializeVersionNegotiationPacket( bool ietf_quic, + bool use_length_prefix, const ParsedQuicVersionVector& supported_versions); // Creates a connectivity probing packet for versions prior to version 99.
diff --git a/quic/core/quic_packet_creator_test.cc b/quic/core/quic_packet_creator_test.cc index 802c07b..bd49182 100644 --- a/quic/core/quic_packet_creator_test.cc +++ b/quic/core/quic_packet_creator_test.cc
@@ -813,8 +813,11 @@ versions.push_back(test::QuicVersionMax()); const bool ietf_quic = VersionHasIetfInvariantHeader(GetParam().version.transport_version); + const bool has_length_prefix = + GetParam().version.HasLengthPrefixedConnectionIds(); std::unique_ptr<QuicEncryptedPacket> encrypted( - creator_.SerializeVersionNegotiationPacket(ietf_quic, versions)); + creator_.SerializeVersionNegotiationPacket(ietf_quic, has_length_prefix, + versions)); { InSequence s; @@ -1820,6 +1823,9 @@ if (QuicVersionHasLongHeaderLengths(version)) { expected_largest_payload -= 2; } + if (GetParam().version.HasLengthPrefixedConnectionIds()) { + expected_largest_payload -= 1; + } EXPECT_EQ(expected_largest_payload, creator_.GetGuaranteedLargestMessagePayload()); }
diff --git a/quic/core/quic_packet_generator.cc b/quic/core/quic_packet_generator.cc index fe17069..160222f 100644 --- a/quic/core/quic_packet_generator.cc +++ b/quic/core/quic_packet_generator.cc
@@ -297,9 +297,10 @@ std::unique_ptr<QuicEncryptedPacket> QuicPacketGenerator::SerializeVersionNegotiationPacket( bool ietf_quic, + bool use_length_prefix, const ParsedQuicVersionVector& supported_versions) { - return packet_creator_.SerializeVersionNegotiationPacket(ietf_quic, - supported_versions); + return packet_creator_.SerializeVersionNegotiationPacket( + ietf_quic, use_length_prefix, supported_versions); } OwningSerializedPacketPointer
diff --git a/quic/core/quic_packet_generator.h b/quic/core/quic_packet_generator.h index ea7da5d..c6902e0 100644 --- a/quic/core/quic_packet_generator.h +++ b/quic/core/quic_packet_generator.h
@@ -141,6 +141,7 @@ // Creates a version negotiation packet which supports |supported_versions|. std::unique_ptr<QuicEncryptedPacket> SerializeVersionNegotiationPacket( bool ietf_quic, + bool use_length_prefix, const ParsedQuicVersionVector& supported_versions); // Creates a connectivity probing packet.
diff --git a/quic/core/quic_packets.cc b/quic/core/quic_packets.cc index 4887e82..7d4769f 100644 --- a/quic/core/quic_packets.cc +++ b/quic/core/quic_packets.cc
@@ -134,6 +134,9 @@ if (include_diversification_nonce) { size += kDiversificationNonceSize; } + if (VersionHasLengthPrefixedConnectionIds(version)) { + size += kConnectionIdLengthSize; + } DCHECK(QuicVersionHasLongHeaderLengths(version) || !GetQuicReloadableFlag(quic_fix_get_packet_header_size) || retry_token_length_length + retry_token_length + length_length == @@ -508,6 +511,7 @@ packet(packet), form(GOOGLE_QUIC_PACKET), version_flag(false), + use_length_prefix(false), version_label(0), version(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED), destination_connection_id(EmptyQuicConnectionId()),
diff --git a/quic/core/quic_packets.h b/quic/core/quic_packets.h index cf6099e..3af15ea 100644 --- a/quic/core/quic_packets.h +++ b/quic/core/quic_packets.h
@@ -425,6 +425,7 @@ // Fields below are populated by QuicFramer::ProcessPacketDispatcher. PacketHeaderFormat form; bool version_flag; + bool use_length_prefix; QuicVersionLabel version_label; ParsedQuicVersion version; QuicConnectionId destination_connection_id;
diff --git a/quic/core/quic_time_wait_list_manager.cc b/quic/core/quic_time_wait_list_manager.cc index cb29a40..a0e7cfb 100644 --- a/quic/core/quic_time_wait_list_manager.cc +++ b/quic/core/quic_time_wait_list_manager.cc
@@ -206,17 +206,20 @@ QuicConnectionId server_connection_id, QuicConnectionId client_connection_id, bool ietf_quic, + bool use_length_prefix, const ParsedQuicVersionVector& supported_versions, const QuicSocketAddress& self_address, const QuicSocketAddress& peer_address, std::unique_ptr<QuicPerPacketContext> packet_context) { std::unique_ptr<QuicEncryptedPacket> version_packet = - QuicFramer::BuildVersionNegotiationPacket(server_connection_id, - client_connection_id, ietf_quic, - supported_versions); + QuicFramer::BuildVersionNegotiationPacket( + server_connection_id, client_connection_id, ietf_quic, + use_length_prefix, supported_versions); QUIC_DVLOG(2) << "Dispatcher sending version negotiation packet: {" << ParsedQuicVersionVectorToString(supported_versions) << "}, " - << (ietf_quic ? "" : "!") << "ietf_quic:" << std::endl + << (ietf_quic ? "" : "!") + << "ietf_quic:" << (use_length_prefix ? "" : "!") + << "use_length_prefix:" << std::endl << QuicTextUtils::HexDump(QuicStringPiece( version_packet->data(), version_packet->length())); SendOrQueuePacket(QuicMakeUnique<QueuedPacket>(self_address, peer_address,
diff --git a/quic/core/quic_time_wait_list_manager.h b/quic/core/quic_time_wait_list_manager.h index c53632c..9a807c0 100644 --- a/quic/core/quic_time_wait_list_manager.h +++ b/quic/core/quic_time_wait_list_manager.h
@@ -125,6 +125,7 @@ QuicConnectionId server_connection_id, QuicConnectionId client_connection_id, bool ietf_quic, + bool use_length_prefix, const ParsedQuicVersionVector& supported_versions, const QuicSocketAddress& self_address, const QuicSocketAddress& peer_address,
diff --git a/quic/core/quic_time_wait_list_manager_test.cc b/quic/core/quic_time_wait_list_manager_test.cc index 0d9e32a..daa6431 100644 --- a/quic/core/quic_time_wait_list_manager_test.cc +++ b/quic/core/quic_time_wait_list_manager_test.cc
@@ -251,31 +251,50 @@ TEST_F(QuicTimeWaitListManagerTest, SendVersionNegotiationPacket) { std::unique_ptr<QuicEncryptedPacket> packet( - QuicFramer::BuildVersionNegotiationPacket(connection_id_, - EmptyQuicConnectionId(), false, - AllSupportedVersions())); + QuicFramer::BuildVersionNegotiationPacket( + connection_id_, EmptyQuicConnectionId(), /*ietf_quic=*/false, + /*use_length_prefix=*/false, AllSupportedVersions())); EXPECT_CALL(writer_, WritePacket(_, packet->length(), self_address_.host(), peer_address_, _)) .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1))); time_wait_list_manager_.SendVersionNegotiationPacket( - connection_id_, EmptyQuicConnectionId(), false, AllSupportedVersions(), - self_address_, peer_address_, QuicMakeUnique<QuicPerPacketContext>()); + connection_id_, EmptyQuicConnectionId(), /*ietf_quic=*/false, + /*use_length_prefix=*/false, AllSupportedVersions(), self_address_, + peer_address_, QuicMakeUnique<QuicPerPacketContext>()); + EXPECT_EQ(0u, time_wait_list_manager_.num_connections()); +} + +TEST_F(QuicTimeWaitListManagerTest, + SendIetfVersionNegotiationPacketWithoutLengthPrefix) { + std::unique_ptr<QuicEncryptedPacket> packet( + QuicFramer::BuildVersionNegotiationPacket( + connection_id_, EmptyQuicConnectionId(), /*ietf_quic=*/true, + /*use_length_prefix=*/false, AllSupportedVersions())); + EXPECT_CALL(writer_, WritePacket(_, packet->length(), self_address_.host(), + peer_address_, _)) + .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1))); + + time_wait_list_manager_.SendVersionNegotiationPacket( + connection_id_, EmptyQuicConnectionId(), /*ietf_quic=*/true, + /*use_length_prefix=*/false, AllSupportedVersions(), self_address_, + peer_address_, QuicMakeUnique<QuicPerPacketContext>()); EXPECT_EQ(0u, time_wait_list_manager_.num_connections()); } TEST_F(QuicTimeWaitListManagerTest, SendIetfVersionNegotiationPacket) { std::unique_ptr<QuicEncryptedPacket> packet( - QuicFramer::BuildVersionNegotiationPacket(connection_id_, - EmptyQuicConnectionId(), true, - AllSupportedVersions())); + QuicFramer::BuildVersionNegotiationPacket( + connection_id_, EmptyQuicConnectionId(), /*ietf_quic=*/true, + /*use_length_prefix=*/true, AllSupportedVersions())); EXPECT_CALL(writer_, WritePacket(_, packet->length(), self_address_.host(), peer_address_, _)) .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1))); time_wait_list_manager_.SendVersionNegotiationPacket( - connection_id_, EmptyQuicConnectionId(), true, AllSupportedVersions(), - self_address_, peer_address_, QuicMakeUnique<QuicPerPacketContext>()); + connection_id_, EmptyQuicConnectionId(), /*ietf_quic=*/true, + /*use_length_prefix=*/true, AllSupportedVersions(), self_address_, + peer_address_, QuicMakeUnique<QuicPerPacketContext>()); EXPECT_EQ(0u, time_wait_list_manager_.num_connections()); } @@ -285,16 +304,17 @@ SetQuicRestartFlag(quic_do_not_override_connection_id, true); std::unique_ptr<QuicEncryptedPacket> packet( - QuicFramer::BuildVersionNegotiationPacket(connection_id_, - TestConnectionId(0x33), true, - AllSupportedVersions())); + QuicFramer::BuildVersionNegotiationPacket( + connection_id_, TestConnectionId(0x33), /*ietf_quic=*/true, + /*use_length_prefix=*/true, AllSupportedVersions())); EXPECT_CALL(writer_, WritePacket(_, packet->length(), self_address_.host(), peer_address_, _)) .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1))); time_wait_list_manager_.SendVersionNegotiationPacket( - connection_id_, TestConnectionId(0x33), true, AllSupportedVersions(), - self_address_, peer_address_, QuicMakeUnique<QuicPerPacketContext>()); + connection_id_, TestConnectionId(0x33), /*ietf_quic=*/true, + /*use_length_prefix=*/true, AllSupportedVersions(), self_address_, + peer_address_, QuicMakeUnique<QuicPerPacketContext>()); EXPECT_EQ(0u, time_wait_list_manager_.num_connections()); }
diff --git a/quic/core/quic_utils.h b/quic/core/quic_utils.h index 294f52f..db29740 100644 --- a/quic/core/quic_utils.h +++ b/quic/core/quic_utils.h
@@ -109,7 +109,7 @@ TransmissionType retransmission_type); // Returns true if header with |first_byte| is considered as an IETF QUIC - // packet header. + // packet header. This only works on the server. static bool IsIetfPacketHeader(uint8_t first_byte); // Returns true if header with |first_byte| is considered as an IETF QUIC
diff --git a/quic/core/quic_versions.cc b/quic/core/quic_versions.cc index 950dd1d..406d44b 100644 --- a/quic/core/quic_versions.cc +++ b/quic/core/quic_versions.cc
@@ -84,6 +84,10 @@ return VersionLacksHeadersStream(transport_version); } +bool ParsedQuicVersion::HasLengthPrefixedConnectionIds() const { + return VersionHasLengthPrefixedConnectionIds(transport_version); +} + bool VersionLacksHeadersStream(QuicTransportVersion transport_version) { if (GetQuicFlag(FLAGS_quic_headers_stream_id_in_v99) == 0) { return false; @@ -91,6 +95,11 @@ return transport_version == QUIC_VERSION_99; } +bool VersionHasLengthPrefixedConnectionIds( + QuicTransportVersion transport_version) { + return transport_version >= QUIC_VERSION_99; +} + std::ostream& operator<<(std::ostream& os, const ParsedQuicVersion& version) { os << ParsedQuicVersionToString(version); return os; @@ -418,6 +427,34 @@ return result; } +bool QuicVersionLabelUses4BitConnectionIdLength( + QuicVersionLabel version_label) { + // As we deprecate old versions, we still need the ability to send valid + // version negotiation packets for those versions. This function keeps track + // of the versions that ever supported the 4bit connection ID length encoding + // that we know about. Google QUIC 43 and earlier used a different encoding, + // and Google QUIC 49 will start using the new length prefixed encoding. + // Similarly, only IETF drafts 11 to 21 used this encoding. + + // Check Q044, Q045, Q046, Q047 and Q048. + for (uint8_t c = '4'; c <= '8'; ++c) { + if (version_label == MakeVersionLabel('Q', '0', '4', c)) { + return true; + } + } + // Check T048. + if (version_label == MakeVersionLabel('T', '0', '4', '8')) { + return true; + } + // Check IETF draft versions in [11,21]. + for (uint8_t draft_number = 11; draft_number <= 21; ++draft_number) { + if (version_label == MakeVersionLabel(0xff, 0x00, 0x00, draft_number)) { + return true; + } + } + return false; +} + ParsedQuicVersion UnsupportedQuicVersion() { return ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED); } @@ -453,6 +490,7 @@ SetQuicFlag(FLAGS_quic_supports_tls_handshake, true); SetQuicFlag(FLAGS_quic_headers_stream_id_in_v99, 60); SetQuicReloadableFlag(quic_simplify_stop_waiting, true); + SetQuicReloadableFlag(quic_use_parse_public_header, true); SetQuicRestartFlag(quic_do_not_override_connection_id, true); SetQuicRestartFlag(quic_use_allocated_connection_ids, true); SetQuicRestartFlag(quic_dispatcher_hands_chlo_extractor_one_version, true);
diff --git a/quic/core/quic_versions.h b/quic/core/quic_versions.h index 72bb32c..3edb895 100644 --- a/quic/core/quic_versions.h +++ b/quic/core/quic_versions.h
@@ -175,6 +175,11 @@ // Returns whether this version does not have the Google QUIC headers stream. bool DoesNotHaveHeadersStream() const; + + // Returns whether this version supports long header 8-bit encoded + // connection ID lengths as described in draft-ietf-quic-invariants-06 and + // draft-ietf-quic-transport-22. + bool HasLengthPrefixedConnectionIds() const; }; QUIC_EXPORT_PRIVATE ParsedQuicVersion UnsupportedQuicVersion(); @@ -426,6 +431,18 @@ return transport_version >= QUIC_VERSION_99; } +// Returns whether this version supports long header 8-bit encoded +// connection ID lengths as described in draft-ietf-quic-invariants-06 and +// draft-ietf-quic-transport-22. +QUIC_EXPORT_PRIVATE bool VersionHasLengthPrefixedConnectionIds( + QuicTransportVersion transport_version); + +// Returns whether this version label supports long header 4-bit encoded +// connection ID lengths as described in draft-ietf-quic-invariants-05 and +// draft-ietf-quic-transport-21. +QUIC_EXPORT_PRIVATE bool QuicVersionLabelUses4BitConnectionIdLength( + QuicVersionLabel version_label); + // Returns the ALPN string to use in TLS for this version of QUIC. QUIC_EXPORT_PRIVATE std::string AlpnForVersion( ParsedQuicVersion parsed_version);
diff --git a/quic/test_tools/mock_quic_time_wait_list_manager.h b/quic/test_tools/mock_quic_time_wait_list_manager.h index b46e68b..6b2b6d0 100644 --- a/quic/test_tools/mock_quic_time_wait_list_manager.h +++ b/quic/test_tools/mock_quic_time_wait_list_manager.h
@@ -45,10 +45,11 @@ PacketHeaderFormat header_format, std::unique_ptr<QuicPerPacketContext> packet_context)); - MOCK_METHOD7(SendVersionNegotiationPacket, + MOCK_METHOD8(SendVersionNegotiationPacket, void(QuicConnectionId server_connection_id, QuicConnectionId client_connection_id, bool ietf_quic, + bool has_length_prefix, const ParsedQuicVersionVector& supported_versions, const QuicSocketAddress& server_address, const QuicSocketAddress& client_address,