|
|
|
@ -22,9 +22,7 @@ |
|
|
|
|
#include <grpc/support/port_platform.h> |
|
|
|
|
|
|
|
|
|
#include <stdlib.h> |
|
|
|
|
#include <string.h> |
|
|
|
|
|
|
|
|
|
#include <algorithm> |
|
|
|
|
#include <cstdint> |
|
|
|
|
#include <string> |
|
|
|
|
#include <type_traits> |
|
|
|
@ -33,9 +31,7 @@ |
|
|
|
|
#include "absl/container/inlined_vector.h" |
|
|
|
|
#include "absl/functional/function_ref.h" |
|
|
|
|
#include "absl/meta/type_traits.h" |
|
|
|
|
#include "absl/strings/match.h" |
|
|
|
|
#include "absl/strings/numbers.h" |
|
|
|
|
#include "absl/strings/str_cat.h" |
|
|
|
|
#include "absl/strings/string_view.h" |
|
|
|
|
#include "absl/types/optional.h" |
|
|
|
|
|
|
|
|
@ -47,11 +43,9 @@ |
|
|
|
|
#include "src/core/lib/gprpp/chunked_vector.h" |
|
|
|
|
#include "src/core/lib/gprpp/table.h" |
|
|
|
|
#include "src/core/lib/gprpp/time.h" |
|
|
|
|
#include "src/core/lib/iomgr/exec_ctx.h" |
|
|
|
|
#include "src/core/lib/resource_quota/arena.h" |
|
|
|
|
#include "src/core/lib/slice/slice.h" |
|
|
|
|
#include "src/core/lib/transport/parsed_metadata.h" |
|
|
|
|
#include "src/core/lib/transport/timeout_encoding.h" |
|
|
|
|
|
|
|
|
|
namespace grpc_core { |
|
|
|
|
|
|
|
|
@ -67,23 +61,9 @@ struct GrpcTimeoutMetadata { |
|
|
|
|
using ValueType = Timestamp; |
|
|
|
|
using MementoType = Duration; |
|
|
|
|
static absl::string_view key() { return "grpc-timeout"; } |
|
|
|
|
static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error) { |
|
|
|
|
auto timeout = ParseTimeout(value); |
|
|
|
|
if (!timeout.has_value()) { |
|
|
|
|
on_error("invalid value", value); |
|
|
|
|
return Duration::Infinity(); |
|
|
|
|
} |
|
|
|
|
return *timeout; |
|
|
|
|
} |
|
|
|
|
static ValueType MementoToValue(MementoType timeout) { |
|
|
|
|
if (timeout == Duration::Infinity()) { |
|
|
|
|
return Timestamp::InfFuture(); |
|
|
|
|
} |
|
|
|
|
return ExecCtx::Get()->Now() + timeout; |
|
|
|
|
} |
|
|
|
|
static Slice Encode(ValueType x) { |
|
|
|
|
return Timeout::FromDuration(x - ExecCtx::Get()->Now()).Encode(); |
|
|
|
|
} |
|
|
|
|
static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error); |
|
|
|
|
static ValueType MementoToValue(MementoType timeout); |
|
|
|
|
static Slice Encode(ValueType x); |
|
|
|
|
static std::string DisplayValue(MementoType x) { return x.ToString(); } |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
@ -99,28 +79,13 @@ struct TeMetadata { |
|
|
|
|
}; |
|
|
|
|
using MementoType = ValueType; |
|
|
|
|
static absl::string_view key() { return "te"; } |
|
|
|
|
static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error) { |
|
|
|
|
auto out = kInvalid; |
|
|
|
|
if (value == "trailers") { |
|
|
|
|
out = kTrailers; |
|
|
|
|
} else { |
|
|
|
|
on_error("invalid value", value); |
|
|
|
|
} |
|
|
|
|
return out; |
|
|
|
|
} |
|
|
|
|
static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error); |
|
|
|
|
static ValueType MementoToValue(MementoType te) { return te; } |
|
|
|
|
static StaticSlice Encode(ValueType x) { |
|
|
|
|
GPR_ASSERT(x == kTrailers); |
|
|
|
|
return StaticSlice::FromStaticString("trailers"); |
|
|
|
|
} |
|
|
|
|
static const char* DisplayValue(MementoType te) { |
|
|
|
|
switch (te) { |
|
|
|
|
case ValueType::kTrailers: |
|
|
|
|
return "trailers"; |
|
|
|
|
default: |
|
|
|
|
return "<discarded-invalid-value>"; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
static const char* DisplayValue(MementoType te); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// content-type metadata trait.
|
|
|
|
@ -136,47 +101,13 @@ struct ContentTypeMetadata { |
|
|
|
|
}; |
|
|
|
|
using MementoType = ValueType; |
|
|
|
|
static absl::string_view key() { return "content-type"; } |
|
|
|
|
static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error) { |
|
|
|
|
auto out = kInvalid; |
|
|
|
|
auto value_string = value.as_string_view(); |
|
|
|
|
if (value_string == "application/grpc") { |
|
|
|
|
out = kApplicationGrpc; |
|
|
|
|
} else if (absl::StartsWith(value_string, "application/grpc;")) { |
|
|
|
|
out = kApplicationGrpc; |
|
|
|
|
} else if (absl::StartsWith(value_string, "application/grpc+")) { |
|
|
|
|
out = kApplicationGrpc; |
|
|
|
|
} else if (value_string.empty()) { |
|
|
|
|
out = kEmpty; |
|
|
|
|
} else { |
|
|
|
|
on_error("invalid value", value); |
|
|
|
|
} |
|
|
|
|
return out; |
|
|
|
|
} |
|
|
|
|
static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error); |
|
|
|
|
static ValueType MementoToValue(MementoType content_type) { |
|
|
|
|
return content_type; |
|
|
|
|
} |
|
|
|
|
static StaticSlice Encode(ValueType x) { |
|
|
|
|
switch (x) { |
|
|
|
|
case kEmpty: |
|
|
|
|
return StaticSlice::FromStaticString(""); |
|
|
|
|
case kApplicationGrpc: |
|
|
|
|
return StaticSlice::FromStaticString("application/grpc"); |
|
|
|
|
case kInvalid: |
|
|
|
|
return StaticSlice::FromStaticString("application/grpc+unknown"); |
|
|
|
|
} |
|
|
|
|
GPR_UNREACHABLE_CODE( |
|
|
|
|
return StaticSlice::FromStaticString("unrepresentable value")); |
|
|
|
|
} |
|
|
|
|
static const char* DisplayValue(MementoType content_type) { |
|
|
|
|
switch (content_type) { |
|
|
|
|
case ValueType::kApplicationGrpc: |
|
|
|
|
return "application/grpc"; |
|
|
|
|
case ValueType::kEmpty: |
|
|
|
|
return ""; |
|
|
|
|
default: |
|
|
|
|
return "<discarded-invalid-value>"; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static StaticSlice Encode(ValueType x); |
|
|
|
|
static const char* DisplayValue(MementoType content_type); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// scheme metadata trait.
|
|
|
|
@ -193,38 +124,12 @@ struct HttpSchemeMetadata { |
|
|
|
|
return Parse(value.as_string_view(), on_error); |
|
|
|
|
} |
|
|
|
|
static ValueType Parse(absl::string_view value, |
|
|
|
|
MetadataParseErrorFn on_error) { |
|
|
|
|
if (value == "http") { |
|
|
|
|
return kHttp; |
|
|
|
|
} else if (value == "https") { |
|
|
|
|
return kHttps; |
|
|
|
|
} |
|
|
|
|
on_error("invalid value", Slice::FromCopiedBuffer(value)); |
|
|
|
|
return kInvalid; |
|
|
|
|
} |
|
|
|
|
MetadataParseErrorFn on_error); |
|
|
|
|
static ValueType MementoToValue(MementoType content_type) { |
|
|
|
|
return content_type; |
|
|
|
|
} |
|
|
|
|
static StaticSlice Encode(ValueType x) { |
|
|
|
|
switch (x) { |
|
|
|
|
case kHttp: |
|
|
|
|
return StaticSlice::FromStaticString("http"); |
|
|
|
|
case kHttps: |
|
|
|
|
return StaticSlice::FromStaticString("https"); |
|
|
|
|
default: |
|
|
|
|
abort(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
static const char* DisplayValue(MementoType content_type) { |
|
|
|
|
switch (content_type) { |
|
|
|
|
case kHttp: |
|
|
|
|
return "http"; |
|
|
|
|
case kHttps: |
|
|
|
|
return "https"; |
|
|
|
|
default: |
|
|
|
|
return "<discarded-invalid-value>"; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
static StaticSlice Encode(ValueType x); |
|
|
|
|
static const char* DisplayValue(MementoType content_type); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// method metadata trait.
|
|
|
|
@ -238,47 +143,12 @@ struct HttpMethodMetadata { |
|
|
|
|
}; |
|
|
|
|
using MementoType = ValueType; |
|
|
|
|
static absl::string_view key() { return ":method"; } |
|
|
|
|
static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error) { |
|
|
|
|
auto out = kInvalid; |
|
|
|
|
auto value_string = value.as_string_view(); |
|
|
|
|
if (value_string == "POST") { |
|
|
|
|
out = kPost; |
|
|
|
|
} else if (value_string == "PUT") { |
|
|
|
|
out = kPut; |
|
|
|
|
} else if (value_string == "GET") { |
|
|
|
|
out = kGet; |
|
|
|
|
} else { |
|
|
|
|
on_error("invalid value", value); |
|
|
|
|
} |
|
|
|
|
return out; |
|
|
|
|
} |
|
|
|
|
static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error); |
|
|
|
|
static ValueType MementoToValue(MementoType content_type) { |
|
|
|
|
return content_type; |
|
|
|
|
} |
|
|
|
|
static StaticSlice Encode(ValueType x) { |
|
|
|
|
switch (x) { |
|
|
|
|
case kPost: |
|
|
|
|
return StaticSlice::FromStaticString("POST"); |
|
|
|
|
case kPut: |
|
|
|
|
return StaticSlice::FromStaticString("PUT"); |
|
|
|
|
case kGet: |
|
|
|
|
return StaticSlice::FromStaticString("GET"); |
|
|
|
|
default: |
|
|
|
|
abort(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
static const char* DisplayValue(MementoType content_type) { |
|
|
|
|
switch (content_type) { |
|
|
|
|
case kPost: |
|
|
|
|
return "POST"; |
|
|
|
|
case kGet: |
|
|
|
|
return "GET"; |
|
|
|
|
case kPut: |
|
|
|
|
return "PUT"; |
|
|
|
|
default: |
|
|
|
|
return "<discarded-invalid-value>"; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
static StaticSlice Encode(ValueType x); |
|
|
|
|
static const char* DisplayValue(MementoType content_type); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// Base type for metadata pertaining to a single compression algorithm
|
|
|
|
@ -286,14 +156,7 @@ struct HttpMethodMetadata { |
|
|
|
|
struct CompressionAlgorithmBasedMetadata { |
|
|
|
|
using ValueType = grpc_compression_algorithm; |
|
|
|
|
using MementoType = ValueType; |
|
|
|
|
static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error) { |
|
|
|
|
auto algorithm = ParseCompressionAlgorithm(value.as_string_view()); |
|
|
|
|
if (!algorithm.has_value()) { |
|
|
|
|
on_error("invalid value", value); |
|
|
|
|
return GRPC_COMPRESS_NONE; |
|
|
|
|
} |
|
|
|
|
return *algorithm; |
|
|
|
|
} |
|
|
|
|
static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error); |
|
|
|
|
static ValueType MementoToValue(MementoType x) { return x; } |
|
|
|
|
static Slice Encode(ValueType x) { |
|
|
|
|
GPR_ASSERT(x != GRPC_COMPRESS_ALGORITHMS_COUNT); |
|
|
|
@ -401,9 +264,9 @@ struct HttpPathMetadata : public SimpleSliceBasedMetadata { |
|
|
|
|
static absl::string_view key() { return ":path"; } |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// We separate SimpleIntBasedMetadata into two pieces: one that does not depend
|
|
|
|
|
// on the invalid value, and one that does. This allows the compiler to easily
|
|
|
|
|
// see the functions that are shared, and helps reduce code bloat here.
|
|
|
|
|
// We separate SimpleIntBasedMetadata into two pieces: one that does not
|
|
|
|
|
// depend on the invalid value, and one that does. This allows the compiler to
|
|
|
|
|
// easily see the functions that are shared, and helps reduce code bloat here.
|
|
|
|
|
template <typename Int> |
|
|
|
|
struct SimpleIntBasedMetadataBase { |
|
|
|
|
using ValueType = Int; |
|
|
|
@ -449,14 +312,7 @@ struct GrpcRetryPushbackMsMetadata { |
|
|
|
|
static ValueType MementoToValue(MementoType x) { return x; } |
|
|
|
|
static Slice Encode(Duration x) { return Slice::FromInt64(x.millis()); } |
|
|
|
|
static int64_t DisplayValue(Duration x) { return x.millis(); } |
|
|
|
|
static Duration ParseMemento(Slice value, MetadataParseErrorFn on_error) { |
|
|
|
|
int64_t out; |
|
|
|
|
if (!absl::SimpleAtoi(value.as_string_view(), &out)) { |
|
|
|
|
on_error("not an integer", value); |
|
|
|
|
return Duration::NegativeInfinity(); |
|
|
|
|
} |
|
|
|
|
return Duration::Milliseconds(out); |
|
|
|
|
} |
|
|
|
|
static Duration ParseMemento(Slice value, MetadataParseErrorFn on_error); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// :status metadata trait.
|
|
|
|
@ -499,28 +355,9 @@ struct LbCostBinMetadata { |
|
|
|
|
}; |
|
|
|
|
using MementoType = ValueType; |
|
|
|
|
static ValueType MementoToValue(MementoType value) { return value; } |
|
|
|
|
static Slice Encode(const ValueType& x) { |
|
|
|
|
auto slice = |
|
|
|
|
MutableSlice::CreateUninitialized(sizeof(double) + x.name.length()); |
|
|
|
|
memcpy(slice.data(), &x.cost, sizeof(double)); |
|
|
|
|
memcpy(slice.data() + sizeof(double), x.name.data(), x.name.length()); |
|
|
|
|
return Slice(std::move(slice)); |
|
|
|
|
} |
|
|
|
|
static std::string DisplayValue(MementoType x) { |
|
|
|
|
return absl::StrCat(x.name, ":", x.cost); |
|
|
|
|
} |
|
|
|
|
static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error) { |
|
|
|
|
if (value.length() < sizeof(double)) { |
|
|
|
|
on_error("too short", value); |
|
|
|
|
return {0, ""}; |
|
|
|
|
} |
|
|
|
|
MementoType out; |
|
|
|
|
memcpy(&out.cost, value.data(), sizeof(double)); |
|
|
|
|
out.name = std::string( |
|
|
|
|
reinterpret_cast<const char*>(value.data()) + sizeof(double), |
|
|
|
|
value.length() - sizeof(double)); |
|
|
|
|
return out; |
|
|
|
|
} |
|
|
|
|
static Slice Encode(const ValueType& x); |
|
|
|
|
static std::string DisplayValue(MementoType x); |
|
|
|
|
static MementoType ParseMemento(Slice value, MetadataParseErrorFn on_error); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// Annotation added by a transport to note whether a failed request was never
|
|
|
|
@ -532,14 +369,7 @@ struct GrpcStreamNetworkState { |
|
|
|
|
kNotSentOnWire, |
|
|
|
|
kNotSeenByServer, |
|
|
|
|
}; |
|
|
|
|
static std::string DisplayValue(ValueType x) { |
|
|
|
|
switch (x) { |
|
|
|
|
case kNotSentOnWire: |
|
|
|
|
return "not sent on wire"; |
|
|
|
|
case kNotSeenByServer: |
|
|
|
|
return "not seen by server"; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
static std::string DisplayValue(ValueType x); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// Annotation added by a server transport to note the peer making a request.
|
|
|
|
@ -547,7 +377,7 @@ struct PeerString { |
|
|
|
|
static absl::string_view DebugKey() { return "PeerString"; } |
|
|
|
|
static constexpr bool kRepeatable = false; |
|
|
|
|
using ValueType = absl::string_view; |
|
|
|
|
static std::string DisplayValue(ValueType x) { return std::string(x); } |
|
|
|
|
static std::string DisplayValue(ValueType x); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// Annotation added by various systems to describe the reason for a failure.
|
|
|
|
@ -555,7 +385,7 @@ struct GrpcStatusContext { |
|
|
|
|
static absl::string_view DebugKey() { return "GrpcStatusContext"; } |
|
|
|
|
static constexpr bool kRepeatable = true; |
|
|
|
|
using ValueType = std::string; |
|
|
|
|
static const std::string& DisplayValue(const std::string& x) { return x; } |
|
|
|
|
static const std::string& DisplayValue(const std::string& x); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
namespace metadata_detail { |
|
|
|
@ -576,11 +406,10 @@ class DebugStringBuilder { |
|
|
|
|
std::string out_; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// IsEncodable: Given a trait, determine if that trait is encodable, or is just
|
|
|
|
|
// a value attached to a MetadataMap.
|
|
|
|
|
// We use the presence of the key() static method to determine if a trait is
|
|
|
|
|
// encodable or not - encodable traits have string names, and non-encodable
|
|
|
|
|
// traits do not.
|
|
|
|
|
// IsEncodable: Given a trait, determine if that trait is encodable, or is
|
|
|
|
|
// just a value attached to a MetadataMap. We use the presence of the key()
|
|
|
|
|
// static method to determine if a trait is encodable or not - encodable
|
|
|
|
|
// traits have string names, and non-encodable traits do not.
|
|
|
|
|
template <typename Trait, typename Ignored = void> |
|
|
|
|
struct IsEncodableTrait { |
|
|
|
|
static const bool value = false; |
|
|
|
@ -630,8 +459,8 @@ struct NameLookup<void> { |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// Helper to take a slice to a memento to a value.
|
|
|
|
|
// By splitting this part out we can scale code size as the number of (memento,
|
|
|
|
|
// value) types, rather than as the number of traits.
|
|
|
|
|
// By splitting this part out we can scale code size as the number of
|
|
|
|
|
// (memento, value) types, rather than as the number of traits.
|
|
|
|
|
template <typename ParseMementoFn, typename MementoToValueFn> |
|
|
|
|
struct ParseValue { |
|
|
|
|
template <ParseMementoFn parse_memento, MementoToValueFn memento_to_value> |
|
|
|
@ -680,8 +509,8 @@ class ParseHelper { |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// This is an "Op" type for NameLookup.
|
|
|
|
|
// Used for MetadataMap::Append, its Found/NotFound methods turn a slice into a
|
|
|
|
|
// value and add it to a container.
|
|
|
|
|
// Used for MetadataMap::Append, its Found/NotFound methods turn a slice into
|
|
|
|
|
// a value and add it to a container.
|
|
|
|
|
template <typename Container> |
|
|
|
|
class AppendHelper { |
|
|
|
|
public: |
|
|
|
@ -698,7 +527,7 @@ class AppendHelper { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
GPR_ATTRIBUTE_NOINLINE void NotFound(absl::string_view key) { |
|
|
|
|
container_->AppendUnknown(key, std::move(value_)); |
|
|
|
|
container_->unknown_.Append(key, std::move(value_)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
@ -721,7 +550,7 @@ class RemoveHelper { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
GPR_ATTRIBUTE_NOINLINE void NotFound(absl::string_view key) { |
|
|
|
|
container_->RemoveUnknown(key); |
|
|
|
|
container_->unknown_.Remove(key); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
@ -729,8 +558,8 @@ class RemoveHelper { |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// This is an "Op" type for NameLookup.
|
|
|
|
|
// Used for MetadataMap::GetStringValue, its Found/NotFound methods generated a
|
|
|
|
|
// string value from the container.
|
|
|
|
|
// Used for MetadataMap::GetStringValue, its Found/NotFound methods generated
|
|
|
|
|
// a string value from the container.
|
|
|
|
|
template <typename Container> |
|
|
|
|
class GetStringValueHelper { |
|
|
|
|
public: |
|
|
|
@ -780,7 +609,7 @@ class GetStringValueHelper { |
|
|
|
|
|
|
|
|
|
GPR_ATTRIBUTE_NOINLINE absl::optional<absl::string_view> NotFound( |
|
|
|
|
absl::string_view key) { |
|
|
|
|
return container_->GetStringValueUnknown(key, backing_); |
|
|
|
|
return container_->unknown_.GetStringValue(key, backing_); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
@ -793,7 +622,17 @@ using LogFn = absl::FunctionRef<void(absl::string_view, absl::string_view)>; |
|
|
|
|
|
|
|
|
|
template <typename T> |
|
|
|
|
struct AdaptDisplayValueToLog { |
|
|
|
|
static std::string ToString(const T& value) { return absl::StrCat(value); } |
|
|
|
|
static std::string ToString(const T& value) { return std::to_string(value); } |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
template <> |
|
|
|
|
struct AdaptDisplayValueToLog<std::string> { |
|
|
|
|
static std::string ToString(const std::string& value) { return value; } |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
template <> |
|
|
|
|
struct AdaptDisplayValueToLog<const std::string&> { |
|
|
|
|
static std::string ToString(const std::string& value) { return value; } |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
template <> |
|
|
|
@ -949,7 +788,7 @@ class CopySink { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void Encode(const Slice& key, const Slice& value) { |
|
|
|
|
dst_->AppendUnknown(key.as_string_view(), value.Ref()); |
|
|
|
|
dst_->unknown_.Append(key.as_string_view(), value.Ref()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
@ -1005,6 +844,31 @@ class TransportSizeEncoder { |
|
|
|
|
uint32_t size_ = 0; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// Handle unknown (non-trait-based) fields in the metadata map.
|
|
|
|
|
class UnknownMap { |
|
|
|
|
public: |
|
|
|
|
explicit UnknownMap(Arena* arena) : unknown_(arena) {} |
|
|
|
|
|
|
|
|
|
using BackingType = ChunkedVector<std::pair<Slice, Slice>, 10>; |
|
|
|
|
|
|
|
|
|
void Append(absl::string_view key, Slice value); |
|
|
|
|
void Remove(absl::string_view key); |
|
|
|
|
absl::optional<absl::string_view> GetStringValue(absl::string_view key, |
|
|
|
|
std::string* backing) const; |
|
|
|
|
|
|
|
|
|
BackingType::ConstForwardIterator begin() const { return unknown_.cbegin(); } |
|
|
|
|
BackingType::ConstForwardIterator end() const { return unknown_.cend(); } |
|
|
|
|
|
|
|
|
|
bool empty() const { return unknown_.empty(); } |
|
|
|
|
size_t size() const { return unknown_.size(); } |
|
|
|
|
void Clear() { unknown_.Clear(); } |
|
|
|
|
Arena* arena() const { return unknown_.arena(); } |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
// Backing store for added metadata.
|
|
|
|
|
ChunkedVector<std::pair<Slice, Slice>, 10> unknown_; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
} // namespace metadata_detail
|
|
|
|
|
|
|
|
|
|
// Helper function for encoders
|
|
|
|
@ -1065,21 +929,23 @@ MetadataValueAsSlice(typename Which::ValueType value) { |
|
|
|
|
// // Parse a memento from a slice
|
|
|
|
|
// // Takes ownership of value
|
|
|
|
|
// // Calls fn in the case of an error that should be reported to the user
|
|
|
|
|
// static MementoType ParseMemento(Slice value, MementoParseErrorFn fn) { ...
|
|
|
|
|
// static MementoType ParseMemento(Slice value, MementoParseErrorFn fn) {
|
|
|
|
|
// ...
|
|
|
|
|
// }
|
|
|
|
|
// // Convert a memento to a value
|
|
|
|
|
// static ValueType MementoToValue(MementoType memento) { ... }
|
|
|
|
|
// // Convert a value to its canonical text wire format (the format that
|
|
|
|
|
// // ParseMemento will accept!)
|
|
|
|
|
// static Slice Encode(const ValueType& value);
|
|
|
|
|
// // Convert a value to something that can be passed to StrCat and displayed
|
|
|
|
|
// // Convert a value to something that can be passed to StrCat and
|
|
|
|
|
// displayed
|
|
|
|
|
// // for debugging
|
|
|
|
|
// static SomeStrCatableType DisplayValue(MementoType value) { ... }
|
|
|
|
|
// };
|
|
|
|
|
//
|
|
|
|
|
// Non-encodable traits are determined by missing the key() method, and have the
|
|
|
|
|
// following signature (and by convention omit the Metadata part of the type
|
|
|
|
|
// name):
|
|
|
|
|
// Non-encodable traits are determined by missing the key() method, and have
|
|
|
|
|
// the following signature (and by convention omit the Metadata part of the
|
|
|
|
|
// type name):
|
|
|
|
|
// // Traits for the GrpcXyz field:
|
|
|
|
|
// struct GrpcXyz {
|
|
|
|
|
// // The string key that should be used for debug dumps - should not be a
|
|
|
|
@ -1089,7 +955,8 @@ MetadataValueAsSlice(typename Which::ValueType value) { |
|
|
|
|
// static constexpr bool kRepeatable = ...;
|
|
|
|
|
// // The type that's stored on MetadataBatch
|
|
|
|
|
// using ValueType = ...;
|
|
|
|
|
// // Convert a value to something that can be passed to StrCat and displayed
|
|
|
|
|
// // Convert a value to something that can be passed to StrCat and
|
|
|
|
|
// displayed
|
|
|
|
|
// // for debugging
|
|
|
|
|
// static SomeStrCatableType DisplayValue(ValueType value) { ... }
|
|
|
|
|
// };
|
|
|
|
@ -1102,10 +969,10 @@ MetadataValueAsSlice(typename Which::ValueType value) { |
|
|
|
|
// in the compression table. This is what mementos are used for.
|
|
|
|
|
//
|
|
|
|
|
// A trait offers the capability to turn a slice into a memento via
|
|
|
|
|
// ParseMemento. This is exposed to users of MetadataMap via the Parse() method,
|
|
|
|
|
// that returns a ParsedMetadata object. That ParsedMetadata object can in turn
|
|
|
|
|
// be used to set the same value on many different MetadataMaps without having
|
|
|
|
|
// to reparse.
|
|
|
|
|
// ParseMemento. This is exposed to users of MetadataMap via the Parse()
|
|
|
|
|
// method, that returns a ParsedMetadata object. That ParsedMetadata object
|
|
|
|
|
// can in turn be used to set the same value on many different MetadataMaps
|
|
|
|
|
// without having to reparse.
|
|
|
|
|
//
|
|
|
|
|
// Implementation wise, ParsedMetadata is a type erased wrapper around
|
|
|
|
|
// MementoType. When we set a value on MetadataMap, we first turn that memento
|
|
|
|
@ -1309,36 +1176,9 @@ class MetadataMap { |
|
|
|
|
template <typename Which> |
|
|
|
|
using Value = metadata_detail::Value<Which>; |
|
|
|
|
|
|
|
|
|
void AppendUnknown(absl::string_view key, Slice value) { |
|
|
|
|
unknown_.EmplaceBack(Slice::FromCopiedString(key), value.Ref()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void RemoveUnknown(absl::string_view key) { |
|
|
|
|
unknown_.SetEnd(std::remove_if(unknown_.begin(), unknown_.end(), |
|
|
|
|
[key](const std::pair<Slice, Slice>& p) { |
|
|
|
|
return p.first.as_string_view() == key; |
|
|
|
|
})); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
absl::optional<absl::string_view> GetStringValueUnknown( |
|
|
|
|
absl::string_view key, std::string* backing) const { |
|
|
|
|
absl::optional<absl::string_view> out; |
|
|
|
|
for (const auto& p : unknown_) { |
|
|
|
|
if (p.first.as_string_view() == key) { |
|
|
|
|
if (!out.has_value()) { |
|
|
|
|
out = p.second.as_string_view(); |
|
|
|
|
} else { |
|
|
|
|
out = *backing = absl::StrCat(*out, ",", p.second.as_string_view()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return out; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Table of known metadata types.
|
|
|
|
|
Table<Value<Traits>...> table_; |
|
|
|
|
// Backing store for added metadata.
|
|
|
|
|
ChunkedVector<std::pair<Slice, Slice>, 10> unknown_; |
|
|
|
|
metadata_detail::UnknownMap unknown_; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// Ok/not-ok check for metadata maps that contain GrpcStatusMetadata, so that
|
|
|
|
@ -1356,8 +1196,8 @@ template <typename Derived, typename... Traits> |
|
|
|
|
MetadataMap<Derived, Traits...>::MetadataMap(MetadataMap&& other) noexcept |
|
|
|
|
: table_(std::move(other.table_)), unknown_(std::move(other.unknown_)) {} |
|
|
|
|
|
|
|
|
|
// We never create MetadataMap directly, instead we create Derived, but we want
|
|
|
|
|
// to be able to move it without redeclaring this.
|
|
|
|
|
// We never create MetadataMap directly, instead we create Derived, but we
|
|
|
|
|
// want to be able to move it without redeclaring this.
|
|
|
|
|
// NOLINTNEXTLINE(misc-unconventional-assign-operator)
|
|
|
|
|
template <typename Derived, typename... Traits> |
|
|
|
|
Derived& MetadataMap<Derived, Traits...>::operator=( |
|
|
|
|