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