xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/moqt/moqt_parser.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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 // A parser for draft-ietf-moq-transport-01.
6 
7 #ifndef QUICHE_QUIC_MOQT_MOQT_PARSER_H_
8 #define QUICHE_QUIC_MOQT_MOQT_PARSER_H_
9 
10 #include <cstddef>
11 #include <cstdint>
12 #include <optional>
13 #include <string>
14 
15 #include "absl/strings/string_view.h"
16 #include "quiche/quic/core/quic_data_reader.h"
17 #include "quiche/quic/moqt/moqt_messages.h"
18 #include "quiche/common/platform/api/quiche_export.h"
19 
20 namespace moqt {
21 
22 class QUICHE_EXPORT MoqtParserVisitor {
23  public:
24   virtual ~MoqtParserVisitor() = default;
25 
26   // If |end_of_message| is true, |payload| contains the last bytes of the
27   // OBJECT payload. If not, there will be subsequent calls with further payload
28   // data. The parser retains ownership of |message| and |payload|, so the
29   // visitor needs to copy anything it wants to retain.
30   virtual void OnObjectMessage(const MoqtObject& message,
31                                absl::string_view payload,
32                                bool end_of_message) = 0;
33   // All of these are called only when the entire message has arrived. The
34   // parser retains ownership of the memory.
35   virtual void OnClientSetupMessage(const MoqtClientSetup& message) = 0;
36   virtual void OnServerSetupMessage(const MoqtServerSetup& message) = 0;
37   virtual void OnSubscribeMessage(const MoqtSubscribe& message) = 0;
38   virtual void OnSubscribeOkMessage(const MoqtSubscribeOk& message) = 0;
39   virtual void OnSubscribeErrorMessage(const MoqtSubscribeError& message) = 0;
40   virtual void OnUnsubscribeMessage(const MoqtUnsubscribe& message) = 0;
41   virtual void OnSubscribeDoneMessage(const MoqtSubscribeDone& message) = 0;
42   virtual void OnAnnounceMessage(const MoqtAnnounce& message) = 0;
43   virtual void OnAnnounceOkMessage(const MoqtAnnounceOk& message) = 0;
44   virtual void OnAnnounceErrorMessage(const MoqtAnnounceError& message) = 0;
45   virtual void OnUnannounceMessage(const MoqtUnannounce& message) = 0;
46   virtual void OnGoAwayMessage(const MoqtGoAway& message) = 0;
47 
48   virtual void OnParsingError(MoqtError code, absl::string_view reason) = 0;
49 };
50 
51 class QUICHE_EXPORT MoqtParser {
52  public:
MoqtParser(bool uses_web_transport,MoqtParserVisitor & visitor)53   MoqtParser(bool uses_web_transport, MoqtParserVisitor& visitor)
54       : visitor_(visitor), uses_web_transport_(uses_web_transport) {}
55   ~MoqtParser() = default;
56 
57   // Take a buffer from the transport in |data|. Parse each complete message and
58   // call the appropriate visitor function. If |fin| is true, there
59   // is no more data arriving on the stream, so the parser will deliver any
60   // message encoded as to run to the end of the stream.
61   // All bytes can be freed. Calls OnParsingError() when there is a parsing
62   // error.
63   // Any calls after sending |fin| = true will be ignored.
64   // TODO(martinduke): Figure out what has to happen if the message arrives via
65   // datagram rather than a stream.
66   void ProcessData(absl::string_view data, bool fin);
67 
68   // Provide a separate path for datagrams. Returns the payload bytes, or empty
69   // string_view on error. The caller provides the whole datagram in |data|.
70   // The function puts the object metadata in |object_metadata|.
71   static absl::string_view ProcessDatagram(absl::string_view data,
72                                            MoqtObject& object_metadata);
73 
74  private:
75   // The central switch statement to dispatch a message to the correct
76   // Process* function. Returns 0 if it could not parse the full messsage
77   // (except for object payload). Otherwise, returns the number of bytes
78   // processed.
79   size_t ProcessMessage(absl::string_view data, bool fin);
80   // The Process* functions parse the serialized data into the appropriate
81   // structs, and call the relevant visitor function for further action. Returns
82   // the number of bytes consumed if the message is complete; returns 0
83   // otherwise.
84   size_t ProcessObject(quic::QuicDataReader& reader, MoqtMessageType type,
85                        bool fin);
86   size_t ProcessClientSetup(quic::QuicDataReader& reader);
87   size_t ProcessServerSetup(quic::QuicDataReader& reader);
88   size_t ProcessSubscribe(quic::QuicDataReader& reader);
89   size_t ProcessSubscribeOk(quic::QuicDataReader& reader);
90   size_t ProcessSubscribeError(quic::QuicDataReader& reader);
91   size_t ProcessUnsubscribe(quic::QuicDataReader& reader);
92   size_t ProcessSubscribeDone(quic::QuicDataReader& reader);
93   size_t ProcessAnnounce(quic::QuicDataReader& reader);
94   size_t ProcessAnnounceOk(quic::QuicDataReader& reader);
95   size_t ProcessAnnounceError(quic::QuicDataReader& reader);
96   size_t ProcessUnannounce(quic::QuicDataReader& reader);
97   size_t ProcessGoAway(quic::QuicDataReader& reader);
98 
99   static size_t ParseObjectHeader(quic::QuicDataReader& reader,
100                                   MoqtObject& object, MoqtMessageType type);
101 
102   // If |error| is not provided, assumes kProtocolViolation.
103   void ParseError(absl::string_view reason);
104   void ParseError(MoqtError error, absl::string_view reason);
105 
106   // Reads an integer whose length is specified by a preceding VarInt62 and
107   // returns it in |result|. Returns false if parsing fails.
108   bool ReadVarIntPieceVarInt62(quic::QuicDataReader& reader, uint64_t& result);
109   // Read a Location field from SUBSCRIBE REQUEST
110   bool ReadLocation(quic::QuicDataReader& reader,
111                     std::optional<MoqtSubscribeLocation>& loc);
112   // Read a parameter and return the value as a string_view. Returns false if
113   // |reader| does not have enough data.
114   bool ReadParameter(quic::QuicDataReader& reader, uint64_t& type,
115                      absl::string_view& value);
116   // Convert a string view to a varint. Throws an error and returns false if the
117   // string_view is not exactly the right length.
118   bool StringViewToVarInt(absl::string_view& sv, uint64_t& vi);
119 
120   // Simplify understanding of state.
121   // Returns true if the stream has delivered all object metadata common to all
122   // objects on that stream.
ObjectStreamInitialized()123   bool ObjectStreamInitialized() const { return object_metadata_.has_value(); }
124   // Returns true if the stream has delivered all metadata but not all payload
125   // for the most recent object.
ObjectPayloadInProgress()126   bool ObjectPayloadInProgress() const {
127     return (object_metadata_.has_value() &&
128             (object_metadata_->forwarding_preference ==
129                  MoqtForwardingPreference::kObject ||
130              object_metadata_->forwarding_preference ==
131                  MoqtForwardingPreference::kDatagram ||
132              payload_length_remaining_ > 0));
133   }
134 
135   MoqtParserVisitor& visitor_;
136   bool uses_web_transport_;
137   bool no_more_data_ = false;  // Fatal error or fin. No more parsing.
138   bool parsing_error_ = false;
139 
140   std::string buffered_message_;
141 
142   // Metadata for an object which is delivered in parts.
143   // If object_metadata_ is nullopt, nothing has been processed on the stream.
144   // If object_metadata_ exists but payload_length is nullopt or
145   // payload_length_remaining_ is nonzero, the object payload is in mid-
146   // delivery.
147   // If object_metadata_ exists and payload_length_remaining_ is zero, an object
148   // has been completely delivered and the next object header on the stream has
149   // not been delivered.
150   // Use ObjectStreamInitialized() and ObjectPayloadInProgress() to keep the
151   // state straight.
152   std::optional<MoqtObject> object_metadata_ = std::nullopt;
153   size_t payload_length_remaining_ = 0;
154 
155   bool processing_ = false;  // True if currently in ProcessData(), to prevent
156                              // re-entrancy.
157 };
158 
159 }  // namespace moqt
160 
161 #endif  // QUICHE_QUIC_MOQT_MOQT_PARSER_H_
162