xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/common/capsule.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright (c) 2021 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/common/capsule.h"
6 
7 #include <cstddef>
8 #include <cstdint>
9 #include <limits>
10 #include <ostream>
11 #include <string>
12 #include <type_traits>
13 #include <utility>
14 
15 #include "absl/status/status.h"
16 #include "absl/status/statusor.h"
17 #include "absl/strings/escaping.h"
18 #include "absl/strings/str_cat.h"
19 #include "absl/strings/string_view.h"
20 #include "absl/types/span.h"
21 #include "absl/types/variant.h"
22 #include "quiche/common/platform/api/quiche_bug_tracker.h"
23 #include "quiche/common/platform/api/quiche_export.h"
24 #include "quiche/common/platform/api/quiche_logging.h"
25 #include "quiche/common/quiche_buffer_allocator.h"
26 #include "quiche/common/quiche_data_reader.h"
27 #include "quiche/common/quiche_data_writer.h"
28 #include "quiche/common/quiche_ip_address.h"
29 #include "quiche/common/quiche_status_utils.h"
30 #include "quiche/common/wire_serialization.h"
31 #include "quiche/web_transport/web_transport.h"
32 
33 namespace quiche {
34 
CapsuleTypeToString(CapsuleType capsule_type)35 std::string CapsuleTypeToString(CapsuleType capsule_type) {
36   switch (capsule_type) {
37     case CapsuleType::DATAGRAM:
38       return "DATAGRAM";
39     case CapsuleType::LEGACY_DATAGRAM:
40       return "LEGACY_DATAGRAM";
41     case CapsuleType::LEGACY_DATAGRAM_WITHOUT_CONTEXT:
42       return "LEGACY_DATAGRAM_WITHOUT_CONTEXT";
43     case CapsuleType::CLOSE_WEBTRANSPORT_SESSION:
44       return "CLOSE_WEBTRANSPORT_SESSION";
45     case CapsuleType::DRAIN_WEBTRANSPORT_SESSION:
46       return "DRAIN_WEBTRANSPORT_SESSION";
47     case CapsuleType::ADDRESS_REQUEST:
48       return "ADDRESS_REQUEST";
49     case CapsuleType::ADDRESS_ASSIGN:
50       return "ADDRESS_ASSIGN";
51     case CapsuleType::ROUTE_ADVERTISEMENT:
52       return "ROUTE_ADVERTISEMENT";
53     case CapsuleType::WT_STREAM:
54       return "WT_STREAM";
55     case CapsuleType::WT_STREAM_WITH_FIN:
56       return "WT_STREAM_WITH_FIN";
57     case CapsuleType::WT_RESET_STREAM:
58       return "WT_RESET_STREAM";
59     case CapsuleType::WT_STOP_SENDING:
60       return "WT_STOP_SENDING";
61     case CapsuleType::WT_MAX_STREAM_DATA:
62       return "WT_MAX_STREAM_DATA";
63     case CapsuleType::WT_MAX_STREAMS_BIDI:
64       return "WT_MAX_STREAMS_BIDI";
65     case CapsuleType::WT_MAX_STREAMS_UNIDI:
66       return "WT_MAX_STREAMS_UNIDI";
67   }
68   return absl::StrCat("Unknown(", static_cast<uint64_t>(capsule_type), ")");
69 }
70 
operator <<(std::ostream & os,const CapsuleType & capsule_type)71 std::ostream& operator<<(std::ostream& os, const CapsuleType& capsule_type) {
72   os << CapsuleTypeToString(capsule_type);
73   return os;
74 }
75 
76 // static
Datagram(absl::string_view http_datagram_payload)77 Capsule Capsule::Datagram(absl::string_view http_datagram_payload) {
78   return Capsule(DatagramCapsule{http_datagram_payload});
79 }
80 
81 // static
LegacyDatagram(absl::string_view http_datagram_payload)82 Capsule Capsule::LegacyDatagram(absl::string_view http_datagram_payload) {
83   return Capsule(LegacyDatagramCapsule{http_datagram_payload});
84 }
85 
86 // static
LegacyDatagramWithoutContext(absl::string_view http_datagram_payload)87 Capsule Capsule::LegacyDatagramWithoutContext(
88     absl::string_view http_datagram_payload) {
89   return Capsule(LegacyDatagramWithoutContextCapsule{http_datagram_payload});
90 }
91 
92 // static
CloseWebTransportSession(webtransport::SessionErrorCode error_code,absl::string_view error_message)93 Capsule Capsule::CloseWebTransportSession(
94     webtransport::SessionErrorCode error_code,
95     absl::string_view error_message) {
96   return Capsule(CloseWebTransportSessionCapsule({error_code, error_message}));
97 }
98 
99 // static
AddressRequest()100 Capsule Capsule::AddressRequest() { return Capsule(AddressRequestCapsule()); }
101 
102 // static
AddressAssign()103 Capsule Capsule::AddressAssign() { return Capsule(AddressAssignCapsule()); }
104 
105 // static
RouteAdvertisement()106 Capsule Capsule::RouteAdvertisement() {
107   return Capsule(RouteAdvertisementCapsule());
108 }
109 
110 // static
Unknown(uint64_t capsule_type,absl::string_view unknown_capsule_data)111 Capsule Capsule::Unknown(uint64_t capsule_type,
112                          absl::string_view unknown_capsule_data) {
113   return Capsule(UnknownCapsule{capsule_type, unknown_capsule_data});
114 }
115 
operator ==(const Capsule & other) const116 bool Capsule::operator==(const Capsule& other) const {
117   return capsule_ == other.capsule_;
118 }
119 
ToString() const120 std::string DatagramCapsule::ToString() const {
121   return absl::StrCat("DATAGRAM[",
122                       absl::BytesToHexString(http_datagram_payload), "]");
123 }
124 
ToString() const125 std::string LegacyDatagramCapsule::ToString() const {
126   return absl::StrCat("LEGACY_DATAGRAM[",
127                       absl::BytesToHexString(http_datagram_payload), "]");
128 }
129 
ToString() const130 std::string LegacyDatagramWithoutContextCapsule::ToString() const {
131   return absl::StrCat("LEGACY_DATAGRAM_WITHOUT_CONTEXT[",
132                       absl::BytesToHexString(http_datagram_payload), "]");
133 }
134 
ToString() const135 std::string CloseWebTransportSessionCapsule::ToString() const {
136   return absl::StrCat("CLOSE_WEBTRANSPORT_SESSION(error_code=", error_code,
137                       ",error_message=\"", error_message, "\")");
138 }
139 
ToString() const140 std::string DrainWebTransportSessionCapsule::ToString() const {
141   return "DRAIN_WEBTRANSPORT_SESSION()";
142 }
143 
ToString() const144 std::string AddressRequestCapsule::ToString() const {
145   std::string rv = "ADDRESS_REQUEST[";
146   for (auto requested_address : requested_addresses) {
147     absl::StrAppend(&rv, "(", requested_address.request_id, "-",
148                     requested_address.ip_prefix.ToString(), ")");
149   }
150   absl::StrAppend(&rv, "]");
151   return rv;
152 }
153 
ToString() const154 std::string AddressAssignCapsule::ToString() const {
155   std::string rv = "ADDRESS_ASSIGN[";
156   for (auto assigned_address : assigned_addresses) {
157     absl::StrAppend(&rv, "(", assigned_address.request_id, "-",
158                     assigned_address.ip_prefix.ToString(), ")");
159   }
160   absl::StrAppend(&rv, "]");
161   return rv;
162 }
163 
ToString() const164 std::string RouteAdvertisementCapsule::ToString() const {
165   std::string rv = "ROUTE_ADVERTISEMENT[";
166   for (auto ip_address_range : ip_address_ranges) {
167     absl::StrAppend(&rv, "(", ip_address_range.start_ip_address.ToString(), "-",
168                     ip_address_range.end_ip_address.ToString(), "-",
169                     static_cast<int>(ip_address_range.ip_protocol), ")");
170   }
171   absl::StrAppend(&rv, "]");
172   return rv;
173 }
174 
ToString() const175 std::string UnknownCapsule::ToString() const {
176   return absl::StrCat("Unknown(", type, ") [", absl::BytesToHexString(payload),
177                       "]");
178 }
179 
ToString() const180 std::string WebTransportStreamDataCapsule::ToString() const {
181   return absl::StrCat(CapsuleTypeToString(capsule_type()),
182                       " [stream_id=", stream_id,
183                       ", data=", absl::BytesToHexString(data), "]");
184 }
185 
ToString() const186 std::string WebTransportResetStreamCapsule::ToString() const {
187   return absl::StrCat("WT_RESET_STREAM(stream_id=", stream_id,
188                       ", error_code=", error_code, ")");
189 }
190 
ToString() const191 std::string WebTransportStopSendingCapsule::ToString() const {
192   return absl::StrCat("WT_STOP_SENDING(stream_id=", stream_id,
193                       ", error_code=", error_code, ")");
194 }
195 
ToString() const196 std::string WebTransportMaxStreamDataCapsule::ToString() const {
197   return absl::StrCat("WT_MAX_STREAM_DATA (stream_id=", stream_id,
198                       ", max_stream_data=", max_stream_data, ")");
199 }
200 
ToString() const201 std::string WebTransportMaxStreamsCapsule::ToString() const {
202   return absl::StrCat(CapsuleTypeToString(capsule_type()),
203                       " (max_streams=", max_stream_count, ")");
204 }
205 
ToString() const206 std::string Capsule::ToString() const {
207   return absl::visit([](const auto& capsule) { return capsule.ToString(); },
208                      capsule_);
209 }
210 
operator <<(std::ostream & os,const Capsule & capsule)211 std::ostream& operator<<(std::ostream& os, const Capsule& capsule) {
212   os << capsule.ToString();
213   return os;
214 }
215 
CapsuleParser(Visitor * visitor)216 CapsuleParser::CapsuleParser(Visitor* visitor) : visitor_(visitor) {
217   QUICHE_DCHECK_NE(visitor_, nullptr);
218 }
219 
220 // Serialization logic for quiche::PrefixWithId.
221 class WirePrefixWithId {
222  public:
223   using DataType = PrefixWithId;
224 
WirePrefixWithId(const PrefixWithId & prefix)225   WirePrefixWithId(const PrefixWithId& prefix) : prefix_(prefix) {}
226 
GetLengthOnWire()227   size_t GetLengthOnWire() {
228     return ComputeLengthOnWire(
229         WireVarInt62(prefix_.request_id),
230         WireUint8(prefix_.ip_prefix.address().IsIPv4() ? 4 : 6),
231         WireBytes(prefix_.ip_prefix.address().ToPackedString()),
232         WireUint8(prefix_.ip_prefix.prefix_length()));
233   }
234 
SerializeIntoWriter(QuicheDataWriter & writer)235   absl::Status SerializeIntoWriter(QuicheDataWriter& writer) {
236     return AppendToStatus(
237         quiche::SerializeIntoWriter(
238             writer, WireVarInt62(prefix_.request_id),
239             WireUint8(prefix_.ip_prefix.address().IsIPv4() ? 4 : 6),
240             WireBytes(prefix_.ip_prefix.address().ToPackedString()),
241             WireUint8(prefix_.ip_prefix.prefix_length())),
242         " while serializing a PrefixWithId");
243   }
244 
245  private:
246   const PrefixWithId& prefix_;
247 };
248 
249 // Serialization logic for quiche::IpAddressRange.
250 class WireIpAddressRange {
251  public:
252   using DataType = IpAddressRange;
253 
WireIpAddressRange(const IpAddressRange & range)254   explicit WireIpAddressRange(const IpAddressRange& range) : range_(range) {}
255 
GetLengthOnWire()256   size_t GetLengthOnWire() {
257     return ComputeLengthOnWire(
258         WireUint8(range_.start_ip_address.IsIPv4() ? 4 : 6),
259         WireBytes(range_.start_ip_address.ToPackedString()),
260         WireBytes(range_.end_ip_address.ToPackedString()),
261         WireUint8(range_.ip_protocol));
262   }
263 
SerializeIntoWriter(QuicheDataWriter & writer)264   absl::Status SerializeIntoWriter(QuicheDataWriter& writer) {
265     return AppendToStatus(
266         ::quiche::SerializeIntoWriter(
267             writer, WireUint8(range_.start_ip_address.IsIPv4() ? 4 : 6),
268             WireBytes(range_.start_ip_address.ToPackedString()),
269             WireBytes(range_.end_ip_address.ToPackedString()),
270             WireUint8(range_.ip_protocol)),
271         " while serializing an IpAddressRange");
272   }
273 
274  private:
275   const IpAddressRange& range_;
276 };
277 
278 template <typename... T>
SerializeCapsuleFields(CapsuleType type,QuicheBufferAllocator * allocator,T...fields)279 absl::StatusOr<quiche::QuicheBuffer> SerializeCapsuleFields(
280     CapsuleType type, QuicheBufferAllocator* allocator, T... fields) {
281   size_t capsule_payload_size = ComputeLengthOnWire(fields...);
282   return SerializeIntoBuffer(allocator, WireVarInt62(type),
283                              WireVarInt62(capsule_payload_size), fields...);
284 }
285 
SerializeCapsuleWithStatus(const Capsule & capsule,quiche::QuicheBufferAllocator * allocator)286 absl::StatusOr<quiche::QuicheBuffer> SerializeCapsuleWithStatus(
287     const Capsule& capsule, quiche::QuicheBufferAllocator* allocator) {
288   switch (capsule.capsule_type()) {
289     case CapsuleType::DATAGRAM:
290       return SerializeCapsuleFields(
291           capsule.capsule_type(), allocator,
292           WireBytes(capsule.datagram_capsule().http_datagram_payload));
293     case CapsuleType::LEGACY_DATAGRAM:
294       return SerializeCapsuleFields(
295           capsule.capsule_type(), allocator,
296           WireBytes(capsule.legacy_datagram_capsule().http_datagram_payload));
297     case CapsuleType::LEGACY_DATAGRAM_WITHOUT_CONTEXT:
298       return SerializeCapsuleFields(
299           capsule.capsule_type(), allocator,
300           WireBytes(capsule.legacy_datagram_without_context_capsule()
301                         .http_datagram_payload));
302     case CapsuleType::CLOSE_WEBTRANSPORT_SESSION:
303       return SerializeCapsuleFields(
304           capsule.capsule_type(), allocator,
305           WireUint32(capsule.close_web_transport_session_capsule().error_code),
306           WireBytes(
307               capsule.close_web_transport_session_capsule().error_message));
308     case CapsuleType::DRAIN_WEBTRANSPORT_SESSION:
309       return SerializeCapsuleFields(capsule.capsule_type(), allocator);
310     case CapsuleType::ADDRESS_REQUEST:
311       return SerializeCapsuleFields(
312           capsule.capsule_type(), allocator,
313           WireSpan<WirePrefixWithId>(absl::MakeConstSpan(
314               capsule.address_request_capsule().requested_addresses)));
315     case CapsuleType::ADDRESS_ASSIGN:
316       return SerializeCapsuleFields(
317           capsule.capsule_type(), allocator,
318           WireSpan<WirePrefixWithId>(absl::MakeConstSpan(
319               capsule.address_assign_capsule().assigned_addresses)));
320     case CapsuleType::ROUTE_ADVERTISEMENT:
321       return SerializeCapsuleFields(
322           capsule.capsule_type(), allocator,
323           WireSpan<WireIpAddressRange>(absl::MakeConstSpan(
324               capsule.route_advertisement_capsule().ip_address_ranges)));
325     case CapsuleType::WT_STREAM:
326     case CapsuleType::WT_STREAM_WITH_FIN:
327       return SerializeCapsuleFields(
328           capsule.capsule_type(), allocator,
329           WireVarInt62(capsule.web_transport_stream_data().stream_id),
330           WireBytes(capsule.web_transport_stream_data().data));
331     case CapsuleType::WT_RESET_STREAM:
332       return SerializeCapsuleFields(
333           capsule.capsule_type(), allocator,
334           WireVarInt62(capsule.web_transport_reset_stream().stream_id),
335           WireVarInt62(capsule.web_transport_reset_stream().error_code));
336     case CapsuleType::WT_STOP_SENDING:
337       return SerializeCapsuleFields(
338           capsule.capsule_type(), allocator,
339           WireVarInt62(capsule.web_transport_stop_sending().stream_id),
340           WireVarInt62(capsule.web_transport_stop_sending().error_code));
341     case CapsuleType::WT_MAX_STREAM_DATA:
342       return SerializeCapsuleFields(
343           capsule.capsule_type(), allocator,
344           WireVarInt62(capsule.web_transport_max_stream_data().stream_id),
345           WireVarInt62(
346               capsule.web_transport_max_stream_data().max_stream_data));
347     case CapsuleType::WT_MAX_STREAMS_BIDI:
348     case CapsuleType::WT_MAX_STREAMS_UNIDI:
349       return SerializeCapsuleFields(
350           capsule.capsule_type(), allocator,
351           WireVarInt62(capsule.web_transport_max_streams().max_stream_count));
352     default:
353       return SerializeCapsuleFields(
354           capsule.capsule_type(), allocator,
355           WireBytes(capsule.unknown_capsule().payload));
356   }
357 }
358 
SerializeDatagramCapsuleHeader(uint64_t datagram_size,QuicheBufferAllocator * allocator)359 QuicheBuffer SerializeDatagramCapsuleHeader(uint64_t datagram_size,
360                                             QuicheBufferAllocator* allocator) {
361   absl::StatusOr<QuicheBuffer> buffer =
362       SerializeIntoBuffer(allocator, WireVarInt62(CapsuleType::DATAGRAM),
363                           WireVarInt62(datagram_size));
364   if (!buffer.ok()) {
365     return QuicheBuffer();
366   }
367   return *std::move(buffer);
368 }
369 
SerializeWebTransportStreamCapsuleHeader(webtransport::StreamId stream_id,bool fin,uint64_t write_size,QuicheBufferAllocator * allocator)370 QUICHE_EXPORT QuicheBuffer SerializeWebTransportStreamCapsuleHeader(
371     webtransport::StreamId stream_id, bool fin, uint64_t write_size,
372     QuicheBufferAllocator* allocator) {
373   absl::StatusOr<QuicheBuffer> buffer = SerializeIntoBuffer(
374       allocator,
375       WireVarInt62(fin ? CapsuleType::WT_STREAM_WITH_FIN
376                        : CapsuleType::WT_STREAM),
377       WireVarInt62(write_size + QuicheDataWriter::GetVarInt62Len(stream_id)),
378       WireVarInt62(stream_id));
379   if (!buffer.ok()) {
380     return QuicheBuffer();
381   }
382   return *std::move(buffer);
383 }
384 
SerializeCapsule(const Capsule & capsule,quiche::QuicheBufferAllocator * allocator)385 QuicheBuffer SerializeCapsule(const Capsule& capsule,
386                               quiche::QuicheBufferAllocator* allocator) {
387   absl::StatusOr<QuicheBuffer> serialized =
388       SerializeCapsuleWithStatus(capsule, allocator);
389   if (!serialized.ok()) {
390     QUICHE_BUG(capsule_serialization_failed)
391         << "Failed to serialize the following capsule:\n"
392         << capsule << "Serialization error: " << serialized.status();
393     return QuicheBuffer();
394   }
395   return *std::move(serialized);
396 }
397 
IngestCapsuleFragment(absl::string_view capsule_fragment)398 bool CapsuleParser::IngestCapsuleFragment(absl::string_view capsule_fragment) {
399   if (parsing_error_occurred_) {
400     return false;
401   }
402   absl::StrAppend(&buffered_data_, capsule_fragment);
403   while (true) {
404     const absl::StatusOr<size_t> buffered_data_read = AttemptParseCapsule();
405     if (!buffered_data_read.ok()) {
406       ReportParseFailure(buffered_data_read.status().message());
407       buffered_data_.clear();
408       return false;
409     }
410     if (*buffered_data_read == 0) {
411       break;
412     }
413     buffered_data_.erase(0, *buffered_data_read);
414   }
415   static constexpr size_t kMaxCapsuleBufferSize = 1024 * 1024;
416   if (buffered_data_.size() > kMaxCapsuleBufferSize) {
417     buffered_data_.clear();
418     ReportParseFailure("Refusing to buffer too much capsule data");
419     return false;
420   }
421   return true;
422 }
423 
424 namespace {
ReadWebTransportStreamId(QuicheDataReader & reader,webtransport::StreamId & id)425 absl::Status ReadWebTransportStreamId(QuicheDataReader& reader,
426                                       webtransport::StreamId& id) {
427   uint64_t raw_id;
428   if (!reader.ReadVarInt62(&raw_id)) {
429     return absl::InvalidArgumentError("Failed to read WebTransport Stream ID");
430   }
431   if (raw_id > std::numeric_limits<uint32_t>::max()) {
432     return absl::InvalidArgumentError("Stream ID does not fit into a uint32_t");
433   }
434   id = static_cast<webtransport::StreamId>(raw_id);
435   return absl::OkStatus();
436 }
437 
ParseCapsulePayload(QuicheDataReader & reader,CapsuleType type)438 absl::StatusOr<Capsule> ParseCapsulePayload(QuicheDataReader& reader,
439                                             CapsuleType type) {
440   switch (type) {
441     case CapsuleType::DATAGRAM:
442       return Capsule::Datagram(reader.ReadRemainingPayload());
443     case CapsuleType::LEGACY_DATAGRAM:
444       return Capsule::LegacyDatagram(reader.ReadRemainingPayload());
445     case CapsuleType::LEGACY_DATAGRAM_WITHOUT_CONTEXT:
446       return Capsule::LegacyDatagramWithoutContext(
447           reader.ReadRemainingPayload());
448     case CapsuleType::CLOSE_WEBTRANSPORT_SESSION: {
449       CloseWebTransportSessionCapsule capsule;
450       if (!reader.ReadUInt32(&capsule.error_code)) {
451         return absl::InvalidArgumentError(
452             "Unable to parse capsule CLOSE_WEBTRANSPORT_SESSION error code");
453       }
454       capsule.error_message = reader.ReadRemainingPayload();
455       return Capsule(std::move(capsule));
456     }
457     case CapsuleType::DRAIN_WEBTRANSPORT_SESSION:
458       return Capsule(DrainWebTransportSessionCapsule());
459     case CapsuleType::ADDRESS_REQUEST: {
460       AddressRequestCapsule capsule;
461       while (!reader.IsDoneReading()) {
462         PrefixWithId requested_address;
463         if (!reader.ReadVarInt62(&requested_address.request_id)) {
464           return absl::InvalidArgumentError(
465               "Unable to parse capsule ADDRESS_REQUEST request ID");
466         }
467         uint8_t address_family;
468         if (!reader.ReadUInt8(&address_family)) {
469           return absl::InvalidArgumentError(
470               "Unable to parse capsule ADDRESS_REQUEST family");
471         }
472         if (address_family != 4 && address_family != 6) {
473           return absl::InvalidArgumentError("Bad ADDRESS_REQUEST family");
474         }
475         absl::string_view ip_address_bytes;
476         if (!reader.ReadStringPiece(&ip_address_bytes,
477                                     address_family == 4
478                                         ? QuicheIpAddress::kIPv4AddressSize
479                                         : QuicheIpAddress::kIPv6AddressSize)) {
480           return absl::InvalidArgumentError(
481               "Unable to read capsule ADDRESS_REQUEST address");
482         }
483         quiche::QuicheIpAddress ip_address;
484         if (!ip_address.FromPackedString(ip_address_bytes.data(),
485                                          ip_address_bytes.size())) {
486           return absl::InvalidArgumentError(
487               "Unable to parse capsule ADDRESS_REQUEST address");
488         }
489         uint8_t ip_prefix_length;
490         if (!reader.ReadUInt8(&ip_prefix_length)) {
491           return absl::InvalidArgumentError(
492               "Unable to parse capsule ADDRESS_REQUEST IP prefix length");
493         }
494         if (ip_prefix_length > QuicheIpPrefix(ip_address).prefix_length()) {
495           return absl::InvalidArgumentError("Invalid IP prefix length");
496         }
497         requested_address.ip_prefix =
498             QuicheIpPrefix(ip_address, ip_prefix_length);
499         capsule.requested_addresses.push_back(requested_address);
500       }
501       return Capsule(std::move(capsule));
502     }
503     case CapsuleType::ADDRESS_ASSIGN: {
504       AddressAssignCapsule capsule;
505       while (!reader.IsDoneReading()) {
506         PrefixWithId assigned_address;
507         if (!reader.ReadVarInt62(&assigned_address.request_id)) {
508           return absl::InvalidArgumentError(
509               "Unable to parse capsule ADDRESS_ASSIGN request ID");
510         }
511         uint8_t address_family;
512         if (!reader.ReadUInt8(&address_family)) {
513           return absl::InvalidArgumentError(
514               "Unable to parse capsule ADDRESS_ASSIGN family");
515         }
516         if (address_family != 4 && address_family != 6) {
517           return absl::InvalidArgumentError("Bad ADDRESS_ASSIGN family");
518         }
519         absl::string_view ip_address_bytes;
520         if (!reader.ReadStringPiece(&ip_address_bytes,
521                                     address_family == 4
522                                         ? QuicheIpAddress::kIPv4AddressSize
523                                         : QuicheIpAddress::kIPv6AddressSize)) {
524           return absl::InvalidArgumentError(
525               "Unable to read capsule ADDRESS_ASSIGN address");
526         }
527         quiche::QuicheIpAddress ip_address;
528         if (!ip_address.FromPackedString(ip_address_bytes.data(),
529                                          ip_address_bytes.size())) {
530           return absl::InvalidArgumentError(
531               "Unable to parse capsule ADDRESS_ASSIGN address");
532         }
533         uint8_t ip_prefix_length;
534         if (!reader.ReadUInt8(&ip_prefix_length)) {
535           return absl::InvalidArgumentError(
536               "Unable to parse capsule ADDRESS_ASSIGN IP prefix length");
537         }
538         if (ip_prefix_length > QuicheIpPrefix(ip_address).prefix_length()) {
539           return absl::InvalidArgumentError("Invalid IP prefix length");
540         }
541         assigned_address.ip_prefix =
542             QuicheIpPrefix(ip_address, ip_prefix_length);
543         capsule.assigned_addresses.push_back(assigned_address);
544       }
545       return Capsule(std::move(capsule));
546     }
547     case CapsuleType::ROUTE_ADVERTISEMENT: {
548       RouteAdvertisementCapsule capsule;
549       while (!reader.IsDoneReading()) {
550         uint8_t address_family;
551         if (!reader.ReadUInt8(&address_family)) {
552           return absl::InvalidArgumentError(
553               "Unable to parse capsule ROUTE_ADVERTISEMENT family");
554         }
555         if (address_family != 4 && address_family != 6) {
556           return absl::InvalidArgumentError("Bad ROUTE_ADVERTISEMENT family");
557         }
558         IpAddressRange ip_address_range;
559         absl::string_view start_ip_address_bytes;
560         if (!reader.ReadStringPiece(&start_ip_address_bytes,
561                                     address_family == 4
562                                         ? QuicheIpAddress::kIPv4AddressSize
563                                         : QuicheIpAddress::kIPv6AddressSize)) {
564           return absl::InvalidArgumentError(
565               "Unable to read capsule ROUTE_ADVERTISEMENT start address");
566         }
567         if (!ip_address_range.start_ip_address.FromPackedString(
568                 start_ip_address_bytes.data(), start_ip_address_bytes.size())) {
569           return absl::InvalidArgumentError(
570               "Unable to parse capsule ROUTE_ADVERTISEMENT start address");
571         }
572         absl::string_view end_ip_address_bytes;
573         if (!reader.ReadStringPiece(&end_ip_address_bytes,
574                                     address_family == 4
575                                         ? QuicheIpAddress::kIPv4AddressSize
576                                         : QuicheIpAddress::kIPv6AddressSize)) {
577           return absl::InvalidArgumentError(
578               "Unable to read capsule ROUTE_ADVERTISEMENT end address");
579         }
580         if (!ip_address_range.end_ip_address.FromPackedString(
581                 end_ip_address_bytes.data(), end_ip_address_bytes.size())) {
582           return absl::InvalidArgumentError(
583               "Unable to parse capsule ROUTE_ADVERTISEMENT end address");
584         }
585         if (!reader.ReadUInt8(&ip_address_range.ip_protocol)) {
586           return absl::InvalidArgumentError(
587               "Unable to parse capsule ROUTE_ADVERTISEMENT IP protocol");
588         }
589         capsule.ip_address_ranges.push_back(ip_address_range);
590       }
591       return Capsule(std::move(capsule));
592     }
593     case CapsuleType::WT_STREAM:
594     case CapsuleType::WT_STREAM_WITH_FIN: {
595       WebTransportStreamDataCapsule capsule;
596       capsule.fin = (type == CapsuleType::WT_STREAM_WITH_FIN);
597       QUICHE_RETURN_IF_ERROR(
598           ReadWebTransportStreamId(reader, capsule.stream_id));
599       capsule.data = reader.ReadRemainingPayload();
600       return Capsule(std::move(capsule));
601     }
602     case CapsuleType::WT_RESET_STREAM: {
603       WebTransportResetStreamCapsule capsule;
604       QUICHE_RETURN_IF_ERROR(
605           ReadWebTransportStreamId(reader, capsule.stream_id));
606       if (!reader.ReadVarInt62(&capsule.error_code)) {
607         return absl::InvalidArgumentError(
608             "Failed to parse the RESET_STREAM error code");
609       }
610       return Capsule(std::move(capsule));
611     }
612     case CapsuleType::WT_STOP_SENDING: {
613       WebTransportStopSendingCapsule capsule;
614       QUICHE_RETURN_IF_ERROR(
615           ReadWebTransportStreamId(reader, capsule.stream_id));
616       if (!reader.ReadVarInt62(&capsule.error_code)) {
617         return absl::InvalidArgumentError(
618             "Failed to parse the STOP_SENDING error code");
619       }
620       return Capsule(std::move(capsule));
621     }
622     case CapsuleType::WT_MAX_STREAM_DATA: {
623       WebTransportMaxStreamDataCapsule capsule;
624       QUICHE_RETURN_IF_ERROR(
625           ReadWebTransportStreamId(reader, capsule.stream_id));
626       if (!reader.ReadVarInt62(&capsule.max_stream_data)) {
627         return absl::InvalidArgumentError(
628             "Failed to parse the max stream data field");
629       }
630       return Capsule(std::move(capsule));
631     }
632     case CapsuleType::WT_MAX_STREAMS_UNIDI:
633     case CapsuleType::WT_MAX_STREAMS_BIDI: {
634       WebTransportMaxStreamsCapsule capsule;
635       capsule.stream_type = type == CapsuleType::WT_MAX_STREAMS_UNIDI
636                                 ? webtransport::StreamType::kUnidirectional
637                                 : webtransport::StreamType::kBidirectional;
638       if (!reader.ReadVarInt62(&capsule.max_stream_count)) {
639         return absl::InvalidArgumentError(
640             "Failed to parse the max streams field");
641       }
642       return Capsule(std::move(capsule));
643     }
644     default:
645       return Capsule(UnknownCapsule{static_cast<uint64_t>(type),
646                                     reader.ReadRemainingPayload()});
647   }
648 }
649 }  // namespace
650 
AttemptParseCapsule()651 absl::StatusOr<size_t> CapsuleParser::AttemptParseCapsule() {
652   QUICHE_DCHECK(!parsing_error_occurred_);
653   if (buffered_data_.empty()) {
654     return 0;
655   }
656   QuicheDataReader capsule_fragment_reader(buffered_data_);
657   uint64_t capsule_type64;
658   if (!capsule_fragment_reader.ReadVarInt62(&capsule_type64)) {
659     QUICHE_DVLOG(2) << "Partial read: not enough data to read capsule type";
660     return 0;
661   }
662   absl::string_view capsule_data;
663   if (!capsule_fragment_reader.ReadStringPieceVarInt62(&capsule_data)) {
664     QUICHE_DVLOG(2)
665         << "Partial read: not enough data to read capsule length or "
666            "full capsule data";
667     return 0;
668   }
669   QuicheDataReader capsule_data_reader(capsule_data);
670   absl::StatusOr<Capsule> capsule = ParseCapsulePayload(
671       capsule_data_reader, static_cast<CapsuleType>(capsule_type64));
672   QUICHE_RETURN_IF_ERROR(capsule.status());
673   if (!visitor_->OnCapsule(*capsule)) {
674     return absl::AbortedError("Visitor failed to process capsule");
675   }
676   return capsule_fragment_reader.PreviouslyReadPayload().length();
677 }
678 
ReportParseFailure(absl::string_view error_message)679 void CapsuleParser::ReportParseFailure(absl::string_view error_message) {
680   if (parsing_error_occurred_) {
681     QUICHE_BUG(multiple parse errors) << "Experienced multiple parse failures";
682     return;
683   }
684   parsing_error_occurred_ = true;
685   visitor_->OnCapsuleParseFailure(error_message);
686 }
687 
ErrorIfThereIsRemainingBufferedData()688 void CapsuleParser::ErrorIfThereIsRemainingBufferedData() {
689   if (parsing_error_occurred_) {
690     return;
691   }
692   if (!buffered_data_.empty()) {
693     ReportParseFailure("Incomplete capsule left at the end of the stream");
694   }
695 }
696 
operator ==(const PrefixWithId & other) const697 bool PrefixWithId::operator==(const PrefixWithId& other) const {
698   return request_id == other.request_id && ip_prefix == other.ip_prefix;
699 }
700 
operator ==(const IpAddressRange & other) const701 bool IpAddressRange::operator==(const IpAddressRange& other) const {
702   return start_ip_address == other.start_ip_address &&
703          end_ip_address == other.end_ip_address &&
704          ip_protocol == other.ip_protocol;
705 }
706 
operator ==(const AddressAssignCapsule & other) const707 bool AddressAssignCapsule::operator==(const AddressAssignCapsule& other) const {
708   return assigned_addresses == other.assigned_addresses;
709 }
710 
operator ==(const AddressRequestCapsule & other) const711 bool AddressRequestCapsule::operator==(
712     const AddressRequestCapsule& other) const {
713   return requested_addresses == other.requested_addresses;
714 }
715 
operator ==(const RouteAdvertisementCapsule & other) const716 bool RouteAdvertisementCapsule::operator==(
717     const RouteAdvertisementCapsule& other) const {
718   return ip_address_ranges == other.ip_address_ranges;
719 }
720 
operator ==(const WebTransportStreamDataCapsule & other) const721 bool WebTransportStreamDataCapsule::operator==(
722     const WebTransportStreamDataCapsule& other) const {
723   return stream_id == other.stream_id && data == other.data && fin == other.fin;
724 }
725 
operator ==(const WebTransportResetStreamCapsule & other) const726 bool WebTransportResetStreamCapsule::operator==(
727     const WebTransportResetStreamCapsule& other) const {
728   return stream_id == other.stream_id && error_code == other.error_code;
729 }
730 
operator ==(const WebTransportStopSendingCapsule & other) const731 bool WebTransportStopSendingCapsule::operator==(
732     const WebTransportStopSendingCapsule& other) const {
733   return stream_id == other.stream_id && error_code == other.error_code;
734 }
735 
operator ==(const WebTransportMaxStreamDataCapsule & other) const736 bool WebTransportMaxStreamDataCapsule::operator==(
737     const WebTransportMaxStreamDataCapsule& other) const {
738   return stream_id == other.stream_id &&
739          max_stream_data == other.max_stream_data;
740 }
741 
operator ==(const WebTransportMaxStreamsCapsule & other) const742 bool WebTransportMaxStreamsCapsule::operator==(
743     const WebTransportMaxStreamsCapsule& other) const {
744   return stream_type == other.stream_type &&
745          max_stream_count == other.max_stream_count;
746 }
747 
748 }  // namespace quiche
749