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