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,