1 // Copyright 2021 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <grpc/support/port_platform.h>
16
17 #include "src/core/lib/transport/metadata_batch.h"
18
19 #include <string.h>
20
21 #include <algorithm>
22 #include <string>
23
24 #include "absl/base/no_destructor.h"
25 #include "absl/container/flat_hash_set.h"
26 #include "absl/strings/escaping.h"
27 #include "absl/strings/match.h"
28 #include "absl/strings/str_cat.h"
29 #include "absl/strings/str_format.h"
30
31 #include "src/core/lib/transport/timeout_encoding.h"
32
33 namespace grpc_core {
34 namespace metadata_detail {
35
Add(absl::string_view key,absl::string_view value)36 void DebugStringBuilder::Add(absl::string_view key, absl::string_view value) {
37 if (!out_.empty()) out_.append(", ");
38 absl::StrAppend(&out_, absl::CEscape(key), ": ", absl::CEscape(value));
39 }
40
AddAfterRedaction(absl::string_view key,absl::string_view value)41 void DebugStringBuilder::AddAfterRedaction(absl::string_view key,
42 absl::string_view value) {
43 if (IsAllowListed(key)) {
44 Add(key, value);
45 } else {
46 Add(key, absl::StrCat(value.size(), " bytes redacted by allow listing."));
47 }
48 }
49
IsAllowListed(const absl::string_view key) const50 bool DebugStringBuilder::IsAllowListed(const absl::string_view key) const {
51 static const absl::NoDestructor<absl::flat_hash_set<std::string>> allow_list(
52 [] {
53 absl::flat_hash_set<std::string> allow_list;
54 // go/keep-sorted start
55 allow_list.insert(std::string(ContentTypeMetadata::key()));
56 allow_list.insert(std::string(EndpointLoadMetricsBinMetadata::key()));
57 allow_list.insert(std::string(GrpcAcceptEncodingMetadata::key()));
58 allow_list.insert(std::string(GrpcEncodingMetadata::key()));
59 allow_list.insert(std::string(GrpcInternalEncodingRequest::key()));
60 allow_list.insert(std::string(GrpcLbClientStatsMetadata::key()));
61 allow_list.insert(std::string(GrpcMessageMetadata::key()));
62 allow_list.insert(std::string(GrpcPreviousRpcAttemptsMetadata::key()));
63 allow_list.insert(std::string(GrpcRetryPushbackMsMetadata::key()));
64 allow_list.insert(std::string(GrpcServerStatsBinMetadata::key()));
65 allow_list.insert(std::string(GrpcStatusMetadata::key()));
66 allow_list.insert(std::string(GrpcTagsBinMetadata::key()));
67 allow_list.insert(std::string(GrpcTimeoutMetadata::key()));
68 allow_list.insert(std::string(GrpcTraceBinMetadata::key()));
69 allow_list.insert(std::string(HostMetadata::key()));
70 allow_list.insert(std::string(HttpAuthorityMetadata::key()));
71 allow_list.insert(std::string(HttpMethodMetadata::key()));
72 allow_list.insert(std::string(HttpPathMetadata::key()));
73 allow_list.insert(std::string(HttpSchemeMetadata::key()));
74 allow_list.insert(std::string(HttpStatusMetadata::key()));
75 allow_list.insert(std::string(LbCostBinMetadata::key()));
76 allow_list.insert(std::string(LbTokenMetadata::key()));
77 allow_list.insert(std::string(TeMetadata::key()));
78 allow_list.insert(std::string(UserAgentMetadata::key()));
79 allow_list.insert(std::string(XEnvoyPeerMetadata::key()));
80
81 // go/keep-sorted end
82 // go/keep-sorted start
83 allow_list.insert(std::string(GrpcCallWasCancelled::DebugKey()));
84 allow_list.insert(std::string(GrpcRegisteredMethod::DebugKey()));
85 allow_list.insert(std::string(GrpcStatusContext::DebugKey()));
86 allow_list.insert(std::string(GrpcStatusFromWire::DebugKey()));
87 allow_list.insert(std::string(GrpcStreamNetworkState::DebugKey()));
88 allow_list.insert(std::string(GrpcTarPit::DebugKey()));
89 allow_list.insert(std::string(GrpcTrailersOnly::DebugKey()));
90 allow_list.insert(std::string(PeerString::DebugKey()));
91 allow_list.insert(std::string(WaitForReady::DebugKey()));
92 // go/keep-sorted end
93 return allow_list;
94 }());
95 return allow_list->contains(key);
96 }
97
Append(absl::string_view key,Slice value)98 void UnknownMap::Append(absl::string_view key, Slice value) {
99 unknown_.emplace_back(Slice::FromCopiedString(key), value.Ref());
100 }
101
Remove(absl::string_view key)102 void UnknownMap::Remove(absl::string_view key) {
103 unknown_.erase(std::remove_if(unknown_.begin(), unknown_.end(),
104 [key](const std::pair<Slice, Slice>& p) {
105 return p.first.as_string_view() == key;
106 }),
107 unknown_.end());
108 }
109
GetStringValue(absl::string_view key,std::string * backing) const110 absl::optional<absl::string_view> UnknownMap::GetStringValue(
111 absl::string_view key, std::string* backing) const {
112 absl::optional<absl::string_view> out;
113 for (const auto& p : unknown_) {
114 if (p.first.as_string_view() == key) {
115 if (!out.has_value()) {
116 out = p.second.as_string_view();
117 } else {
118 out = *backing = absl::StrCat(*out, ",", p.second.as_string_view());
119 }
120 }
121 }
122 return out;
123 }
124
125 } // namespace metadata_detail
126
ParseMemento(Slice value,bool,MetadataParseErrorFn)127 ContentTypeMetadata::MementoType ContentTypeMetadata::ParseMemento(
128 Slice value, bool, MetadataParseErrorFn /*on_error*/) {
129 auto out = kInvalid;
130 auto value_string = value.as_string_view();
131 if (value_string == "application/grpc") {
132 out = kApplicationGrpc;
133 } else if (absl::StartsWith(value_string, "application/grpc;")) {
134 out = kApplicationGrpc;
135 } else if (absl::StartsWith(value_string, "application/grpc+")) {
136 out = kApplicationGrpc;
137 } else if (value_string.empty()) {
138 out = kEmpty;
139 } else {
140 // We are intentionally not invoking on_error here since the spec is not
141 // clear on what the behavior should be here, so to avoid breaking anyone,
142 // we should continue to accept this.
143 }
144 return out;
145 }
146
Encode(ValueType x)147 StaticSlice ContentTypeMetadata::Encode(ValueType x) {
148 switch (x) {
149 case kEmpty:
150 return StaticSlice::FromStaticString("");
151 case kApplicationGrpc:
152 return StaticSlice::FromStaticString("application/grpc");
153 case kInvalid:
154 return StaticSlice::FromStaticString("application/grpc+unknown");
155 }
156 GPR_UNREACHABLE_CODE(
157 return StaticSlice::FromStaticString("unrepresentable value"));
158 }
159
DisplayValue(ValueType content_type)160 const char* ContentTypeMetadata::DisplayValue(ValueType content_type) {
161 switch (content_type) {
162 case ValueType::kApplicationGrpc:
163 return "application/grpc";
164 case ValueType::kEmpty:
165 return "";
166 default:
167 return "<discarded-invalid-value>";
168 }
169 }
170
ParseMemento(Slice value,bool,MetadataParseErrorFn on_error)171 GrpcTimeoutMetadata::MementoType GrpcTimeoutMetadata::ParseMemento(
172 Slice value, bool, MetadataParseErrorFn on_error) {
173 auto timeout = ParseTimeout(value);
174 if (!timeout.has_value()) {
175 on_error("invalid value", value);
176 return Duration::Infinity();
177 }
178 return *timeout;
179 }
180
MementoToValue(MementoType timeout)181 GrpcTimeoutMetadata::ValueType GrpcTimeoutMetadata::MementoToValue(
182 MementoType timeout) {
183 if (timeout == Duration::Infinity()) {
184 return Timestamp::InfFuture();
185 }
186 return Timestamp::Now() + timeout;
187 }
188
Encode(ValueType x)189 Slice GrpcTimeoutMetadata::Encode(ValueType x) {
190 return Timeout::FromDuration(x - Timestamp::Now()).Encode();
191 }
192
ParseMemento(Slice value,bool,MetadataParseErrorFn on_error)193 TeMetadata::MementoType TeMetadata::ParseMemento(
194 Slice value, bool, MetadataParseErrorFn on_error) {
195 auto out = kInvalid;
196 if (value == "trailers") {
197 out = kTrailers;
198 } else {
199 on_error("invalid value", value);
200 }
201 return out;
202 }
203
DisplayValue(ValueType te)204 const char* TeMetadata::DisplayValue(ValueType te) {
205 switch (te) {
206 case ValueType::kTrailers:
207 return "trailers";
208 default:
209 return "<discarded-invalid-value>";
210 }
211 }
212
Parse(absl::string_view value,MetadataParseErrorFn on_error)213 HttpSchemeMetadata::ValueType HttpSchemeMetadata::Parse(
214 absl::string_view value, MetadataParseErrorFn on_error) {
215 if (value == "http") {
216 return kHttp;
217 } else if (value == "https") {
218 return kHttps;
219 }
220 on_error("invalid value", Slice::FromCopiedBuffer(value));
221 return kInvalid;
222 }
223
Encode(ValueType x)224 StaticSlice HttpSchemeMetadata::Encode(ValueType x) {
225 switch (x) {
226 case kHttp:
227 return StaticSlice::FromStaticString("http");
228 case kHttps:
229 return StaticSlice::FromStaticString("https");
230 default:
231 abort();
232 }
233 }
234
EncodedSizeOfKey(HttpSchemeMetadata,HttpSchemeMetadata::ValueType x)235 size_t EncodedSizeOfKey(HttpSchemeMetadata, HttpSchemeMetadata::ValueType x) {
236 switch (x) {
237 case HttpSchemeMetadata::kHttp:
238 return 4;
239 case HttpSchemeMetadata::kHttps:
240 return 5;
241 default:
242 return 0;
243 }
244 }
245
DisplayValue(ValueType content_type)246 const char* HttpSchemeMetadata::DisplayValue(ValueType content_type) {
247 switch (content_type) {
248 case kHttp:
249 return "http";
250 case kHttps:
251 return "https";
252 default:
253 return "<discarded-invalid-value>";
254 }
255 }
256
ParseMemento(Slice value,bool,MetadataParseErrorFn on_error)257 HttpMethodMetadata::MementoType HttpMethodMetadata::ParseMemento(
258 Slice value, bool, MetadataParseErrorFn on_error) {
259 auto out = kInvalid;
260 auto value_string = value.as_string_view();
261 if (value_string == "POST") {
262 out = kPost;
263 } else if (value_string == "PUT") {
264 out = kPut;
265 } else if (value_string == "GET") {
266 out = kGet;
267 } else {
268 on_error("invalid value", value);
269 }
270 return out;
271 }
272
Encode(ValueType x)273 StaticSlice HttpMethodMetadata::Encode(ValueType x) {
274 switch (x) {
275 case kPost:
276 return StaticSlice::FromStaticString("POST");
277 case kPut:
278 return StaticSlice::FromStaticString("PUT");
279 case kGet:
280 return StaticSlice::FromStaticString("GET");
281 default:
282 // TODO(ctiller): this should be an abort, we should split up the debug
283 // string generation from the encode string generation so that debug
284 // strings can always succeed and encode strings can crash.
285 return StaticSlice::FromStaticString("<<INVALID METHOD>>");
286 }
287 }
288
DisplayValue(ValueType content_type)289 const char* HttpMethodMetadata::DisplayValue(ValueType content_type) {
290 switch (content_type) {
291 case kPost:
292 return "POST";
293 case kGet:
294 return "GET";
295 case kPut:
296 return "PUT";
297 default:
298 return "<discarded-invalid-value>";
299 }
300 }
301
302 CompressionAlgorithmBasedMetadata::MementoType
ParseMemento(Slice value,bool,MetadataParseErrorFn on_error)303 CompressionAlgorithmBasedMetadata::ParseMemento(Slice value, bool,
304 MetadataParseErrorFn on_error) {
305 auto algorithm = ParseCompressionAlgorithm(value.as_string_view());
306 if (!algorithm.has_value()) {
307 on_error("invalid value", value);
308 return GRPC_COMPRESS_NONE;
309 }
310 return *algorithm;
311 }
312
ParseMemento(Slice value,bool,MetadataParseErrorFn on_error)313 Duration GrpcRetryPushbackMsMetadata::ParseMemento(
314 Slice value, bool, MetadataParseErrorFn on_error) {
315 int64_t out;
316 if (!absl::SimpleAtoi(value.as_string_view(), &out)) {
317 on_error("not an integer", value);
318 return Duration::NegativeInfinity();
319 }
320 return Duration::Milliseconds(out);
321 }
322
Encode(const ValueType & x)323 Slice LbCostBinMetadata::Encode(const ValueType& x) {
324 auto slice =
325 MutableSlice::CreateUninitialized(sizeof(double) + x.name.length());
326 memcpy(slice.data(), &x.cost, sizeof(double));
327 memcpy(slice.data() + sizeof(double), x.name.data(), x.name.length());
328 return Slice(std::move(slice));
329 }
330
DisplayValue(ValueType x)331 std::string LbCostBinMetadata::DisplayValue(ValueType x) {
332 return absl::StrCat(x.name, ":", x.cost);
333 }
334
ParseMemento(Slice value,bool,MetadataParseErrorFn on_error)335 LbCostBinMetadata::MementoType LbCostBinMetadata::ParseMemento(
336 Slice value, bool, MetadataParseErrorFn on_error) {
337 if (value.length() < sizeof(double)) {
338 on_error("too short", value);
339 return {0, ""};
340 }
341 MementoType out;
342 memcpy(&out.cost, value.data(), sizeof(double));
343 out.name =
344 std::string(reinterpret_cast<const char*>(value.data()) + sizeof(double),
345 value.length() - sizeof(double));
346 return out;
347 }
348
DisplayValue(ValueType x)349 std::string GrpcStreamNetworkState::DisplayValue(ValueType x) {
350 switch (x) {
351 case kNotSentOnWire:
352 return "not sent on wire";
353 case kNotSeenByServer:
354 return "not seen by server";
355 }
356 GPR_UNREACHABLE_CODE(return "unknown value");
357 }
358
DisplayValue(void * x)359 std::string GrpcRegisteredMethod::DisplayValue(void* x) {
360 return absl::StrFormat("%p", x);
361 }
362
DisplayValue(const ValueType & x)363 std::string PeerString::DisplayValue(const ValueType& x) {
364 return std::string(x.as_string_view());
365 }
366
DisplayValue(const std::string & x)367 const std::string& GrpcStatusContext::DisplayValue(const std::string& x) {
368 return x;
369 }
370
DisplayValue(ValueType x)371 std::string WaitForReady::DisplayValue(ValueType x) {
372 return absl::StrCat(x.value ? "true" : "false",
373 x.explicitly_set ? " (explicit)" : "");
374 }
375
376 } // namespace grpc_core
377