Update to MoQT draft-10. Use new extensions encoding (just passing a blob) Status datagrams also have extensions. PiperOrigin-RevId: 736218941
diff --git a/quiche/quic/moqt/moqt_framer.cc b/quiche/quic/moqt/moqt_framer.cc index 60ba2ea..5d98ec3 100644 --- a/quiche/quic/moqt/moqt_framer.cc +++ b/quiche/quic/moqt/moqt_framer.cc
@@ -173,67 +173,6 @@ const MoqtSubscribeParameters& list_; }; -class WireExtensionHeader { - public: - explicit WireExtensionHeader(const MoqtExtensionHeader& header) - : header_(header) {} - - size_t GetLengthOnWire() { - if ((header_.type % 2) == 0) { - return quiche::ComputeLengthOnWire( - WireVarInt62(header_.type), - WireVarInt62(absl::get<uint64_t>(header_.value))); - } else { - return quiche::ComputeLengthOnWire( - WireVarInt62(header_.type), - WireStringWithVarInt62Length(absl::get<std::string>(header_.value))); - } - } - - absl::Status SerializeIntoWriter(quiche::QuicheDataWriter& writer) { - if ((header_.type % 2) == 0) { - if (!absl::holds_alternative<uint64_t>(header_.value)) { - return absl::InvalidArgumentError("Extension type is not uint64_t"); - } - return quiche::SerializeIntoWriter( - writer, WireVarInt62(header_.type), - WireVarInt62(absl::get<uint64_t>(header_.value))); - } else { - if (!absl::holds_alternative<std::string>(header_.value)) { - return absl::InvalidArgumentError("Extension type is not std::string"); - } - return quiche::SerializeIntoWriter( - writer, WireVarInt62(header_.type), - WireStringWithVarInt62Length(absl::get<std::string>(header_.value))); - } - } - - private: - const MoqtExtensionHeader& header_; -}; - -class WireExtensionHeaderList { - public: - explicit WireExtensionHeaderList( - const std::vector<MoqtExtensionHeader>& headers) - : headers_(headers) {} - - size_t GetLengthOnWire() { - return quiche::ComputeLengthOnWire( - WireVarInt62(headers_.size()), - WireSpan<WireExtensionHeader, MoqtExtensionHeader>(headers_)); - } - - absl::Status SerializeIntoWriter(quiche::QuicheDataWriter& writer) { - return quiche::SerializeIntoWriter( - writer, WireVarInt62(headers_.size()), - WireSpan<WireExtensionHeader, MoqtExtensionHeader>(headers_)); - } - - private: - const std::vector<MoqtExtensionHeader>& headers_; -}; - class WireFullTrackName { public: using DataType = FullTrackName; @@ -342,34 +281,34 @@ switch (message_type) { case MoqtDataStreamType::kStreamHeaderSubgroup: return (message.payload_length == 0) - ? Serialize( - WireVarInt62(message.object_id), - WireExtensionHeaderList(message.extension_headers), - WireVarInt62(message.payload_length), - WireVarInt62( - static_cast<uint64_t>(message.object_status))) - : Serialize( - WireVarInt62(message.object_id), - WireExtensionHeaderList(message.extension_headers), - WireVarInt62(message.payload_length)); + ? Serialize(WireVarInt62(message.object_id), + WireStringWithVarInt62Length( + message.extension_headers), + WireVarInt62(message.payload_length), + WireVarInt62(static_cast<uint64_t>( + message.object_status))) + : Serialize(WireVarInt62(message.object_id), + WireStringWithVarInt62Length( + message.extension_headers), + WireVarInt62(message.payload_length)); case MoqtDataStreamType::kStreamHeaderFetch: return (message.payload_length == 0) - ? Serialize( - WireVarInt62(message.group_id), - WireVarInt62(*message.subgroup_id), - WireVarInt62(message.object_id), - WireUint8(message.publisher_priority), - WireExtensionHeaderList(message.extension_headers), - WireVarInt62(message.payload_length), - WireVarInt62( - static_cast<uint64_t>(message.object_status))) - : Serialize( - WireVarInt62(message.group_id), - WireVarInt62(*message.subgroup_id), - WireVarInt62(message.object_id), - WireUint8(message.publisher_priority), - WireExtensionHeaderList(message.extension_headers), - WireVarInt62(message.payload_length)); + ? Serialize(WireVarInt62(message.group_id), + WireVarInt62(*message.subgroup_id), + WireVarInt62(message.object_id), + WireUint8(message.publisher_priority), + WireStringWithVarInt62Length( + message.extension_headers), + WireVarInt62(message.payload_length), + WireVarInt62(static_cast<uint64_t>( + message.object_status))) + : Serialize(WireVarInt62(message.group_id), + WireVarInt62(*message.subgroup_id), + WireVarInt62(message.object_id), + WireUint8(message.publisher_priority), + WireStringWithVarInt62Length( + message.extension_headers), + WireVarInt62(message.payload_length)); default: QUICHE_NOTREACHED(); return quiche::QuicheBuffer(); @@ -378,42 +317,46 @@ switch (message_type) { case MoqtDataStreamType::kStreamHeaderSubgroup: return (message.payload_length == 0) - ? Serialize(WireVarInt62(message_type), - WireVarInt62(message.track_alias), - WireVarInt62(message.group_id), - WireVarInt62(*message.subgroup_id), - WireUint8(message.publisher_priority), - WireVarInt62(message.object_id), - WireExtensionHeaderList(message.extension_headers), - WireVarInt62(message.payload_length), - WireVarInt62(message.object_status)) - : Serialize(WireVarInt62(message_type), - WireVarInt62(message.track_alias), - WireVarInt62(message.group_id), - WireVarInt62(*message.subgroup_id), - WireUint8(message.publisher_priority), - WireVarInt62(message.object_id), - WireExtensionHeaderList(message.extension_headers), - WireVarInt62(message.payload_length)); + ? Serialize( + WireVarInt62(message_type), + WireVarInt62(message.track_alias), + WireVarInt62(message.group_id), + WireVarInt62(*message.subgroup_id), + WireUint8(message.publisher_priority), + WireVarInt62(message.object_id), + WireStringWithVarInt62Length(message.extension_headers), + WireVarInt62(message.payload_length), + WireVarInt62(message.object_status)) + : Serialize( + WireVarInt62(message_type), + WireVarInt62(message.track_alias), + WireVarInt62(message.group_id), + WireVarInt62(*message.subgroup_id), + WireUint8(message.publisher_priority), + WireVarInt62(message.object_id), + WireStringWithVarInt62Length(message.extension_headers), + WireVarInt62(message.payload_length)); case MoqtDataStreamType::kStreamHeaderFetch: return (message.payload_length == 0) - ? Serialize(WireVarInt62(message_type), - WireVarInt62(message.track_alias), - WireVarInt62(message.group_id), - WireVarInt62(*message.subgroup_id), - WireVarInt62(message.object_id), - WireUint8(message.publisher_priority), - WireExtensionHeaderList(message.extension_headers), - WireVarInt62(message.payload_length), - WireVarInt62(message.object_status)) - : Serialize(WireVarInt62(message_type), - WireVarInt62(message.track_alias), - WireVarInt62(message.group_id), - WireVarInt62(*message.subgroup_id), - WireVarInt62(message.object_id), - WireUint8(message.publisher_priority), - WireExtensionHeaderList(message.extension_headers), - WireVarInt62(message.payload_length)); + ? Serialize( + WireVarInt62(message_type), + WireVarInt62(message.track_alias), + WireVarInt62(message.group_id), + WireVarInt62(*message.subgroup_id), + WireVarInt62(message.object_id), + WireUint8(message.publisher_priority), + WireStringWithVarInt62Length(message.extension_headers), + WireVarInt62(message.payload_length), + WireVarInt62(message.object_status)) + : Serialize( + WireVarInt62(message_type), + WireVarInt62(message.track_alias), + WireVarInt62(message.group_id), + WireVarInt62(*message.subgroup_id), + WireVarInt62(message.object_id), + WireUint8(message.publisher_priority), + WireStringWithVarInt62Length(message.extension_headers), + WireVarInt62(message.payload_length)); default: QUICHE_NOTREACHED(); return quiche::QuicheBuffer(); @@ -437,13 +380,14 @@ WireVarInt62(MoqtDatagramType::kObjectStatus), WireVarInt62(message.track_alias), WireVarInt62(message.group_id), WireVarInt62(message.object_id), WireUint8(message.publisher_priority), + WireStringWithVarInt62Length(message.extension_headers), WireVarInt62(message.object_status)); } return Serialize( WireVarInt62(MoqtDatagramType::kObject), WireVarInt62(message.track_alias), WireVarInt62(message.group_id), WireVarInt62(message.object_id), WireUint8(message.publisher_priority), - WireExtensionHeaderList(message.extension_headers), + WireStringWithVarInt62Length(message.extension_headers), WireVarInt62(message.payload_length), WireBytes(payload)); }
diff --git a/quiche/quic/moqt/moqt_framer_test.cc b/quiche/quic/moqt/moqt_framer_test.cc index 798e2f0..7a347f5 100644 --- a/quiche/quic/moqt/moqt_framer_test.cc +++ b/quiche/quic/moqt/moqt_framer_test.cc
@@ -13,7 +13,6 @@ #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" -#include "absl/types/variant.h" #include "quiche/quic/moqt/moqt_messages.h" #include "quiche/quic/moqt/moqt_priority.h" #include "quiche/quic/moqt/test_tools/moqt_test_message.h" @@ -301,7 +300,7 @@ /*group_id=*/5, /*object_id=*/6, /*publisher_priority=*/7, - /*extension_headers=*/std::vector<MoqtExtensionHeader>({}), + std::string(kDefaultExtensionBlob.data(), kDefaultExtensionBlob.size()), /*object_status=*/MoqtObjectStatus::kNormal, /*subgroup_id=*/8, /*payload_length=*/3, @@ -340,7 +339,7 @@ /*group_id=*/5, /*object_id=*/6, /*publisher_priority=*/7, - /*extension_headers=*/std::vector<MoqtExtensionHeader>({}), + std::string(kDefaultExtensionBlob), /*object_status=*/MoqtObjectStatus::kNormal, /*subgroup_id=*/std::nullopt, /*payload_length=*/3, @@ -371,8 +370,7 @@ /*group_id=*/5, /*object_id=*/6, /*publisher_priority=*/7, - std::vector<MoqtExtensionHeader>( - {MoqtExtensionHeader(0, 12ULL), MoqtExtensionHeader(1, "foo")}), + std::string(kDefaultExtensionBlob), /*object_status=*/MoqtObjectStatus::kNormal, /*subgroup_id=*/std::nullopt, /*payload_length=*/3, @@ -391,7 +389,7 @@ /*group_id=*/5, /*object_id=*/6, /*publisher_priority=*/7, - std::vector<MoqtExtensionHeader>({}), + std::string(kDefaultExtensionBlob), /*object_status=*/MoqtObjectStatus::kEndOfGroup, /*subgroup_id=*/std::nullopt, /*payload_length=*/0, @@ -533,38 +531,6 @@ EXPECT_EQ(*end_group, 5); } -TEST_F(MoqtFramerSimpleTest, InvalidExtensionType) { - MoqtObject object = { - /*track_alias=*/4, - /*group_id=*/5, - /*object_id=*/6, - /*publisher_priority=*/7, - /*extension_headers=*/ - std::vector<MoqtExtensionHeader>({MoqtExtensionHeader(0, 12ULL)}), - /*object_status=*/MoqtObjectStatus::kNormal, - /*subgroup_id=*/std::nullopt, - /*payload_length=*/3, - }; - EXPECT_QUIC_BUG(framer_.SerializeObjectHeader( - object, MoqtDataStreamType::kStreamHeaderSubgroup, false), - "Object metadata is invalid"); - - object = { - /*track_alias=*/4, - /*group_id=*/5, - /*object_id=*/6, - /*publisher_priority=*/7, - /*extension_headers=*/ - std::vector<MoqtExtensionHeader>({MoqtExtensionHeader(1, "foo")}), - /*object_status=*/MoqtObjectStatus::kNormal, - /*subgroup_id=*/std::nullopt, - /*payload_length=*/3, - }; - EXPECT_QUIC_BUG(framer_.SerializeObjectHeader( - object, MoqtDataStreamType::kStreamHeaderSubgroup, false), - "Object metadata is invalid"); -} - TEST_F(MoqtFramerSimpleTest, JoiningFetch) { JoiningFetchMessage message; quiche::QuicheBuffer buffer =
diff --git a/quiche/quic/moqt/moqt_messages.h b/quiche/quic/moqt/moqt_messages.h index af78e4d..d961905 100644 --- a/quiche/quic/moqt/moqt_messages.h +++ b/quiche/quic/moqt/moqt_messages.h
@@ -36,11 +36,11 @@ } enum class MoqtVersion : uint64_t { - kDraft08 = 0xff000008, + kDraft10 = 0xff00000a, kUnrecognizedVersionForTests = 0xfe0000ff, }; -inline constexpr MoqtVersion kDefaultMoqtVersion = MoqtVersion::kDraft08; +inline constexpr MoqtVersion kDefaultMoqtVersion = MoqtVersion::kDraft10; inline constexpr uint64_t kDefaultInitialMaxSubscribeId = 100; inline constexpr uint64_t kMinNamespaceElements = 1; inline constexpr uint64_t kMaxNamespaceElements = 32; @@ -340,11 +340,6 @@ MoqtObjectStatus IntegerToObjectStatus(uint64_t integer); -struct MoqtExtensionHeader { - uint64_t type; - absl::variant<uint64_t, std::string> value; -}; - // The data contained in every Object message, although the message type // implies some of the values. struct QUICHE_EXPORT MoqtObject { @@ -352,7 +347,7 @@ uint64_t group_id; uint64_t object_id; MoqtPriority publisher_priority; - std::vector<MoqtExtensionHeader> extension_headers; + std::string extension_headers; // Raw, unparsed extension headers. MoqtObjectStatus object_status; std::optional<uint64_t> subgroup_id; uint64_t payload_length;
diff --git a/quiche/quic/moqt/moqt_parser.cc b/quiche/quic/moqt/moqt_parser.cc index 5233a6b..6a79a96 100644 --- a/quiche/quic/moqt/moqt_parser.cc +++ b/quiche/quic/moqt/moqt_parser.cc
@@ -66,8 +66,6 @@ return false; } -bool IsExtensionTypeVarint(uint64_t type) { return (type % 2 == 0); } - } // namespace // The buffering philosophy is complicated, to minimize copying. Here is an @@ -964,14 +962,17 @@ std::optional<absl::string_view> ParseDatagram(absl::string_view data, MoqtObject& object_metadata) { uint64_t type_raw, object_status_raw; + absl::string_view extensions; quic::QuicDataReader reader(data); if (!reader.ReadVarInt62(&type_raw) || !reader.ReadVarInt62(&object_metadata.track_alias) || !reader.ReadVarInt62(&object_metadata.group_id) || !reader.ReadVarInt62(&object_metadata.object_id) || - !reader.ReadUInt8(&object_metadata.publisher_priority)) { + !reader.ReadUInt8(&object_metadata.publisher_priority) || + !reader.ReadStringPieceVarInt62(&extensions)) { return std::nullopt; } + object_metadata.extension_headers = std::string(extensions); if (static_cast<MoqtDatagramType>(type_raw) == MoqtDatagramType::kObjectStatus) { object_metadata.payload_length = 0; @@ -981,30 +982,7 @@ object_metadata.object_status = IntegerToObjectStatus(object_status_raw); return ""; } - uint64_t extensions_remaining; - if (!reader.ReadVarInt62(&extensions_remaining)) { - return std::nullopt; - } - while (extensions_remaining > 0) { - uint64_t type; - if (!reader.ReadVarInt62(&type)) { - return std::nullopt; - } - --extensions_remaining; - if (IsExtensionTypeVarint(type)) { - uint64_t value; - if (!reader.ReadVarInt62(&value)) { - return std::nullopt; - } - object_metadata.extension_headers.push_back({type, value}); - } else { - absl::string_view value; - if (!reader.ReadStringPieceVarInt62(&value)) { - return std::nullopt; - } - object_metadata.extension_headers.push_back({type, std::string(value)}); - } - } + absl::string_view payload; if (!reader.ReadStringPieceVarInt62(&payload)) { return std::nullopt; @@ -1111,26 +1089,20 @@ next_input_ = is_fetch ? kObjectId : kPublisherPriority; break; case kPublisherPriority: - next_input_ = is_fetch ? kExtensionCount : kObjectId; + next_input_ = is_fetch ? kExtensionSize : kObjectId; break; case kObjectId: - next_input_ = is_fetch ? kPublisherPriority : kExtensionCount; + next_input_ = is_fetch ? kPublisherPriority : kExtensionSize; break; - case kExtensionLength: - next_input_ = kExtensionPayload; + case kExtensionBody: + next_input_ = kObjectPayloadLength; break; - case kStatus: case kData: next_input_ = is_fetch ? kGroupId : kObjectId; break; - case kExtensionCount: // Either kExtensionType or - // kObjectPayloadLength. - case kExtensionType: // Either kExtensionVarint or kExtensionLength. - case kExtensionVarint: // Either kExtensionType or - // kObjectPayloadLength. - case kExtensionPayload: // Either kExtensionType or + case kExtensionSize: // Either kExtensionBody or // kObjectPayloadLength. case kObjectPayloadLength: // Either kStatus or kData depending on length. case kPadding: // Handled separately. @@ -1211,50 +1183,12 @@ return; } - case kExtensionCount: { + case kExtensionSize: { std::optional<uint64_t> value_read = ReadVarInt62NoFin(); if (value_read.has_value()) { - extensions_remaining_ = *value_read; - next_input_ = (extensions_remaining_ == 0) ? kObjectPayloadLength - : kExtensionType; metadata_.extension_headers.clear(); - } - return; - } - - case kExtensionType: { - std::optional<uint64_t> value_read = ReadVarInt62NoFin(); - if (value_read.has_value()) { - --extensions_remaining_; - current_extension_.type = *value_read; - next_input_ = IsExtensionTypeVarint(*value_read) ? kExtensionVarint - : kExtensionLength; - } - return; - } - - case kExtensionVarint: { - std::optional<uint64_t> value_read = ReadVarInt62NoFin(); - if (value_read.has_value()) { - next_input_ = (extensions_remaining_ == 0) ? kObjectPayloadLength - : kExtensionType; - current_extension_.value = *value_read; - metadata_.extension_headers.push_back(current_extension_); - current_extension_.value = ""; - } - return; - } - - case kExtensionLength: { - std::optional<uint64_t> value_read = ReadVarInt62NoFin(); - if (value_read.has_value()) { - if (*value_read > 0) { - next_input_ = kExtensionPayload; - payload_length_remaining_ = *value_read; - } else { - next_input_ = (extensions_remaining_ == 0) ? kObjectPayloadLength - : kExtensionType; - } + payload_length_remaining_ = *value_read; + next_input_ = (value_read == 0) ? kObjectPayloadLength : kExtensionBody; } return; } @@ -1295,7 +1229,7 @@ return; } - case kExtensionPayload: + case kExtensionBody: case kData: { while (payload_length_remaining_ > 0) { quiche::ReadStream::PeekResult peek_result = @@ -1322,17 +1256,14 @@ AdvanceParserState(); } } else { - std::get<std::string>(current_extension_.value) - .append(peek_result.peeked_data.substr(0, chunk_size)); + absl::StrAppend(&metadata_.extension_headers, + peek_result.peeked_data.substr(0, chunk_size)); if (stream_.SkipBytes(chunk_size)) { ParseError("FIN received at an unexpected point in the stream"); return; } if (done) { - next_input_ = (extensions_remaining_ == 0) ? kObjectPayloadLength - : kExtensionType; - metadata_.extension_headers.push_back(current_extension_); - current_extension_.value = ""; + AdvanceParserState(); } } }
diff --git a/quiche/quic/moqt/moqt_parser.h b/quiche/quic/moqt/moqt_parser.h index 97727d5..d9e5d0f 100644 --- a/quiche/quic/moqt/moqt_parser.h +++ b/quiche/quic/moqt/moqt_parser.h
@@ -223,11 +223,8 @@ kSubgroupId, kPublisherPriority, kObjectId, - kExtensionCount, - kExtensionType, - kExtensionVarint, - kExtensionLength, - kExtensionPayload, + kExtensionSize, + kExtensionBody, kObjectPayloadLength, kStatus, kData, @@ -241,13 +238,10 @@ struct State { NextInput next_input; uint64_t payload_remaining; - uint64_t extensions_remaining; bool operator==(const State&) const = default; }; - State state() const { - return State{next_input_, payload_length_remaining_, extensions_remaining_}; - } + State state() const { return State{next_input_, payload_length_remaining_}; } void ReadDataUntil(StopCondition stop_condition); @@ -282,9 +276,7 @@ NextInput next_input_ = kStreamType; MoqtObject metadata_; size_t payload_length_remaining_ = 0; - uint64_t extensions_remaining_ = 0; size_t num_objects_read_ = 0; - MoqtExtensionHeader current_extension_; bool processing_ = false; // True if currently in ProcessData(), to prevent // re-entrancy.
diff --git a/quiche/quic/moqt/moqt_parser_test.cc b/quiche/quic/moqt/moqt_parser_test.cc index 03b9856..926980e 100644 --- a/quiche/quic/moqt/moqt_parser_test.cc +++ b/quiche/quic/moqt/moqt_parser_test.cc
@@ -504,6 +504,27 @@ EXPECT_FALSE(visitor_.parsing_error_.has_value()); } +TEST_F(MoqtMessageSpecificTest, ObjectSplitInExtension) { + webtransport::test::InMemoryStream stream(/*stream_id=*/0); + MoqtDataParser parser(&stream, &visitor_); + auto message = std::make_unique<StreamHeaderSubgroupMessage>(); + + // first part + stream.Receive(message->PacketSample().substr(0, 10), false); + parser.ReadAllData(); + EXPECT_EQ(visitor_.messages_received_, 0); + + // second part + stream.Receive( + message->PacketSample().substr(10, sizeof(message->total_message_size())), + false); + parser.ReadAllData(); + EXPECT_EQ(visitor_.messages_received_, 1); + EXPECT_TRUE(visitor_.last_message_.has_value() && + message->EqualFieldValues(*visitor_.last_message_)); + EXPECT_TRUE(visitor_.end_of_message_); +} + TEST_F(MoqtMessageSpecificTest, StreamHeaderSubgroupFollowOn) { webtransport::test::InMemoryStream stream(/*stream_id=*/0); MoqtDataParser parser(&stream, &visitor_);
diff --git a/quiche/quic/moqt/moqt_session_test.cc b/quiche/quic/moqt/moqt_session_test.cc index c4e9332..a89565d 100644 --- a/quiche/quic/moqt/moqt_session_test.cc +++ b/quiche/quic/moqt/moqt_session_test.cc
@@ -941,7 +941,7 @@ /*group_sequence=*/0, /*object_sequence=*/0, /*publisher_priority=*/0, - std::vector<MoqtExtensionHeader>(), + /*extension_headers=*/"", /*object_status=*/MoqtObjectStatus::kNormal, /*subgroup_id=*/0, /*payload_length=*/8, @@ -967,7 +967,7 @@ /*group_sequence=*/0, /*object_sequence=*/0, /*publisher_priority=*/0, - std::vector<MoqtExtensionHeader>(), + /*extension_headers=*/"", /*object_status=*/MoqtObjectStatus::kNormal, /*subgroup_id=*/0, /*payload_length=*/16, @@ -999,7 +999,7 @@ /*group_sequence=*/0, /*object_sequence=*/0, /*publisher_priority=*/0, - std::vector<MoqtExtensionHeader>(), + /*extension_headers=*/"", /*object_status=*/MoqtObjectStatus::kNormal, /*subgroup_id=*/0, /*payload_length=*/16, @@ -1026,7 +1026,7 @@ /*group_sequence=*/0, /*object_sequence=*/0, /*publisher_priority=*/0, - std::vector<MoqtExtensionHeader>(), + /*extension_headers=*/"", /*object_status=*/MoqtObjectStatus::kNormal, /*subgroup_id=*/0, /*payload_length=*/8, @@ -1072,7 +1072,7 @@ /*group_sequence=*/0, /*object_sequence=*/0, /*publisher_priority=*/0, - std::vector<MoqtExtensionHeader>(), + /*extension_headers=*/"", /*object_status=*/MoqtObjectStatus::kNormal, /*subgroup_id=*/0, /*payload_length=*/8, @@ -1440,7 +1440,7 @@ // Reopen the window. correct_message = false; - // object id, payload length, status. + // object id, extensions, payload length, status. const std::string kExpectedMessage2 = {0x01, 0x00, 0x00, 0x03}; EXPECT_CALL(mock_stream, CanWrite()).WillRepeatedly([&] { return true; }); EXPECT_CALL(*track, GetCachedObject(FullSequence(5, 1))).WillRepeatedly([&] { @@ -1779,7 +1779,7 @@ /*group_sequence=*/0, /*object_sequence=*/0, /*publisher_priority=*/0, - std::vector<MoqtExtensionHeader>(), + /*extension_headers=*/"", /*object_status=*/MoqtObjectStatus::kNormal, /*subgroup_id=*/std::nullopt, /*payload_length=*/8, @@ -1804,7 +1804,7 @@ /*group_sequence=*/0, /*object_sequence=*/0, /*publisher_priority=*/0, - std::vector<MoqtExtensionHeader>(), + /*extension_headers=*/"", /*object_status=*/MoqtObjectStatus::kNormal, /*subgroup_id=*/0, /*payload_length=*/8, @@ -1838,7 +1838,7 @@ /*group_sequence=*/0, /*object_sequence=*/0, /*publisher_priority=*/0, - std::vector<MoqtExtensionHeader>(), + /*extension_headers=*/"", /*object_status=*/MoqtObjectStatus::kNormal, /*subgroup_id=*/0, /*payload_length=*/8, @@ -2473,7 +2473,7 @@ /*group_id, object_id=*/0, 0, /*publisher_priority=*/128, - std::vector<MoqtExtensionHeader>(), + /*extension_headers=*/"", /*status=*/MoqtObjectStatus::kNormal, /*subgroup=*/0, /*payload_length=*/3, @@ -2623,7 +2623,7 @@ /*group_id, object_id=*/0, 0, /*publisher_priority=*/128, - std::vector<MoqtExtensionHeader>(), + /*extension_headers=*/"", /*status=*/MoqtObjectStatus::kNormal, /*subgroup=*/0, /*payload_length=*/3, @@ -2694,7 +2694,7 @@ /*group_id, object_id=*/0, 0, /*publisher_priority=*/128, - std::vector<MoqtExtensionHeader>(), + /*extension_headers=*/"", /*status=*/MoqtObjectStatus::kNormal, /*subgroup=*/0, /*payload_length=*/3, @@ -2785,7 +2785,7 @@ /*group_id, object_id=*/0, 0, /*publisher_priority=*/128, - std::vector<MoqtExtensionHeader>(), + /*extension_headers=*/"", /*status=*/MoqtObjectStatus::kNormal, /*subgroup=*/0, /*payload_length=*/6, @@ -3216,7 +3216,7 @@ /*group_id=*/0, /*object_id=*/0, /*publisher_priority=*/7, - std::vector<MoqtExtensionHeader>(), + /*extension_headers=*/"", /*object_status=*/MoqtObjectStatus::kGroupDoesNotExist, /*subgroup_id=*/0, /*payload_length=*/0, @@ -3273,7 +3273,7 @@ /*group_id=*/0, /*object_id=*/0, /*publisher_priority=*/7, - std::vector<MoqtExtensionHeader>(), + /*extension_headers=*/"", /*object_status=*/MoqtObjectStatus::kGroupDoesNotExist, /*subgroup_id=*/0, /*payload_length=*/0, @@ -3327,7 +3327,7 @@ /*group_id=*/0, /*object_id=*/0, /*publisher_priority=*/7, - std::vector<MoqtExtensionHeader>(), + /*extension_headers=*/"", /*object_status=*/MoqtObjectStatus::kGroupDoesNotExist, /*subgroup_id=*/0, /*payload_length=*/0,
diff --git a/quiche/quic/moqt/moqt_track_test.cc b/quiche/quic/moqt/moqt_track_test.cc index 13a6700..1a9fbc4 100644 --- a/quiche/quic/moqt/moqt_track_test.cc +++ b/quiche/quic/moqt/moqt_track_test.cc
@@ -4,9 +4,11 @@ #include "quiche/quic/moqt/moqt_track.h" +#include <cstdint> #include <memory> #include <optional> #include <utility> +#include <vector> #include "absl/memory/memory.h" #include "absl/status/status.h" @@ -174,14 +176,7 @@ PublishedObject object; EXPECT_EQ(fetch_task_->GetNextObject(object), MoqtFetchTask::GetNextObjectResult::kPending); - MoqtObject new_object = {1, - 3, - 0, - 128, - std::vector<MoqtExtensionHeader>(), - MoqtObjectStatus::kNormal, - 0, - 6}; + MoqtObject new_object = {1, 3, 0, 128, "", MoqtObjectStatus::kNormal, 0, 6}; bool got_object = false; fetch_task_->SetObjectAvailableCallback([&]() { got_object = true;
diff --git a/quiche/quic/moqt/test_tools/moqt_test_message.h b/quiche/quic/moqt/test_tools/moqt_test_message.h index 9da46f0..1eca5c6 100644 --- a/quiche/quic/moqt/test_tools/moqt_test_message.h +++ b/quiche/quic/moqt/test_tools/moqt_test_message.h
@@ -11,6 +11,7 @@ #include <memory> #include <optional> #include <string> +#include <utility> #include <vector> #include "absl/strings/string_view.h" @@ -26,6 +27,9 @@ namespace moqt::test { +inline constexpr absl::string_view kDefaultExtensionBlob( + "\x00\x0c\x01\x03\x66\x6f\x6f", 7); + // Base class containing a wire image and the corresponding structured // representation of an example of each message. It allows parser and framer // tests to iterate through all message types without much specialized code. @@ -164,7 +168,7 @@ class QUICHE_NO_EXPORT ObjectMessage : public TestMessageBase { public: bool EqualFieldValues(MessageStructuredData& values) const override { - auto cast = std::get<MoqtObject>(values); + auto cast = std::move(std::get<MoqtObject>(values)); if (cast.track_alias != object_.track_alias) { QUIC_LOG(INFO) << "OBJECT Track ID mismatch"; return false; @@ -181,21 +185,10 @@ QUIC_LOG(INFO) << "OBJECT Publisher Priority mismatch"; return false; } - if (cast.extension_headers.size() != object_.extension_headers.size()) { - QUIC_LOG(INFO) << "OBJECT Extension Header size mismatch"; + if (cast.extension_headers != object_.extension_headers) { + QUIC_LOG(INFO) << "OBJECT Extension Header mismatch"; return false; } - for (size_t i = 0; i < cast.extension_headers.size(); ++i) { - if (cast.extension_headers[i].type != object_.extension_headers[i].type) { - QUIC_LOG(INFO) << "OBJECT Extension Header type mismatch"; - return false; - } - if (cast.extension_headers[i].value != - object_.extension_headers[i].value) { - QUIC_LOG(INFO) << "OBJECT Extension Header value mismatch"; - return false; - } - } if (cast.object_status != object_.object_status) { QUIC_LOG(INFO) << "OBJECT Object Status mismatch"; return false; @@ -221,10 +214,7 @@ /*group_id*/ 5, /*object_id=*/6, /*publisher_priority=*/7, - std::vector<MoqtExtensionHeader>( - {MoqtExtensionHeader(0, absl::variant<uint64_t, std::string>(12ULL)), - MoqtExtensionHeader(1, - absl::variant<uint64_t, std::string>("foo"))}), + std::string(kDefaultExtensionBlob), /*object_status=*/MoqtObjectStatus::kNormal, /*subgroup_id=*/std::nullopt, /*payload_length=*/3, @@ -238,13 +228,13 @@ } void ExpandVarints() override { - ExpandVarintsImpl("vvvv-vvvvv---v---", false); + ExpandVarintsImpl("vvvv-v-------v---", false); } private: uint8_t raw_packet_[17] = { 0x01, 0x04, 0x05, 0x06, // varints - 0x07, 0x02, // publisher priority, no extensions + 0x07, 0x07, // publisher priority, 7B extensions 0x00, 0x0c, 0x01, 0x03, 0x66, 0x6f, 0x6f, // extensions 0x03, 0x66, 0x6f, 0x6f, // payload = "foo" }; @@ -256,15 +246,17 @@ SetWireImage(raw_packet_, sizeof(raw_packet_)); object_.object_status = MoqtObjectStatus::kEndOfGroup; object_.payload_length = 0; - object_.extension_headers.clear(); } - void ExpandVarints() override { ExpandVarintsImpl("vvvv-v", false); } + void ExpandVarints() override { ExpandVarintsImpl("vvvv-v-------v", false); } private: - uint8_t raw_packet_[6] = { - 0x02, 0x04, 0x05, 0x06, // varints - 0x07, 0x03, // publisher priority, kEndOfGroup + uint8_t raw_packet_[14] = { + 0x02, 0x04, 0x05, 0x06, // varints + 0x07, // publisher priority + 0x07, // 7B extensions + 0x00, 0x0c, 0x01, 0x03, 0x66, 0x6f, 0x6f, // extensions + 0x03, // kEndOfGroup }; }; @@ -277,7 +269,9 @@ object_.subgroup_id = 8; } - void ExpandVarints() override { ExpandVarintsImpl("vvvv-vvvvvv---v", false); } + void ExpandVarints() override { + ExpandVarintsImpl("vvvv-vv-------v---", false); + } bool SetPayloadLength(uint8_t payload_length) { if (payload_length > 63) { @@ -295,7 +289,7 @@ 0x04, // type field 0x04, 0x05, 0x08, // varints 0x07, // publisher priority - 0x06, 0x02, // object ID, 2 extensions + 0x06, 0x07, // object ID, 7B extensions 0x00, 0x0c, 0x01, 0x03, 0x66, 0x6f, 0x6f, // extensions 0x03, 0x66, 0x6f, 0x6f, // payload = "foo" }; @@ -310,11 +304,11 @@ object_.object_id = 9; } - void ExpandVarints() override { ExpandVarintsImpl("vvvvvv---v", false); } + void ExpandVarints() override { ExpandVarintsImpl("vv-------v---", false); } private: uint8_t raw_packet_[13] = { - 0x09, 0x02, // object ID; 2 extensions + 0x09, 0x07, // object ID; 7B extensions 0x00, 0x0c, 0x01, 0x03, 0x66, 0x6f, 0x6f, // extensions 0x03, 0x62, 0x61, 0x72, // payload = "bar" }; @@ -328,7 +322,7 @@ } void ExpandVarints() override { - ExpandVarintsImpl("vvvvv-vvvvv---v---", false); + ExpandVarintsImpl("vvvvv-v-------v---", false); } bool SetPayloadLength(uint8_t payload_length) { @@ -348,7 +342,7 @@ 0x04, // subscribe ID // object middler: 0x05, 0x08, 0x06, // sequence - 0x07, 0x02, // publisher priority, 2 extensions + 0x07, 0x07, // publisher priority, 7B extensions 0x00, 0x0c, 0x01, 0x03, 0x66, 0x6f, 0x6f, // extensions 0x03, 0x66, 0x6f, 0x6f, // payload = "foo" }; @@ -363,11 +357,13 @@ object_.object_id = 9; } - void ExpandVarints() override { ExpandVarintsImpl("vvv-vv---", false); } + void ExpandVarints() override { + ExpandVarintsImpl("vvv-v-------v---", false); + } private: uint8_t raw_packet_[16] = { - 0x05, 0x08, 0x09, 0x07, 0x02, // Object metadata + 0x05, 0x08, 0x09, 0x07, 0x07, // Object metadata 0x00, 0x0c, 0x01, 0x03, 0x66, 0x6f, 0x6f, // extensions 0x03, 0x62, 0x61, 0x72, // Payload = "bar" };