blob: 7b4cc46d16b0e1a3be89dadbc80bce2dd381b053 [file] [log] [blame]
// Copyright (c) 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef QUICHE_QUIC_CORE_HTTP_CAPSULE_H_
#define QUICHE_QUIC_CORE_HTTP_CAPSULE_H_
#include <cstdint>
#include <string>
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "quiche/quic/core/quic_data_reader.h"
#include "quiche/quic/core/quic_types.h"
#include "quiche/common/platform/api/quiche_logging.h"
#include "quiche/common/quiche_buffer_allocator.h"
namespace quic {
enum class CapsuleType : uint64_t {
// Casing in this enum matches the IETF specification.
LEGACY_DATAGRAM = 0xff37a0, // draft-ietf-masque-h3-datagram-04.
DATAGRAM_WITHOUT_CONTEXT =
0xff37a5, // draft-ietf-masque-h3-datagram-05 to -08.
CLOSE_WEBTRANSPORT_SESSION = 0x2843,
};
QUIC_EXPORT_PRIVATE std::string CapsuleTypeToString(CapsuleType capsule_type);
QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
const CapsuleType& capsule_type);
struct QUIC_EXPORT_PRIVATE LegacyDatagramCapsule {
absl::string_view http_datagram_payload;
};
struct QUIC_EXPORT_PRIVATE DatagramWithoutContextCapsule {
absl::string_view http_datagram_payload;
};
struct QUIC_EXPORT_PRIVATE CloseWebTransportSessionCapsule {
WebTransportSessionError error_code;
absl::string_view error_message;
};
// Capsule from draft-ietf-masque-h3-datagram.
// IMPORTANT NOTE: Capsule does not own any of the absl::string_view memory it
// points to. Strings saved into a capsule must outlive the capsule object. Any
// code that sees a capsule in a callback needs to either process it immediately
// or perform its own deep copy.
class QUIC_EXPORT_PRIVATE Capsule {
public:
static Capsule LegacyDatagram(
absl::string_view http_datagram_payload = absl::string_view());
static Capsule DatagramWithoutContext(
absl::string_view http_datagram_payload = absl::string_view());
static Capsule CloseWebTransportSession(
WebTransportSessionError error_code = 0,
absl::string_view error_message = "");
static Capsule Unknown(
uint64_t capsule_type,
absl::string_view unknown_capsule_data = absl::string_view());
explicit Capsule(CapsuleType capsule_type);
Capsule(const Capsule& other);
Capsule& operator=(const Capsule& other);
bool operator==(const Capsule& other) const;
// Human-readable information string for debugging purposes.
std::string ToString() const;
friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
const Capsule& capsule);
CapsuleType capsule_type() const { return capsule_type_; }
LegacyDatagramCapsule& legacy_datagram_capsule() {
QUICHE_DCHECK_EQ(capsule_type_, CapsuleType::LEGACY_DATAGRAM);
return legacy_datagram_capsule_;
}
const LegacyDatagramCapsule& legacy_datagram_capsule() const {
QUICHE_DCHECK_EQ(capsule_type_, CapsuleType::LEGACY_DATAGRAM);
return legacy_datagram_capsule_;
}
DatagramWithoutContextCapsule& datagram_without_context_capsule() {
QUICHE_DCHECK_EQ(capsule_type_, CapsuleType::DATAGRAM_WITHOUT_CONTEXT);
return datagram_without_context_capsule_;
}
const DatagramWithoutContextCapsule& datagram_without_context_capsule()
const {
QUICHE_DCHECK_EQ(capsule_type_, CapsuleType::DATAGRAM_WITHOUT_CONTEXT);
return datagram_without_context_capsule_;
}
CloseWebTransportSessionCapsule& close_web_transport_session_capsule() {
QUICHE_DCHECK_EQ(capsule_type_, CapsuleType::CLOSE_WEBTRANSPORT_SESSION);
return close_web_transport_session_capsule_;
}
const CloseWebTransportSessionCapsule& close_web_transport_session_capsule()
const {
QUICHE_DCHECK_EQ(capsule_type_, CapsuleType::CLOSE_WEBTRANSPORT_SESSION);
return close_web_transport_session_capsule_;
}
absl::string_view& unknown_capsule_data() {
QUICHE_DCHECK(capsule_type_ != CapsuleType::LEGACY_DATAGRAM &&
capsule_type_ != CapsuleType::DATAGRAM_WITHOUT_CONTEXT &&
capsule_type_ != CapsuleType::CLOSE_WEBTRANSPORT_SESSION)
<< capsule_type_;
return unknown_capsule_data_;
}
const absl::string_view& unknown_capsule_data() const {
QUICHE_DCHECK(capsule_type_ != CapsuleType::LEGACY_DATAGRAM &&
capsule_type_ != CapsuleType::DATAGRAM_WITHOUT_CONTEXT &&
capsule_type_ != CapsuleType::CLOSE_WEBTRANSPORT_SESSION)
<< capsule_type_;
return unknown_capsule_data_;
}
private:
CapsuleType capsule_type_;
union {
LegacyDatagramCapsule legacy_datagram_capsule_;
DatagramWithoutContextCapsule datagram_without_context_capsule_;
CloseWebTransportSessionCapsule close_web_transport_session_capsule_;
absl::string_view unknown_capsule_data_;
};
};
namespace test {
class CapsuleParserPeer;
} // namespace test
class QUIC_EXPORT_PRIVATE CapsuleParser {
public:
class QUIC_EXPORT_PRIVATE Visitor {
public:
virtual ~Visitor() {}
// Called when a capsule has been successfully parsed. The return value
// indicates whether the contents of the capsule are valid: if false is
// returned, the parse operation will be considered failed and
// OnCapsuleParseFailure will be called. Note that since Capsule does not
// own the memory backing its string_views, that memory is only valid until
// this callback returns. Visitors that wish to access the capsule later
// MUST make a deep copy before this returns.
virtual bool OnCapsule(const Capsule& capsule) = 0;
virtual void OnCapsuleParseFailure(const std::string& error_message) = 0;
};
// |visitor| must be non-null, and must outlive CapsuleParser.
explicit CapsuleParser(Visitor* visitor);
// Ingests a capsule fragment (any fragment of bytes from the capsule data
// stream) and parses and complete capsules it encounters. Returns false if a
// parsing error occurred.
bool IngestCapsuleFragment(absl::string_view capsule_fragment);
void ErrorIfThereIsRemainingBufferedData();
friend class test::CapsuleParserPeer;
private:
// Attempts to parse a single capsule from |buffered_data_|. If a full capsule
// is not available, returns 0. If a parsing error occurs, returns 0.
// Otherwise, returns the number of bytes in the parsed capsule.
size_t AttemptParseCapsule();
void ReportParseFailure(const std::string& error_message);
// Whether a parsing error has occurred.
bool parsing_error_occurred_ = false;
// Visitor which will receive callbacks, unowned.
Visitor* visitor_;
std::string buffered_data_;
};
// Serializes |capsule| into a newly allocated buffer.
QUIC_EXPORT_PRIVATE quiche::QuicheBuffer SerializeCapsule(
const Capsule& capsule, quiche::QuicheBufferAllocator* allocator);
} // namespace quic
#endif // QUICHE_QUIC_CORE_HTTP_CAPSULE_H_