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