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