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