xref: /aosp_15_r20/external/grpc-grpc/src/core/lib/transport/metadata_batch.cc (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
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