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