1 // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0.
2
3 use crate::grpc_sys::{self, grpc_metadata, grpc_metadata_array};
4 use std::borrow::Cow;
5 use std::fmt;
6 use std::mem::ManuallyDrop;
7 use std::{mem, slice, str};
8
9 use crate::error::{Error, Result};
10
11 const BINARY_ERROR_DETAILS_KEY: &str = "grpc-status-details-bin";
12
normalize_key(key: &str, binary: bool) -> Result<Cow<'_, str>>13 fn normalize_key(key: &str, binary: bool) -> Result<Cow<'_, str>> {
14 if key.is_empty() {
15 return Err(Error::InvalidMetadata(
16 "metadata key should not be empty".to_owned(),
17 ));
18 }
19 let mut is_upper_case = false;
20 for b in key.as_bytes() {
21 let b = *b;
22 if b.is_ascii_uppercase() {
23 is_upper_case = true;
24 continue;
25 } else if b.is_ascii_lowercase()
26 || b.is_ascii_digit()
27 || b == b'_'
28 || b == b'-'
29 || b == b'.'
30 {
31 continue;
32 }
33 return Err(Error::InvalidMetadata(format!("key {key:?} is invalid")));
34 }
35 let key = if is_upper_case {
36 Cow::Owned(key.to_ascii_lowercase())
37 } else {
38 Cow::Borrowed(key)
39 };
40 if binary {
41 if !key.as_bytes().ends_with(b"-bin") {
42 return Err(Error::InvalidMetadata(
43 "binary key should end with '-bin'".to_owned(),
44 ));
45 }
46 } else if key.as_bytes().ends_with(b"-bin") {
47 return Err(Error::InvalidMetadata(
48 "non-binary key should not end with '-bin'".to_owned(),
49 ));
50 }
51 Ok(key)
52 }
53
54 /// Builder for immutable Metadata.
55 pub struct MetadataBuilder {
56 arr: Metadata,
57 }
58
59 impl MetadataBuilder {
60 /// Create a builder with empty initial capacity.
new() -> MetadataBuilder61 pub fn new() -> MetadataBuilder {
62 MetadataBuilder::with_capacity(0)
63 }
64
65 /// Create a builder with the given value.
with_capacity(cap: usize) -> MetadataBuilder66 pub fn with_capacity(cap: usize) -> MetadataBuilder {
67 MetadataBuilder {
68 arr: Metadata::with_capacity(cap),
69 }
70 }
71
72 /// Add a metadata holding an ASCII value.
73 ///
74 /// `key` must not use suffix (-bin) indicating a binary valued metadata entry.
add_str(&mut self, key: &str, value: &str) -> Result<&mut MetadataBuilder>75 pub fn add_str(&mut self, key: &str, value: &str) -> Result<&mut MetadataBuilder> {
76 if !value.is_ascii() {
77 return Err(Error::InvalidMetadata(
78 "only ascii value is accepted.".to_owned(),
79 ));
80 }
81 for b in value.bytes() {
82 if 0 == unsafe { libc::isprint(b as i32) } {
83 return Err(Error::InvalidMetadata(
84 "Only printable chars are accepted.".to_owned(),
85 ));
86 }
87 }
88 let key = normalize_key(key, false)?;
89 Ok(self.add_metadata(&key, value.as_bytes()))
90 }
91
add_metadata(&mut self, key: &str, value: &[u8]) -> &mut MetadataBuilder92 fn add_metadata(&mut self, key: &str, value: &[u8]) -> &mut MetadataBuilder {
93 unsafe {
94 grpc_sys::grpcwrap_metadata_array_add(
95 &mut self.arr.0,
96 key.as_ptr() as _,
97 key.len(),
98 value.as_ptr() as _,
99 value.len(),
100 )
101 }
102 self
103 }
104
105 /// Add a metadata holding a binary value.
106 ///
107 /// `key` needs to have suffix (-bin) indicating a binary valued metadata entry.
add_bytes(&mut self, key: &str, value: &[u8]) -> Result<&mut MetadataBuilder>108 pub fn add_bytes(&mut self, key: &str, value: &[u8]) -> Result<&mut MetadataBuilder> {
109 let key = normalize_key(key, true)?;
110 Ok(self.add_metadata(&key, value))
111 }
112
113 /// Set binary error details to support rich error model.
114 ///
115 /// See also https://grpc.io/docs/guides/error/#richer-error-model.
set_binary_error_details(&mut self, value: &[u8]) -> &mut MetadataBuilder116 pub(crate) fn set_binary_error_details(&mut self, value: &[u8]) -> &mut MetadataBuilder {
117 self.add_metadata(BINARY_ERROR_DETAILS_KEY, value)
118 }
119
120 /// Create `Metadata` with configured entries.
build(mut self) -> Metadata121 pub fn build(mut self) -> Metadata {
122 unsafe {
123 grpc_sys::grpcwrap_metadata_array_shrink_to_fit(&mut self.arr.0);
124 }
125 self.arr
126 }
127 }
128
129 /// A collection of metadata entries that can be exchanged during a call.
130 ///
131 /// gRPC supports these types of metadata:
132 ///
133 /// - Request headers
134 ///
135 /// They are sent by the client at the beginning of a remote call before
136 /// any request messages are sent.
137 ///
138 /// - Response headers
139 ///
140 /// They are sent by the server at the beginning of a remote call handler
141 /// before any response messages are sent.
142 ///
143 /// - Response trailers
144 ///
145 /// They are sent by the server at the end of a remote call along with
146 /// resulting call status.
147 ///
148 /// Metadata value can be ascii string or bytes. They are distinguish by the
149 /// key suffix, key of bytes value should have suffix '-bin'.
150 #[repr(transparent)]
151 pub struct Metadata(grpc_metadata_array);
152
153 impl Metadata {
with_capacity(cap: usize) -> Metadata154 fn with_capacity(cap: usize) -> Metadata {
155 unsafe {
156 let mut arr = mem::MaybeUninit::uninit();
157 grpc_sys::grpcwrap_metadata_array_init(arr.as_mut_ptr(), cap);
158 Metadata(arr.assume_init())
159 }
160 }
161
162 /// Returns the count of metadata entries.
163 #[inline]
len(&self) -> usize164 pub fn len(&self) -> usize {
165 self.0.count
166 }
167
168 /// Returns true if there is no metadata entries.
169 #[inline]
is_empty(&self) -> bool170 pub fn is_empty(&self) -> bool {
171 self.0.count == 0
172 }
173
174 /// Returns the metadata entry at the `index`.
175 ///
176 /// `None` is returned if out of bound.
get(&self, index: usize) -> Option<(&str, &[u8])>177 pub fn get(&self, index: usize) -> Option<(&str, &[u8])> {
178 if self.0.count <= index {
179 return None;
180 }
181 let (mut key_len, mut val_len) = (0, 0);
182 unsafe {
183 let key = grpc_sys::grpcwrap_metadata_array_get_key(&self.0, index, &mut key_len);
184 let val = grpc_sys::grpcwrap_metadata_array_get_value(&self.0, index, &mut val_len);
185 let key_str = str::from_utf8_unchecked(slice::from_raw_parts(key as _, key_len));
186 let val_bytes = slice::from_raw_parts(val as *const u8, val_len);
187 Some((key_str, val_bytes))
188 }
189 }
190
191 /// Returns an iterator over the metadata entries.
iter(&self) -> MetadataIter<'_>192 pub fn iter(&self) -> MetadataIter<'_> {
193 MetadataIter {
194 data: self,
195 index: 0,
196 }
197 }
198
199 /// Decomposes a Metadata array into its raw components.
200 ///
201 /// Returns the raw pointer to the underlying data, the length of the vector (in elements),
202 /// and the allocated capacity of the data (in elements). These are the same arguments in
203 /// the same order as the arguments to from_raw_parts.
204 ///
205 /// After calling this function, the caller is responsible for the memory previously managed
206 /// by the Metadata. The only way to do this is to convert the raw pointer, length, and
207 /// capacity back into a Metadata with the from_raw_parts function, allowing the destructor
208 /// to perform the cleanup.
into_raw_parts(self) -> (*mut grpc_metadata, usize, usize)209 pub fn into_raw_parts(self) -> (*mut grpc_metadata, usize, usize) {
210 let s = ManuallyDrop::new(self);
211 (s.0.metadata, s.0.count, s.0.capacity)
212 }
213
214 /// Creates a Metadata directly from the raw components of another vector.
215 ///
216 /// ## Safety
217 ///
218 /// The operation is safe only if the three arguments are returned from `into_raw_parts`
219 /// and only convert once.
from_raw_parts(p: *mut grpc_metadata, len: usize, cap: usize) -> Metadata220 pub unsafe fn from_raw_parts(p: *mut grpc_metadata, len: usize, cap: usize) -> Metadata {
221 Metadata(grpc_metadata_array {
222 count: len,
223 capacity: cap,
224 metadata: p,
225 })
226 }
227
228 /// Search for binary error details.
search_binary_error_details(&self) -> &[u8]229 pub(crate) fn search_binary_error_details(&self) -> &[u8] {
230 for (k, v) in self.iter() {
231 if k == BINARY_ERROR_DETAILS_KEY {
232 return v;
233 }
234 }
235 &[]
236 }
237 }
238
239 impl fmt::Debug for Metadata {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result240 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
241 fmt.debug_map()
242 .entries(
243 self.iter()
244 .map(|(k, v)| (k, std::str::from_utf8(v).unwrap_or("?"))),
245 )
246 .finish()
247 }
248 }
249
250 impl Clone for Metadata {
clone(&self) -> Metadata251 fn clone(&self) -> Metadata {
252 let mut builder = MetadataBuilder::with_capacity(self.len());
253 for (k, v) in self.iter() {
254 // use `add_metadata` to skip validation.
255 builder.add_metadata(k, v);
256 }
257 builder.build()
258 }
259 }
260
261 impl Drop for Metadata {
drop(&mut self)262 fn drop(&mut self) {
263 unsafe {
264 grpc_sys::grpcwrap_metadata_array_cleanup(&mut self.0);
265 }
266 }
267 }
268
269 unsafe impl Send for Metadata {}
270 unsafe impl Sync for Metadata {}
271
272 /// A special metadata that only for receiving metadata from remote.
273 ///
274 /// gRPC C Core manages metadata internally, it's unsafe to read them unless
275 /// call is not destroyed.
276 #[repr(transparent)]
277 pub struct UnownedMetadata(grpc_metadata_array);
278
279 impl UnownedMetadata {
280 #[inline]
empty() -> UnownedMetadata281 pub fn empty() -> UnownedMetadata {
282 unsafe { mem::transmute(Metadata::with_capacity(0)) }
283 }
284 #[inline]
assume_valid(&self) -> &Metadata285 pub unsafe fn assume_valid(&self) -> &Metadata {
286 mem::transmute(self)
287 }
288
as_mut_ptr(&mut self) -> *mut grpc_metadata_array289 pub fn as_mut_ptr(&mut self) -> *mut grpc_metadata_array {
290 &mut self.0 as _
291 }
292 }
293
294 impl Drop for UnownedMetadata {
295 #[inline]
drop(&mut self)296 fn drop(&mut self) {
297 unsafe { grpcio_sys::grpcwrap_metadata_array_destroy_metadata_only(&mut self.0) }
298 }
299 }
300
301 unsafe impl Send for UnownedMetadata {}
302 unsafe impl Sync for UnownedMetadata {}
303
304 /// Immutable metadata iterator
305 ///
306 /// This struct is created by the iter method on `Metadata`.
307 pub struct MetadataIter<'a> {
308 data: &'a Metadata,
309 index: usize,
310 }
311
312 impl<'a> Iterator for MetadataIter<'a> {
313 type Item = (&'a str, &'a [u8]);
314
next(&mut self) -> Option<Self::Item>315 fn next(&mut self) -> Option<Self::Item> {
316 let res = self.data.get(self.index);
317 if res.is_some() {
318 self.index += 1;
319 }
320 res
321 }
322
size_hint(&self) -> (usize, Option<usize>)323 fn size_hint(&self) -> (usize, Option<usize>) {
324 let remain = self.data.0.count - self.index;
325 (remain, Some(remain))
326 }
327 }
328
329 impl<'a> IntoIterator for &'a Metadata {
330 type IntoIter = MetadataIter<'a>;
331 type Item = (&'a str, &'a [u8]);
332
into_iter(self) -> MetadataIter<'a>333 fn into_iter(self) -> MetadataIter<'a> {
334 MetadataIter {
335 data: self,
336 index: 0,
337 }
338 }
339 }
340
341 #[cfg(test)]
342 mod tests {
343 use super::*;
344
345 #[test]
test_key_check()346 fn test_key_check() {
347 let mut builder = MetadataBuilder::new();
348 // Non-byte key should not end with '-bin'.
349 assert!(builder.add_str("key-bin", "value").is_err());
350 // Byte key should end with '-bin'.
351 assert!(builder.add_bytes("key", b"value").is_err());
352 // Key should not be empty.
353 assert!(builder.add_str("", "value").is_err());
354 // Key should follow the rule ^[a-z0-9_-.]+$
355 assert!(builder.add_str(":key", "value").is_err());
356 assert!(builder.add_str("key~", "value").is_err());
357 assert!(builder.add_str("ke+y", "value").is_err());
358 // Only printable ascii value is accepted when `add_str`.
359 assert!(builder.add_str("key", "❤").is_err());
360 assert!(builder.add_str("key", "\0").is_err());
361 assert!(builder.add_str("key", "\n").is_err());
362
363 builder.add_str("key", "value").unwrap();
364 builder.add_str("_", "value").unwrap();
365 builder.add_str("-", "value").unwrap();
366 builder.add_str(".", "value").unwrap();
367 builder.add_bytes("key-bin", b"value").unwrap();
368 }
369
370 #[test]
test_metadata()371 fn test_metadata() {
372 let mut builder = MetadataBuilder::new();
373 let mut meta_kvs = vec![];
374 for i in 0..5 {
375 let key = format!("K{i}");
376 let val = format!("v{i}");
377 builder.add_str(&key, &val).unwrap();
378 meta_kvs.push((key.to_ascii_lowercase(), val.into_bytes()));
379 }
380 for i in 5..10 {
381 let key = format!("k{i}-Bin");
382 let val = format!("v{i}");
383 builder.add_bytes(&key, val.as_bytes()).unwrap();
384 meta_kvs.push((key.to_ascii_lowercase(), val.into_bytes()));
385 }
386 let metadata = builder.build();
387 for (i, (exp, res)) in meta_kvs.iter().zip(&metadata).enumerate() {
388 let kv = metadata.get(i).unwrap();
389 assert_eq!(kv, res);
390 assert_eq!(res, (exp.0.as_str(), exp.1.as_slice()));
391 }
392 assert!(metadata.get(10).is_none());
393 assert_eq!(metadata.len(), 10);
394 assert!(!metadata.is_empty());
395 {
396 let mut iter = metadata.iter();
397 for i in 0..10 {
398 assert_eq!(iter.size_hint(), (10 - i, Some(10 - i)));
399 iter.next();
400 }
401 assert_eq!(iter.size_hint(), (0, Some(0)));
402 }
403
404 let metadata1 = metadata.clone();
405 for (x, y) in metadata.iter().zip(&metadata1) {
406 assert_eq!(x, y);
407 }
408 drop(metadata);
409 // Ensure deep copy.
410 assert!(metadata1.get(0).is_some());
411
412 let empty_metadata = MetadataBuilder::new().build();
413 assert!(empty_metadata.is_empty());
414 assert_eq!(empty_metadata.len(), 0);
415 }
416 }
417