1 // Copyright (c) 2023 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "quiche/quic/moqt/moqt_parser.h"
6
7 #include <cstddef>
8 #include <cstdint>
9 #include <cstring>
10 #include <memory>
11 #include <optional>
12 #include <string>
13 #include <utility>
14 #include <vector>
15
16 #include "absl/strings/string_view.h"
17 #include "quiche/quic/core/quic_data_writer.h"
18 #include "quiche/quic/moqt/moqt_messages.h"
19 #include "quiche/quic/moqt/test_tools/moqt_test_message.h"
20 #include "quiche/quic/platform/api/quic_test.h"
21
22 namespace moqt::test {
23
24 namespace {
25
IsObjectMessage(MoqtMessageType type)26 inline bool IsObjectMessage(MoqtMessageType type) {
27 return (type == MoqtMessageType::kObjectStream ||
28 type == MoqtMessageType::kObjectDatagram ||
29 type == MoqtMessageType::kStreamHeaderTrack ||
30 type == MoqtMessageType::kStreamHeaderGroup);
31 }
32
IsObjectWithoutPayloadLength(MoqtMessageType type)33 inline bool IsObjectWithoutPayloadLength(MoqtMessageType type) {
34 return (type == MoqtMessageType::kObjectStream ||
35 type == MoqtMessageType::kObjectDatagram);
36 }
37
38 std::vector<MoqtMessageType> message_types = {
39 MoqtMessageType::kObjectStream,
40 // kObjectDatagram is a unique set of tests.
41 MoqtMessageType::kSubscribe,
42 MoqtMessageType::kSubscribeOk,
43 MoqtMessageType::kSubscribeError,
44 MoqtMessageType::kUnsubscribe,
45 MoqtMessageType::kSubscribeDone,
46 MoqtMessageType::kAnnounce,
47 MoqtMessageType::kAnnounceOk,
48 MoqtMessageType::kAnnounceError,
49 MoqtMessageType::kUnannounce,
50 MoqtMessageType::kClientSetup,
51 MoqtMessageType::kServerSetup,
52 MoqtMessageType::kStreamHeaderTrack,
53 MoqtMessageType::kStreamHeaderGroup,
54 MoqtMessageType::kGoAway,
55 };
56
57 } // namespace
58
59 struct MoqtParserTestParams {
MoqtParserTestParamsmoqt::test::MoqtParserTestParams60 MoqtParserTestParams(MoqtMessageType message_type, bool uses_web_transport)
61 : message_type(message_type), uses_web_transport(uses_web_transport) {}
62 MoqtMessageType message_type;
63 bool uses_web_transport;
64 };
65
GetMoqtParserTestParams()66 std::vector<MoqtParserTestParams> GetMoqtParserTestParams() {
67 std::vector<MoqtParserTestParams> params;
68
69 std::vector<bool> uses_web_transport_bool = {
70 false,
71 true,
72 };
73 for (const MoqtMessageType message_type : message_types) {
74 if (message_type == MoqtMessageType::kClientSetup) {
75 for (const bool uses_web_transport : uses_web_transport_bool) {
76 params.push_back(
77 MoqtParserTestParams(message_type, uses_web_transport));
78 }
79 } else {
80 // All other types are processed the same for either perspective or
81 // transport.
82 params.push_back(MoqtParserTestParams(message_type, true));
83 }
84 }
85 return params;
86 }
87
ParamNameFormatter(const testing::TestParamInfo<MoqtParserTestParams> & info)88 std::string ParamNameFormatter(
89 const testing::TestParamInfo<MoqtParserTestParams>& info) {
90 return MoqtMessageTypeToString(info.param.message_type) + "_" +
91 (info.param.uses_web_transport ? "WebTransport" : "QUIC");
92 }
93
94 class MoqtParserTestVisitor : public MoqtParserVisitor {
95 public:
96 ~MoqtParserTestVisitor() = default;
97
OnObjectMessage(const MoqtObject & message,absl::string_view payload,bool end_of_message)98 void OnObjectMessage(const MoqtObject& message, absl::string_view payload,
99 bool end_of_message) override {
100 MoqtObject object = message;
101 object_payload_ = payload;
102 end_of_message_ = end_of_message;
103 messages_received_++;
104 last_message_ = TestMessageBase::MessageStructuredData(object);
105 }
106
107 template <typename Message>
OnControlMessage(const Message & message)108 void OnControlMessage(const Message& message) {
109 end_of_message_ = true;
110 ++messages_received_;
111 last_message_ = TestMessageBase::MessageStructuredData(message);
112 }
OnClientSetupMessage(const MoqtClientSetup & message)113 void OnClientSetupMessage(const MoqtClientSetup& message) override {
114 OnControlMessage(message);
115 }
OnServerSetupMessage(const MoqtServerSetup & message)116 void OnServerSetupMessage(const MoqtServerSetup& message) override {
117 OnControlMessage(message);
118 }
OnSubscribeMessage(const MoqtSubscribe & message)119 void OnSubscribeMessage(const MoqtSubscribe& message) override {
120 OnControlMessage(message);
121 }
OnSubscribeOkMessage(const MoqtSubscribeOk & message)122 void OnSubscribeOkMessage(const MoqtSubscribeOk& message) override {
123 OnControlMessage(message);
124 }
OnSubscribeErrorMessage(const MoqtSubscribeError & message)125 void OnSubscribeErrorMessage(const MoqtSubscribeError& message) override {
126 OnControlMessage(message);
127 }
OnUnsubscribeMessage(const MoqtUnsubscribe & message)128 void OnUnsubscribeMessage(const MoqtUnsubscribe& message) override {
129 OnControlMessage(message);
130 }
OnSubscribeDoneMessage(const MoqtSubscribeDone & message)131 void OnSubscribeDoneMessage(const MoqtSubscribeDone& message) override {
132 OnControlMessage(message);
133 }
OnAnnounceMessage(const MoqtAnnounce & message)134 void OnAnnounceMessage(const MoqtAnnounce& message) override {
135 OnControlMessage(message);
136 }
OnAnnounceOkMessage(const MoqtAnnounceOk & message)137 void OnAnnounceOkMessage(const MoqtAnnounceOk& message) override {
138 OnControlMessage(message);
139 }
OnAnnounceErrorMessage(const MoqtAnnounceError & message)140 void OnAnnounceErrorMessage(const MoqtAnnounceError& message) override {
141 OnControlMessage(message);
142 }
OnUnannounceMessage(const MoqtUnannounce & message)143 void OnUnannounceMessage(const MoqtUnannounce& message) override {
144 OnControlMessage(message);
145 }
OnGoAwayMessage(const MoqtGoAway & message)146 void OnGoAwayMessage(const MoqtGoAway& message) override {
147 OnControlMessage(message);
148 }
OnParsingError(MoqtError code,absl::string_view reason)149 void OnParsingError(MoqtError code, absl::string_view reason) override {
150 QUIC_LOG(INFO) << "Parsing error: " << reason;
151 parsing_error_ = reason;
152 parsing_error_code_ = code;
153 }
154
155 std::optional<absl::string_view> object_payload_;
156 bool end_of_message_ = false;
157 std::optional<absl::string_view> parsing_error_;
158 MoqtError parsing_error_code_;
159 uint64_t messages_received_ = 0;
160 std::optional<TestMessageBase::MessageStructuredData> last_message_;
161 };
162
163 class MoqtParserTest
164 : public quic::test::QuicTestWithParam<MoqtParserTestParams> {
165 public:
MoqtParserTest()166 MoqtParserTest()
167 : message_type_(GetParam().message_type),
168 webtrans_(GetParam().uses_web_transport),
169 parser_(GetParam().uses_web_transport, visitor_) {}
170
MakeMessage(MoqtMessageType message_type)171 std::unique_ptr<TestMessageBase> MakeMessage(MoqtMessageType message_type) {
172 return CreateTestMessage(message_type, webtrans_);
173 }
174
175 MoqtParserTestVisitor visitor_;
176 MoqtMessageType message_type_;
177 bool webtrans_;
178 MoqtParser parser_;
179 };
180
181 INSTANTIATE_TEST_SUITE_P(MoqtParserTests, MoqtParserTest,
182 testing::ValuesIn(GetMoqtParserTestParams()),
183 ParamNameFormatter);
184
TEST_P(MoqtParserTest,OneMessage)185 TEST_P(MoqtParserTest, OneMessage) {
186 std::unique_ptr<TestMessageBase> message = MakeMessage(message_type_);
187 parser_.ProcessData(message->PacketSample(), true);
188 EXPECT_EQ(visitor_.messages_received_, 1);
189 EXPECT_TRUE(message->EqualFieldValues(*visitor_.last_message_));
190 EXPECT_TRUE(visitor_.end_of_message_);
191 if (IsObjectMessage(message_type_)) {
192 // Check payload message.
193 EXPECT_TRUE(visitor_.object_payload_.has_value());
194 EXPECT_EQ(*(visitor_.object_payload_), "foo");
195 }
196 }
197
TEST_P(MoqtParserTest,OneMessageWithLongVarints)198 TEST_P(MoqtParserTest, OneMessageWithLongVarints) {
199 std::unique_ptr<TestMessageBase> message = MakeMessage(message_type_);
200 message->ExpandVarints();
201 parser_.ProcessData(message->PacketSample(), true);
202 EXPECT_EQ(visitor_.messages_received_, 1);
203 EXPECT_TRUE(message->EqualFieldValues(*visitor_.last_message_));
204 EXPECT_TRUE(visitor_.end_of_message_);
205 if (IsObjectMessage(message_type_)) {
206 // Check payload message.
207 EXPECT_EQ(visitor_.object_payload_, "foo");
208 }
209 EXPECT_FALSE(visitor_.parsing_error_.has_value());
210 }
211
TEST_P(MoqtParserTest,TwoPartMessage)212 TEST_P(MoqtParserTest, TwoPartMessage) {
213 std::unique_ptr<TestMessageBase> message = MakeMessage(message_type_);
214 // The test Object message has payload for less then half the message length,
215 // so splitting the message in half will prevent the first half from being
216 // processed.
217 size_t first_data_size = message->total_message_size() / 2;
218 if (message_type_ == MoqtMessageType::kStreamHeaderTrack) {
219 // The boundary happens to fall right after the stream header, so move it.
220 ++first_data_size;
221 }
222 parser_.ProcessData(message->PacketSample().substr(0, first_data_size),
223 false);
224 EXPECT_EQ(visitor_.messages_received_, 0);
225 parser_.ProcessData(
226 message->PacketSample().substr(
227 first_data_size, message->total_message_size() - first_data_size),
228 true);
229 EXPECT_EQ(visitor_.messages_received_, 1);
230 EXPECT_TRUE(message->EqualFieldValues(*visitor_.last_message_));
231 if (IsObjectMessage(message_type_)) {
232 EXPECT_EQ(visitor_.object_payload_, "foo");
233 }
234 EXPECT_TRUE(visitor_.end_of_message_);
235 EXPECT_FALSE(visitor_.parsing_error_.has_value());
236 }
237
TEST_P(MoqtParserTest,OneByteAtATime)238 TEST_P(MoqtParserTest, OneByteAtATime) {
239 std::unique_ptr<TestMessageBase> message = MakeMessage(message_type_);
240 size_t kObjectPayloadSize = 3;
241 for (size_t i = 0; i < message->total_message_size(); ++i) {
242 if (!IsObjectMessage(message_type_)) {
243 EXPECT_EQ(visitor_.messages_received_, 0);
244 }
245 EXPECT_FALSE(visitor_.end_of_message_);
246 parser_.ProcessData(message->PacketSample().substr(i, 1), false);
247 }
248 EXPECT_EQ(visitor_.messages_received_,
249 (IsObjectMessage(message_type_) ? (kObjectPayloadSize + 1) : 1));
250 if (IsObjectWithoutPayloadLength(message_type_)) {
251 EXPECT_FALSE(visitor_.end_of_message_);
252 parser_.ProcessData(absl::string_view(), true); // Needs the FIN
253 EXPECT_EQ(visitor_.messages_received_, kObjectPayloadSize + 2);
254 }
255 EXPECT_TRUE(message->EqualFieldValues(*visitor_.last_message_));
256 EXPECT_TRUE(visitor_.end_of_message_);
257 EXPECT_FALSE(visitor_.parsing_error_.has_value());
258 }
259
TEST_P(MoqtParserTest,OneByteAtATimeLongerVarints)260 TEST_P(MoqtParserTest, OneByteAtATimeLongerVarints) {
261 std::unique_ptr<TestMessageBase> message = MakeMessage(message_type_);
262 message->ExpandVarints();
263 size_t kObjectPayloadSize = 3;
264 for (size_t i = 0; i < message->total_message_size(); ++i) {
265 if (!IsObjectMessage(message_type_)) {
266 EXPECT_EQ(visitor_.messages_received_, 0);
267 }
268 EXPECT_FALSE(visitor_.end_of_message_);
269 parser_.ProcessData(message->PacketSample().substr(i, 1), false);
270 }
271 EXPECT_EQ(visitor_.messages_received_,
272 (IsObjectMessage(message_type_) ? (kObjectPayloadSize + 1) : 1));
273 if (IsObjectWithoutPayloadLength(message_type_)) {
274 EXPECT_FALSE(visitor_.end_of_message_);
275 parser_.ProcessData(absl::string_view(), true); // Needs the FIN
276 EXPECT_EQ(visitor_.messages_received_, kObjectPayloadSize + 2);
277 }
278 EXPECT_TRUE(message->EqualFieldValues(*visitor_.last_message_));
279 EXPECT_TRUE(visitor_.end_of_message_);
280 EXPECT_FALSE(visitor_.parsing_error_.has_value());
281 }
282
TEST_P(MoqtParserTest,EarlyFin)283 TEST_P(MoqtParserTest, EarlyFin) {
284 std::unique_ptr<TestMessageBase> message = MakeMessage(message_type_);
285 size_t first_data_size = message->total_message_size() / 2;
286 if (message_type_ == MoqtMessageType::kStreamHeaderTrack) {
287 // The boundary happens to fall right after the stream header, so move it.
288 ++first_data_size;
289 }
290 parser_.ProcessData(message->PacketSample().substr(0, first_data_size), true);
291 EXPECT_EQ(visitor_.messages_received_, 0);
292 EXPECT_TRUE(visitor_.parsing_error_.has_value());
293 EXPECT_EQ(*visitor_.parsing_error_, "FIN after incomplete message");
294 }
295
TEST_P(MoqtParserTest,SeparateEarlyFin)296 TEST_P(MoqtParserTest, SeparateEarlyFin) {
297 std::unique_ptr<TestMessageBase> message = MakeMessage(message_type_);
298 size_t first_data_size = message->total_message_size() / 2;
299 if (message_type_ == MoqtMessageType::kStreamHeaderTrack) {
300 // The boundary happens to fall right after the stream header, so move it.
301 ++first_data_size;
302 }
303 parser_.ProcessData(message->PacketSample().substr(0, first_data_size),
304 false);
305 parser_.ProcessData(absl::string_view(), true);
306 EXPECT_EQ(visitor_.messages_received_, 0);
307 EXPECT_TRUE(visitor_.parsing_error_.has_value());
308 EXPECT_EQ(*visitor_.parsing_error_, "End of stream before complete message");
309 EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
310 }
311
312 // Tests for message-specific error cases, and behaviors for a single message
313 // type.
314 class MoqtMessageSpecificTest : public quic::test::QuicTest {
315 public:
MoqtMessageSpecificTest()316 MoqtMessageSpecificTest() {}
317
318 MoqtParserTestVisitor visitor_;
319
320 static constexpr bool kWebTrans = true;
321 static constexpr bool kRawQuic = false;
322 };
323
TEST_F(MoqtMessageSpecificTest,ObjectStreamSeparateFin)324 TEST_F(MoqtMessageSpecificTest, ObjectStreamSeparateFin) {
325 // OBJECT can return on an unknown-length message even without receiving a
326 // FIN.
327 MoqtParser parser(kRawQuic, visitor_);
328 auto message = std::make_unique<ObjectStreamMessage>();
329 parser.ProcessData(message->PacketSample(), false);
330 EXPECT_EQ(visitor_.messages_received_, 1);
331 EXPECT_TRUE(message->EqualFieldValues(*visitor_.last_message_));
332 EXPECT_TRUE(visitor_.object_payload_.has_value());
333 EXPECT_EQ(*(visitor_.object_payload_), "foo");
334 EXPECT_FALSE(visitor_.end_of_message_);
335
336 parser.ProcessData(absl::string_view(), true); // send the FIN
337 EXPECT_EQ(visitor_.messages_received_, 2);
338 EXPECT_TRUE(message->EqualFieldValues(*visitor_.last_message_));
339 EXPECT_TRUE(visitor_.object_payload_.has_value());
340 EXPECT_EQ(*(visitor_.object_payload_), "");
341 EXPECT_TRUE(visitor_.end_of_message_);
342 EXPECT_FALSE(visitor_.parsing_error_.has_value());
343 }
344
345 // Send the header + some payload, pure payload, then pure payload to end the
346 // message.
TEST_F(MoqtMessageSpecificTest,ThreePartObject)347 TEST_F(MoqtMessageSpecificTest, ThreePartObject) {
348 MoqtParser parser(kRawQuic, visitor_);
349 auto message = std::make_unique<ObjectStreamMessage>();
350 parser.ProcessData(message->PacketSample(), false);
351 EXPECT_EQ(visitor_.messages_received_, 1);
352 EXPECT_TRUE(message->EqualFieldValues(*visitor_.last_message_));
353 EXPECT_FALSE(visitor_.end_of_message_);
354 EXPECT_TRUE(visitor_.object_payload_.has_value());
355 EXPECT_EQ(*(visitor_.object_payload_), "foo");
356
357 // second part
358 parser.ProcessData("bar", false);
359 EXPECT_EQ(visitor_.messages_received_, 2);
360 EXPECT_TRUE(message->EqualFieldValues(*visitor_.last_message_));
361 EXPECT_FALSE(visitor_.end_of_message_);
362 EXPECT_TRUE(visitor_.object_payload_.has_value());
363 EXPECT_EQ(*(visitor_.object_payload_), "bar");
364
365 // third part includes FIN
366 parser.ProcessData("deadbeef", true);
367 EXPECT_EQ(visitor_.messages_received_, 3);
368 EXPECT_TRUE(message->EqualFieldValues(*visitor_.last_message_));
369 EXPECT_TRUE(visitor_.end_of_message_);
370 EXPECT_TRUE(visitor_.object_payload_.has_value());
371 EXPECT_EQ(*(visitor_.object_payload_), "deadbeef");
372 EXPECT_FALSE(visitor_.parsing_error_.has_value());
373 }
374
375 // Send the part of header, rest of header + payload, plus payload.
TEST_F(MoqtMessageSpecificTest,ThreePartObjectFirstIncomplete)376 TEST_F(MoqtMessageSpecificTest, ThreePartObjectFirstIncomplete) {
377 MoqtParser parser(kRawQuic, visitor_);
378 auto message = std::make_unique<ObjectStreamMessage>();
379
380 // first part
381 parser.ProcessData(message->PacketSample().substr(0, 4), false);
382 EXPECT_EQ(visitor_.messages_received_, 0);
383
384 // second part. Add padding to it.
385 message->set_wire_image_size(100);
386 parser.ProcessData(
387 message->PacketSample().substr(4, message->total_message_size() - 4),
388 false);
389 EXPECT_EQ(visitor_.messages_received_, 1);
390 EXPECT_TRUE(message->EqualFieldValues(*visitor_.last_message_));
391 EXPECT_FALSE(visitor_.end_of_message_);
392 EXPECT_TRUE(visitor_.object_payload_.has_value());
393 EXPECT_EQ(visitor_.object_payload_->length(), 94);
394
395 // third part includes FIN
396 parser.ProcessData("bar", true);
397 EXPECT_EQ(visitor_.messages_received_, 2);
398 EXPECT_TRUE(message->EqualFieldValues(*visitor_.last_message_));
399 EXPECT_TRUE(visitor_.end_of_message_);
400 EXPECT_TRUE(visitor_.object_payload_.has_value());
401 EXPECT_EQ(*(visitor_.object_payload_), "bar");
402 EXPECT_FALSE(visitor_.parsing_error_.has_value());
403 }
404
TEST_F(MoqtMessageSpecificTest,StreamHeaderGroupFollowOn)405 TEST_F(MoqtMessageSpecificTest, StreamHeaderGroupFollowOn) {
406 MoqtParser parser(kRawQuic, visitor_);
407 // first part
408 auto message1 = std::make_unique<StreamHeaderGroupMessage>();
409 parser.ProcessData(message1->PacketSample(), false);
410 EXPECT_EQ(visitor_.messages_received_, 1);
411 EXPECT_TRUE(message1->EqualFieldValues(*visitor_.last_message_));
412 EXPECT_TRUE(visitor_.end_of_message_);
413 EXPECT_TRUE(visitor_.object_payload_.has_value());
414 EXPECT_EQ(*(visitor_.object_payload_), "foo");
415 EXPECT_FALSE(visitor_.parsing_error_.has_value());
416 // second part
417 auto message2 = std::make_unique<StreamMiddlerGroupMessage>();
418 parser.ProcessData(message2->PacketSample(), false);
419 EXPECT_EQ(visitor_.messages_received_, 2);
420 EXPECT_TRUE(message2->EqualFieldValues(*visitor_.last_message_));
421 EXPECT_TRUE(visitor_.end_of_message_);
422 EXPECT_TRUE(visitor_.object_payload_.has_value());
423 EXPECT_EQ(*(visitor_.object_payload_), "bar");
424 EXPECT_FALSE(visitor_.parsing_error_.has_value());
425 }
426
TEST_F(MoqtMessageSpecificTest,StreamHeaderTrackFollowOn)427 TEST_F(MoqtMessageSpecificTest, StreamHeaderTrackFollowOn) {
428 MoqtParser parser(kRawQuic, visitor_);
429 // first part
430 auto message1 = std::make_unique<StreamHeaderTrackMessage>();
431 parser.ProcessData(message1->PacketSample(), false);
432 EXPECT_EQ(visitor_.messages_received_, 1);
433 EXPECT_TRUE(message1->EqualFieldValues(*visitor_.last_message_));
434 EXPECT_TRUE(visitor_.end_of_message_);
435 EXPECT_TRUE(visitor_.object_payload_.has_value());
436 EXPECT_EQ(*(visitor_.object_payload_), "foo");
437 EXPECT_FALSE(visitor_.parsing_error_.has_value());
438 // second part
439 auto message2 = std::make_unique<StreamMiddlerTrackMessage>();
440 parser.ProcessData(message2->PacketSample(), false);
441 EXPECT_EQ(visitor_.messages_received_, 2);
442 EXPECT_TRUE(message2->EqualFieldValues(*visitor_.last_message_));
443 EXPECT_TRUE(visitor_.end_of_message_);
444 EXPECT_TRUE(visitor_.object_payload_.has_value());
445 EXPECT_EQ(*(visitor_.object_payload_), "bar");
446 EXPECT_FALSE(visitor_.parsing_error_.has_value());
447 }
448
TEST_F(MoqtMessageSpecificTest,ClientSetupRoleIsInvalid)449 TEST_F(MoqtMessageSpecificTest, ClientSetupRoleIsInvalid) {
450 MoqtParser parser(kRawQuic, visitor_);
451 char setup[] = {
452 0x40, 0x40, 0x02, 0x01, 0x02, // versions
453 0x03, // 3 params
454 0x00, 0x01, 0x04, // role = invalid
455 0x01, 0x03, 0x66, 0x6f, 0x6f // path = "foo"
456 };
457 parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
458 EXPECT_EQ(visitor_.messages_received_, 0);
459 EXPECT_TRUE(visitor_.parsing_error_.has_value());
460 EXPECT_EQ(*visitor_.parsing_error_, "Invalid ROLE parameter");
461 EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
462 }
463
TEST_F(MoqtMessageSpecificTest,ServerSetupRoleIsInvalid)464 TEST_F(MoqtMessageSpecificTest, ServerSetupRoleIsInvalid) {
465 MoqtParser parser(kRawQuic, visitor_);
466 char setup[] = {
467 0x40, 0x41, 0x01,
468 0x01, // 1 param
469 0x00, 0x01, 0x04, // role = invalid
470 0x01, 0x03, 0x66, 0x6f, 0x6f // path = "foo"
471 };
472 parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
473 EXPECT_EQ(visitor_.messages_received_, 0);
474 EXPECT_TRUE(visitor_.parsing_error_.has_value());
475 EXPECT_EQ(*visitor_.parsing_error_, "Invalid ROLE parameter");
476 EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
477 }
478
TEST_F(MoqtMessageSpecificTest,SetupRoleAppearsTwice)479 TEST_F(MoqtMessageSpecificTest, SetupRoleAppearsTwice) {
480 MoqtParser parser(kRawQuic, visitor_);
481 char setup[] = {
482 0x40, 0x40, 0x02, 0x01, 0x02, // versions
483 0x03, // 3 params
484 0x00, 0x01, 0x03, // role = PubSub
485 0x00, 0x01, 0x03, // role = PubSub
486 0x01, 0x03, 0x66, 0x6f, 0x6f // path = "foo"
487 };
488 parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
489 EXPECT_EQ(visitor_.messages_received_, 0);
490 EXPECT_TRUE(visitor_.parsing_error_.has_value());
491 EXPECT_EQ(*visitor_.parsing_error_, "ROLE parameter appears twice in SETUP");
492 EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
493 }
494
TEST_F(MoqtMessageSpecificTest,ClientSetupRoleIsMissing)495 TEST_F(MoqtMessageSpecificTest, ClientSetupRoleIsMissing) {
496 MoqtParser parser(kRawQuic, visitor_);
497 char setup[] = {
498 0x40, 0x40, 0x02, 0x01, 0x02, // versions = 1, 2
499 0x01, // 1 param
500 0x01, 0x03, 0x66, 0x6f, 0x6f, // path = "foo"
501 };
502 parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
503 EXPECT_EQ(visitor_.messages_received_, 0);
504 EXPECT_TRUE(visitor_.parsing_error_.has_value());
505 EXPECT_EQ(*visitor_.parsing_error_,
506 "ROLE parameter missing from CLIENT_SETUP message");
507 EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
508 }
509
TEST_F(MoqtMessageSpecificTest,ServerSetupRoleIsMissing)510 TEST_F(MoqtMessageSpecificTest, ServerSetupRoleIsMissing) {
511 MoqtParser parser(kRawQuic, visitor_);
512 char setup[] = {
513 0x40, 0x41, 0x01, 0x00, // 1 param
514 };
515 parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
516 EXPECT_EQ(visitor_.messages_received_, 0);
517 EXPECT_TRUE(visitor_.parsing_error_.has_value());
518 EXPECT_EQ(*visitor_.parsing_error_,
519 "ROLE parameter missing from SERVER_SETUP message");
520 EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
521 }
522
TEST_F(MoqtMessageSpecificTest,SetupRoleVarintLengthIsWrong)523 TEST_F(MoqtMessageSpecificTest, SetupRoleVarintLengthIsWrong) {
524 MoqtParser parser(kRawQuic, visitor_);
525 char setup[] = {
526 0x40, 0x40, // type
527 0x02, 0x01, 0x02, // versions
528 0x02, // 2 parameters
529 0x00, 0x02, 0x03, // role = PubSub, but length is 2
530 0x01, 0x03, 0x66, 0x6f, 0x6f // path = "foo"
531 };
532 parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
533 EXPECT_EQ(visitor_.messages_received_, 0);
534 EXPECT_TRUE(visitor_.parsing_error_.has_value());
535 EXPECT_EQ(*visitor_.parsing_error_,
536 "Parameter length does not match varint encoding");
537
538 EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kParameterLengthMismatch);
539 }
540
TEST_F(MoqtMessageSpecificTest,SetupPathFromServer)541 TEST_F(MoqtMessageSpecificTest, SetupPathFromServer) {
542 MoqtParser parser(kRawQuic, visitor_);
543 char setup[] = {
544 0x40, 0x41,
545 0x01, // version = 1
546 0x01, // 1 param
547 0x01, 0x03, 0x66, 0x6f, 0x6f, // path = "foo"
548 };
549 parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
550 EXPECT_EQ(visitor_.messages_received_, 0);
551 EXPECT_TRUE(visitor_.parsing_error_.has_value());
552 EXPECT_EQ(*visitor_.parsing_error_, "PATH parameter in SERVER_SETUP");
553 EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
554 }
555
TEST_F(MoqtMessageSpecificTest,SetupPathAppearsTwice)556 TEST_F(MoqtMessageSpecificTest, SetupPathAppearsTwice) {
557 MoqtParser parser(kRawQuic, visitor_);
558 char setup[] = {
559 0x40, 0x40, 0x02, 0x01, 0x02, // versions = 1, 2
560 0x03, // 3 params
561 0x00, 0x01, 0x03, // role = PubSub
562 0x01, 0x03, 0x66, 0x6f, 0x6f, // path = "foo"
563 0x01, 0x03, 0x66, 0x6f, 0x6f, // path = "foo"
564 };
565 parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
566 EXPECT_EQ(visitor_.messages_received_, 0);
567 EXPECT_TRUE(visitor_.parsing_error_.has_value());
568 EXPECT_EQ(*visitor_.parsing_error_,
569 "PATH parameter appears twice in CLIENT_SETUP");
570 EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
571 }
572
TEST_F(MoqtMessageSpecificTest,SetupPathOverWebtrans)573 TEST_F(MoqtMessageSpecificTest, SetupPathOverWebtrans) {
574 MoqtParser parser(kWebTrans, visitor_);
575 char setup[] = {
576 0x40, 0x40, 0x02, 0x01, 0x02, // versions = 1, 2
577 0x02, // 2 params
578 0x00, 0x01, 0x03, // role = PubSub
579 0x01, 0x03, 0x66, 0x6f, 0x6f, // path = "foo"
580 };
581 parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
582 EXPECT_EQ(visitor_.messages_received_, 0);
583 EXPECT_TRUE(visitor_.parsing_error_.has_value());
584 EXPECT_EQ(*visitor_.parsing_error_,
585 "WebTransport connection is using PATH parameter in SETUP");
586 EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
587 }
588
TEST_F(MoqtMessageSpecificTest,SetupPathMissing)589 TEST_F(MoqtMessageSpecificTest, SetupPathMissing) {
590 MoqtParser parser(kRawQuic, visitor_);
591 char setup[] = {
592 0x40, 0x40, 0x02, 0x01, 0x02, // versions = 1, 2
593 0x01, // 1 param
594 0x00, 0x01, 0x03, // role = PubSub
595 };
596 parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
597 EXPECT_EQ(visitor_.messages_received_, 0);
598 EXPECT_TRUE(visitor_.parsing_error_.has_value());
599 EXPECT_EQ(*visitor_.parsing_error_,
600 "PATH SETUP parameter missing from Client message over QUIC");
601 EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
602 }
603
TEST_F(MoqtMessageSpecificTest,SubscribeAuthorizationInfoTwice)604 TEST_F(MoqtMessageSpecificTest, SubscribeAuthorizationInfoTwice) {
605 MoqtParser parser(kWebTrans, visitor_);
606 char subscribe[] = {
607 0x03, 0x01, 0x02, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
608 0x04, 0x61, 0x62, 0x63, 0x64, // track_name = "abcd"
609 0x02, 0x04, // start_group = 4 (relative previous)
610 0x01, 0x01, // start_object = 1 (absolute)
611 0x00, // end_group = none
612 0x00, // end_object = none
613 0x02, // two params
614 0x02, 0x03, 0x62, 0x61, 0x72, // authorization_info = "bar"
615 0x02, 0x03, 0x62, 0x61, 0x72, // authorization_info = "bar"
616 };
617 parser.ProcessData(absl::string_view(subscribe, sizeof(subscribe)), false);
618 EXPECT_EQ(visitor_.messages_received_, 0);
619 EXPECT_TRUE(visitor_.parsing_error_.has_value());
620 EXPECT_EQ(*visitor_.parsing_error_,
621 "AUTHORIZATION_INFO parameter appears twice in SUBSCRIBE_REQUEST");
622 EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
623 }
624
TEST_F(MoqtMessageSpecificTest,AnnounceAuthorizationInfoTwice)625 TEST_F(MoqtMessageSpecificTest, AnnounceAuthorizationInfoTwice) {
626 MoqtParser parser(kWebTrans, visitor_);
627 char announce[] = {
628 0x06, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
629 0x02, // 2 params
630 0x02, 0x03, 0x62, 0x61, 0x72, // authorization_info = "bar"
631 0x02, 0x03, 0x62, 0x61, 0x72, // authorization_info = "bar"
632 };
633 parser.ProcessData(absl::string_view(announce, sizeof(announce)), false);
634 EXPECT_EQ(visitor_.messages_received_, 0);
635 EXPECT_TRUE(visitor_.parsing_error_.has_value());
636 EXPECT_EQ(*visitor_.parsing_error_,
637 "AUTHORIZATION_INFO parameter appears twice in ANNOUNCE");
638 EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
639 }
640
TEST_F(MoqtMessageSpecificTest,FinMidPayload)641 TEST_F(MoqtMessageSpecificTest, FinMidPayload) {
642 MoqtParser parser(kRawQuic, visitor_);
643 auto message = std::make_unique<StreamHeaderGroupMessage>();
644 parser.ProcessData(
645 message->PacketSample().substr(0, message->total_message_size() - 1),
646 true);
647 EXPECT_EQ(visitor_.messages_received_, 0);
648 EXPECT_TRUE(visitor_.parsing_error_.has_value());
649 EXPECT_EQ(*visitor_.parsing_error_, "Received FIN mid-payload");
650 EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
651 }
652
TEST_F(MoqtMessageSpecificTest,PartialPayloadThenFin)653 TEST_F(MoqtMessageSpecificTest, PartialPayloadThenFin) {
654 MoqtParser parser(kRawQuic, visitor_);
655 auto message = std::make_unique<StreamHeaderTrackMessage>();
656 parser.ProcessData(
657 message->PacketSample().substr(0, message->total_message_size() - 1),
658 false);
659 parser.ProcessData(absl::string_view(), true);
660 EXPECT_EQ(visitor_.messages_received_, 1);
661 EXPECT_TRUE(visitor_.parsing_error_.has_value());
662 EXPECT_EQ(*visitor_.parsing_error_,
663 "End of stream before complete OBJECT PAYLOAD");
664 EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
665 }
666
TEST_F(MoqtMessageSpecificTest,DataAfterFin)667 TEST_F(MoqtMessageSpecificTest, DataAfterFin) {
668 MoqtParser parser(kRawQuic, visitor_);
669 parser.ProcessData(absl::string_view(), true); // Find FIN
670 parser.ProcessData("foo", false);
671 EXPECT_TRUE(visitor_.parsing_error_.has_value());
672 EXPECT_EQ(*visitor_.parsing_error_, "Data after end of stream");
673 EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
674 }
675
TEST_F(MoqtMessageSpecificTest,Setup2KB)676 TEST_F(MoqtMessageSpecificTest, Setup2KB) {
677 MoqtParser parser(kRawQuic, visitor_);
678 char big_message[2 * kMaxMessageHeaderSize];
679 quic::QuicDataWriter writer(sizeof(big_message), big_message);
680 writer.WriteVarInt62(static_cast<uint64_t>(MoqtMessageType::kServerSetup));
681 writer.WriteVarInt62(0x1); // version
682 writer.WriteVarInt62(0x1); // num_params
683 writer.WriteVarInt62(0xbeef); // unknown param
684 writer.WriteVarInt62(kMaxMessageHeaderSize); // very long parameter
685 writer.WriteRepeatedByte(0x04, kMaxMessageHeaderSize);
686 // Send incomplete message
687 parser.ProcessData(absl::string_view(big_message, writer.length() - 1),
688 false);
689 EXPECT_EQ(visitor_.messages_received_, 0);
690 EXPECT_TRUE(visitor_.parsing_error_.has_value());
691 EXPECT_EQ(*visitor_.parsing_error_, "Cannot parse non-OBJECT messages > 2KB");
692 EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kInternalError);
693 }
694
TEST_F(MoqtMessageSpecificTest,UnknownMessageType)695 TEST_F(MoqtMessageSpecificTest, UnknownMessageType) {
696 MoqtParser parser(kRawQuic, visitor_);
697 char message[4];
698 quic::QuicDataWriter writer(sizeof(message), message);
699 writer.WriteVarInt62(0xbeef); // unknown message type
700 parser.ProcessData(absl::string_view(message, writer.length()), false);
701 EXPECT_EQ(visitor_.messages_received_, 0);
702 EXPECT_TRUE(visitor_.parsing_error_.has_value());
703 EXPECT_EQ(*visitor_.parsing_error_, "Unknown message type");
704 }
705
TEST_F(MoqtMessageSpecificTest,StartGroupIsNone)706 TEST_F(MoqtMessageSpecificTest, StartGroupIsNone) {
707 MoqtParser parser(kRawQuic, visitor_);
708 char subscribe[] = {
709 0x03, 0x01, 0x02, // id and alias
710 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
711 0x04, 0x61, 0x62, 0x63, 0x64, // track_name = "abcd"
712 0x00, // start_group = none
713 0x01, 0x01, // start_object = 1 (absolute)
714 0x00, // end_group = none
715 0x00, // end_object = none
716 0x01, // 1 parameter
717 0x02, 0x03, 0x62, 0x61, 0x72, // authorization_info = "bar"
718 };
719 parser.ProcessData(absl::string_view(subscribe, sizeof(subscribe)), false);
720 EXPECT_EQ(visitor_.messages_received_, 0);
721 EXPECT_TRUE(visitor_.parsing_error_.has_value());
722 EXPECT_EQ(*visitor_.parsing_error_,
723 "START_GROUP must not be None in SUBSCRIBE");
724 }
725
TEST_F(MoqtMessageSpecificTest,StartObjectIsNone)726 TEST_F(MoqtMessageSpecificTest, StartObjectIsNone) {
727 MoqtParser parser(kRawQuic, visitor_);
728 char subscribe[] = {
729 0x03, 0x01, 0x02, // id and alias
730 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
731 0x04, 0x61, 0x62, 0x63, 0x64, // track_name = "abcd"
732 0x02, 0x04, // start_group = 4 (relative previous)
733 0x00, // start_object = none
734 0x00, // end_group = none
735 0x00, // end_object = none
736 0x01, // 1 parameter
737 0x02, 0x03, 0x62, 0x61, 0x72, // authorization_info = "bar"
738 };
739 parser.ProcessData(absl::string_view(subscribe, sizeof(subscribe)), false);
740 EXPECT_EQ(visitor_.messages_received_, 0);
741 EXPECT_TRUE(visitor_.parsing_error_.has_value());
742 EXPECT_EQ(*visitor_.parsing_error_,
743 "START_OBJECT must not be None in SUBSCRIBE");
744 }
745
TEST_F(MoqtMessageSpecificTest,EndGroupIsNoneEndObjectIsNoNone)746 TEST_F(MoqtMessageSpecificTest, EndGroupIsNoneEndObjectIsNoNone) {
747 MoqtParser parser(kRawQuic, visitor_);
748 char subscribe[] = {
749 0x03, 0x01, 0x02, // id and alias
750 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
751 0x04, 0x61, 0x62, 0x63, 0x64, // track_name = "abcd"
752 0x02, 0x04, // start_group = 4 (relative previous)
753 0x01, 0x01, // start_object = 1 (absolute)
754 0x00, // end_group = none
755 0x01, 0x01, // end_object = 1 (absolute)
756 0x01, // 1 parameter
757 0x02, 0x03, 0x62, 0x61, 0x72, // authorization_info = "bar"
758 };
759 parser.ProcessData(absl::string_view(subscribe, sizeof(subscribe)), false);
760 EXPECT_EQ(visitor_.messages_received_, 0);
761 EXPECT_TRUE(visitor_.parsing_error_.has_value());
762 EXPECT_EQ(*visitor_.parsing_error_,
763 "SUBSCRIBE end_group and end_object must be both None "
764 "or both non_None");
765 }
766
TEST_F(MoqtMessageSpecificTest,AllMessagesTogether)767 TEST_F(MoqtMessageSpecificTest, AllMessagesTogether) {
768 char buffer[5000];
769 MoqtParser parser(kRawQuic, visitor_);
770 size_t write = 0;
771 size_t read = 0;
772 int fully_received = 0;
773 std::unique_ptr<TestMessageBase> prev_message = nullptr;
774 for (MoqtMessageType type : message_types) {
775 // Each iteration, process from the halfway point of one message to the
776 // halfway point of the next.
777 if (IsObjectMessage(type)) {
778 continue; // Objects cannot share a stream with other meessages.
779 }
780 std::unique_ptr<TestMessageBase> message =
781 CreateTestMessage(type, kRawQuic);
782 memcpy(buffer + write, message->PacketSample().data(),
783 message->total_message_size());
784 size_t new_read = write + message->total_message_size() / 2;
785 parser.ProcessData(absl::string_view(buffer + read, new_read - read),
786 false);
787 EXPECT_EQ(visitor_.messages_received_, fully_received);
788 if (prev_message != nullptr) {
789 EXPECT_TRUE(prev_message->EqualFieldValues(*visitor_.last_message_));
790 }
791 fully_received++;
792 read = new_read;
793 write += message->total_message_size();
794 prev_message = std::move(message);
795 }
796 // Deliver the rest
797 parser.ProcessData(absl::string_view(buffer + read, write - read), true);
798 EXPECT_EQ(visitor_.messages_received_, fully_received);
799 EXPECT_TRUE(prev_message->EqualFieldValues(*visitor_.last_message_));
800 EXPECT_FALSE(visitor_.parsing_error_.has_value());
801 }
802
TEST_F(MoqtMessageSpecificTest,RelativeLocation)803 TEST_F(MoqtMessageSpecificTest, RelativeLocation) {
804 MoqtParser parser(kRawQuic, visitor_);
805 char subscribe[] = {
806 0x03, 0x01, 0x02, // id and alias
807 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
808 0x04, 0x61, 0x62, 0x63, 0x64, // track_name = "abcd"
809 0x02, 0x00, // start_group = 0 (relative previous)
810 0x03, 0x00, // start_object = 1 (relative next)
811 0x00, // end_group = none
812 0x00, // end_object = none
813 0x01, // 1 parameter
814 0x02, 0x03, 0x62, 0x61, 0x72, // authorization_info = "bar"
815 };
816 parser.ProcessData(absl::string_view(subscribe, sizeof(subscribe)), false);
817 EXPECT_EQ(visitor_.messages_received_, 1);
818 MoqtSubscribe message = std::get<MoqtSubscribe>(*visitor_.last_message_);
819 EXPECT_FALSE(visitor_.parsing_error_.has_value());
820 ASSERT_TRUE(message.start_group.has_value());
821 ASSERT_FALSE(message.start_group->absolute);
822 EXPECT_EQ(message.start_group->relative_value, 0);
823 ASSERT_TRUE(message.start_object.has_value());
824 ASSERT_FALSE(message.start_object->absolute);
825 EXPECT_EQ(message.start_object->relative_value, 1);
826 }
827
TEST_F(MoqtMessageSpecificTest,DatagramSuccessful)828 TEST_F(MoqtMessageSpecificTest, DatagramSuccessful) {
829 ObjectDatagramMessage message;
830 MoqtObject object;
831 absl::string_view payload =
832 MoqtParser::ProcessDatagram(message.PacketSample(), object);
833 TestMessageBase::MessageStructuredData object_metadata =
834 TestMessageBase::MessageStructuredData(object);
835 EXPECT_TRUE(message.EqualFieldValues(object_metadata));
836 EXPECT_EQ(payload, "foo");
837 }
838
TEST_F(MoqtMessageSpecificTest,WrongMessageInDatagram)839 TEST_F(MoqtMessageSpecificTest, WrongMessageInDatagram) {
840 MoqtParser parser(kRawQuic, visitor_);
841 ObjectStreamMessage message;
842 MoqtObject object;
843 absl::string_view payload =
844 MoqtParser::ProcessDatagram(message.PacketSample(), object);
845 EXPECT_TRUE(payload.empty());
846 }
847
TEST_F(MoqtMessageSpecificTest,TruncatedDatagram)848 TEST_F(MoqtMessageSpecificTest, TruncatedDatagram) {
849 MoqtParser parser(kRawQuic, visitor_);
850 ObjectDatagramMessage message;
851 message.set_wire_image_size(4);
852 MoqtObject object;
853 absl::string_view payload =
854 MoqtParser::ProcessDatagram(message.PacketSample(), object);
855 EXPECT_TRUE(payload.empty());
856 }
857
TEST_F(MoqtMessageSpecificTest,VeryTruncatedDatagram)858 TEST_F(MoqtMessageSpecificTest, VeryTruncatedDatagram) {
859 MoqtParser parser(kRawQuic, visitor_);
860 char message = 0x40;
861 MoqtObject object;
862 absl::string_view payload = MoqtParser::ProcessDatagram(
863 absl::string_view(&message, sizeof(message)), object);
864 EXPECT_TRUE(payload.empty());
865 }
866
TEST_F(MoqtMessageSpecificTest,SubscribeOkInvalidContentExists)867 TEST_F(MoqtMessageSpecificTest, SubscribeOkInvalidContentExists) {
868 MoqtParser parser(kRawQuic, visitor_);
869 SubscribeOkMessage subscribe_ok;
870 subscribe_ok.SetInvalidContentExists();
871 parser.ProcessData(subscribe_ok.PacketSample(), false);
872 EXPECT_EQ(visitor_.messages_received_, 0);
873 EXPECT_TRUE(visitor_.parsing_error_.has_value());
874 EXPECT_EQ(*visitor_.parsing_error_,
875 "SUBSCRIBE_OK ContentExists has invalid value");
876 }
877
TEST_F(MoqtMessageSpecificTest,SubscribeDoneInvalidContentExists)878 TEST_F(MoqtMessageSpecificTest, SubscribeDoneInvalidContentExists) {
879 MoqtParser parser(kRawQuic, visitor_);
880 SubscribeDoneMessage subscribe_done;
881 subscribe_done.SetInvalidContentExists();
882 parser.ProcessData(subscribe_done.PacketSample(), false);
883 EXPECT_EQ(visitor_.messages_received_, 0);
884 EXPECT_TRUE(visitor_.parsing_error_.has_value());
885 EXPECT_EQ(*visitor_.parsing_error_,
886 "SUBSCRIBE_DONE ContentExists has invalid value");
887 }
888
889 } // namespace moqt::test
890