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