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