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 
23 #include "absl/strings/escaping.h"
24 #include "absl/strings/match.h"
25 #include "absl/strings/str_cat.h"
26 
27 #include "src/core/lib/transport/timeout_encoding.h"
28 
29 namespace grpc_core {
30 namespace metadata_detail {
31 
Add(absl::string_view key,absl::string_view value)32 void DebugStringBuilder::Add(absl::string_view key, absl::string_view value) {
33   if (!out_.empty()) out_.append(", ");
34   absl::StrAppend(&out_, absl::CEscape(key), ": ", absl::CEscape(value));
35 }
36 
Append(absl::string_view key,Slice value)37 void UnknownMap::Append(absl::string_view key, Slice value) {
38   unknown_.EmplaceBack(Slice::FromCopiedString(key), value.Ref());
39 }
40 
Remove(absl::string_view key)41 void UnknownMap::Remove(absl::string_view key) {
42   unknown_.SetEnd(std::remove_if(unknown_.begin(), unknown_.end(),
43                                  [key](const std::pair<Slice, Slice>& p) {
44                                    return p.first.as_string_view() == key;
45                                  }));
46 }
47 
GetStringValue(absl::string_view key,std::string * backing) const48 absl::optional<absl::string_view> UnknownMap::GetStringValue(
49     absl::string_view key, std::string* backing) const {
50   absl::optional<absl::string_view> out;
51   for (const auto& p : unknown_) {
52     if (p.first.as_string_view() == key) {
53       if (!out.has_value()) {
54         out = p.second.as_string_view();
55       } else {
56         out = *backing = absl::StrCat(*out, ",", p.second.as_string_view());
57       }
58     }
59   }
60   return out;
61 }
62 
63 }  // namespace metadata_detail
64 
ParseMemento(Slice value,MetadataParseErrorFn on_error)65 ContentTypeMetadata::MementoType ContentTypeMetadata::ParseMemento(
66     Slice value, MetadataParseErrorFn on_error) {
67   auto out = kInvalid;
68   auto value_string = value.as_string_view();
69   if (value_string == "application/grpc") {
70     out = kApplicationGrpc;
71   } else if (absl::StartsWith(value_string, "application/grpc;")) {
72     out = kApplicationGrpc;
73   } else if (absl::StartsWith(value_string, "application/grpc+")) {
74     out = kApplicationGrpc;
75   } else if (value_string.empty()) {
76     out = kEmpty;
77   } else {
78     on_error("invalid value", value);
79   }
80   return out;
81 }
82 
Encode(ValueType x)83 StaticSlice ContentTypeMetadata::Encode(ValueType x) {
84   switch (x) {
85     case kEmpty:
86       return StaticSlice::FromStaticString("");
87     case kApplicationGrpc:
88       return StaticSlice::FromStaticString("application/grpc");
89     case kInvalid:
90       return StaticSlice::FromStaticString("application/grpc+unknown");
91   }
92   GPR_UNREACHABLE_CODE(
93       return StaticSlice::FromStaticString("unrepresentable value"));
94 }
95 
DisplayValue(ValueType content_type)96 const char* ContentTypeMetadata::DisplayValue(ValueType content_type) {
97   switch (content_type) {
98     case ValueType::kApplicationGrpc:
99       return "application/grpc";
100     case ValueType::kEmpty:
101       return "";
102     default:
103       return "<discarded-invalid-value>";
104   }
105 }
106 
ParseMemento(Slice value,MetadataParseErrorFn on_error)107 GrpcTimeoutMetadata::MementoType GrpcTimeoutMetadata::ParseMemento(
108     Slice value, MetadataParseErrorFn on_error) {
109   auto timeout = ParseTimeout(value);
110   if (!timeout.has_value()) {
111     on_error("invalid value", value);
112     return Duration::Infinity();
113   }
114   return *timeout;
115 }
116 
MementoToValue(MementoType timeout)117 GrpcTimeoutMetadata::ValueType GrpcTimeoutMetadata::MementoToValue(
118     MementoType timeout) {
119   if (timeout == Duration::Infinity()) {
120     return Timestamp::InfFuture();
121   }
122   return Timestamp::Now() + timeout;
123 }
124 
Encode(ValueType x)125 Slice GrpcTimeoutMetadata::Encode(ValueType x) {
126   return Timeout::FromDuration(x - Timestamp::Now()).Encode();
127 }
128 
ParseMemento(Slice value,MetadataParseErrorFn on_error)129 TeMetadata::MementoType TeMetadata::ParseMemento(
130     Slice value, MetadataParseErrorFn on_error) {
131   auto out = kInvalid;
132   if (value == "trailers") {
133     out = kTrailers;
134   } else {
135     on_error("invalid value", value);
136   }
137   return out;
138 }
139 
DisplayValue(ValueType te)140 const char* TeMetadata::DisplayValue(ValueType te) {
141   switch (te) {
142     case ValueType::kTrailers:
143       return "trailers";
144     default:
145       return "<discarded-invalid-value>";
146   }
147 }
148 
Parse(absl::string_view value,MetadataParseErrorFn on_error)149 HttpSchemeMetadata::ValueType HttpSchemeMetadata::Parse(
150     absl::string_view value, MetadataParseErrorFn on_error) {
151   if (value == "http") {
152     return kHttp;
153   } else if (value == "https") {
154     return kHttps;
155   }
156   on_error("invalid value", Slice::FromCopiedBuffer(value));
157   return kInvalid;
158 }
159 
Encode(ValueType x)160 StaticSlice HttpSchemeMetadata::Encode(ValueType x) {
161   switch (x) {
162     case kHttp:
163       return StaticSlice::FromStaticString("http");
164     case kHttps:
165       return StaticSlice::FromStaticString("https");
166     default:
167       abort();
168   }
169 }
170 
EncodedSizeOfKey(HttpSchemeMetadata,HttpSchemeMetadata::ValueType x)171 size_t EncodedSizeOfKey(HttpSchemeMetadata, HttpSchemeMetadata::ValueType x) {
172   switch (x) {
173     case HttpSchemeMetadata::kHttp:
174       return 4;
175     case HttpSchemeMetadata::kHttps:
176       return 5;
177     default:
178       return 0;
179   }
180 }
181 
DisplayValue(ValueType content_type)182 const char* HttpSchemeMetadata::DisplayValue(ValueType content_type) {
183   switch (content_type) {
184     case kHttp:
185       return "http";
186     case kHttps:
187       return "https";
188     default:
189       return "<discarded-invalid-value>";
190   }
191 }
192 
ParseMemento(Slice value,MetadataParseErrorFn on_error)193 HttpMethodMetadata::MementoType HttpMethodMetadata::ParseMemento(
194     Slice value, MetadataParseErrorFn on_error) {
195   auto out = kInvalid;
196   auto value_string = value.as_string_view();
197   if (value_string == "POST") {
198     out = kPost;
199   } else if (value_string == "PUT") {
200     out = kPut;
201   } else if (value_string == "GET") {
202     out = kGet;
203   } else {
204     on_error("invalid value", value);
205   }
206   return out;
207 }
208 
Encode(ValueType x)209 StaticSlice HttpMethodMetadata::Encode(ValueType x) {
210   switch (x) {
211     case kPost:
212       return StaticSlice::FromStaticString("POST");
213     case kPut:
214       return StaticSlice::FromStaticString("PUT");
215     case kGet:
216       return StaticSlice::FromStaticString("GET");
217     default:
218       // TODO(ctiller): this should be an abort, we should split up the debug
219       // string generation from the encode string generation so that debug
220       // strings can always succeed and encode strings can crash.
221       return StaticSlice::FromStaticString("<<INVALID METHOD>>");
222   }
223 }
224 
DisplayValue(ValueType content_type)225 const char* HttpMethodMetadata::DisplayValue(ValueType content_type) {
226   switch (content_type) {
227     case kPost:
228       return "POST";
229     case kGet:
230       return "GET";
231     case kPut:
232       return "PUT";
233     default:
234       return "<discarded-invalid-value>";
235   }
236 }
237 
238 CompressionAlgorithmBasedMetadata::MementoType
ParseMemento(Slice value,MetadataParseErrorFn on_error)239 CompressionAlgorithmBasedMetadata::ParseMemento(Slice value,
240                                                 MetadataParseErrorFn on_error) {
241   auto algorithm = ParseCompressionAlgorithm(value.as_string_view());
242   if (!algorithm.has_value()) {
243     on_error("invalid value", value);
244     return GRPC_COMPRESS_NONE;
245   }
246   return *algorithm;
247 }
248 
ParseMemento(Slice value,MetadataParseErrorFn on_error)249 Duration GrpcRetryPushbackMsMetadata::ParseMemento(
250     Slice value, MetadataParseErrorFn on_error) {
251   int64_t out;
252   if (!absl::SimpleAtoi(value.as_string_view(), &out)) {
253     on_error("not an integer", value);
254     return Duration::NegativeInfinity();
255   }
256   return Duration::Milliseconds(out);
257 }
258 
Encode(const ValueType & x)259 Slice LbCostBinMetadata::Encode(const ValueType& x) {
260   auto slice =
261       MutableSlice::CreateUninitialized(sizeof(double) + x.name.length());
262   memcpy(slice.data(), &x.cost, sizeof(double));
263   memcpy(slice.data() + sizeof(double), x.name.data(), x.name.length());
264   return Slice(std::move(slice));
265 }
266 
DisplayValue(ValueType x)267 std::string LbCostBinMetadata::DisplayValue(ValueType x) {
268   return absl::StrCat(x.name, ":", x.cost);
269 }
270 
ParseMemento(Slice value,MetadataParseErrorFn on_error)271 LbCostBinMetadata::MementoType LbCostBinMetadata::ParseMemento(
272     Slice value, MetadataParseErrorFn on_error) {
273   if (value.length() < sizeof(double)) {
274     on_error("too short", value);
275     return {0, ""};
276   }
277   MementoType out;
278   memcpy(&out.cost, value.data(), sizeof(double));
279   out.name =
280       std::string(reinterpret_cast<const char*>(value.data()) + sizeof(double),
281                   value.length() - sizeof(double));
282   return out;
283 }
284 
DisplayValue(ValueType x)285 std::string GrpcStreamNetworkState::DisplayValue(ValueType x) {
286   switch (x) {
287     case kNotSentOnWire:
288       return "not sent on wire";
289     case kNotSeenByServer:
290       return "not seen by server";
291   }
292   GPR_UNREACHABLE_CODE(return "unknown value");
293 }
294 
DisplayValue(const ValueType & x)295 std::string PeerString::DisplayValue(const ValueType& x) {
296   return std::string(x.as_string_view());
297 }
298 
DisplayValue(const std::string & x)299 const std::string& GrpcStatusContext::DisplayValue(const std::string& x) {
300   return x;
301 }
302 
DisplayValue(ValueType x)303 std::string WaitForReady::DisplayValue(ValueType x) {
304   return absl::StrCat(x.value ? "true" : "false",
305                       x.explicitly_set ? " (explicit)" : "");
306 }
307 
308 }  // namespace grpc_core
309