1 use bytes::Bytes;
2 use http::header::HeaderName;
3 use std::borrow::Borrow;
4 use std::error::Error;
5 use std::fmt;
6 use std::marker::PhantomData;
7 use std::str::FromStr;
8 
9 use super::encoding::{Ascii, Binary, ValueEncoding};
10 
11 /// Represents a custom metadata field name.
12 ///
13 /// `MetadataKey` is used as the [`MetadataMap`] key.
14 ///
15 /// [`HeaderMap`]: struct.HeaderMap.html
16 /// [`MetadataMap`]: struct.MetadataMap.html
17 #[derive(Clone, Eq, PartialEq, Hash)]
18 #[repr(transparent)]
19 pub struct MetadataKey<VE: ValueEncoding> {
20     // Note: There are unsafe transmutes that assume that the memory layout
21     // of MetadataValue is identical to HeaderName
22     pub(crate) inner: http::header::HeaderName,
23     phantom: PhantomData<VE>,
24 }
25 
26 /// A possible error when converting a `MetadataKey` from another type.
27 #[derive(Debug)]
28 pub struct InvalidMetadataKey {
29     _priv: (),
30 }
31 
32 /// An ascii metadata key.
33 pub type AsciiMetadataKey = MetadataKey<Ascii>;
34 /// A binary metadata key.
35 pub type BinaryMetadataKey = MetadataKey<Binary>;
36 
37 impl<VE: ValueEncoding> MetadataKey<VE> {
38     /// Converts a slice of bytes to a `MetadataKey`.
39     ///
40     /// This function normalizes the input.
from_bytes(src: &[u8]) -> Result<Self, InvalidMetadataKey>41     pub fn from_bytes(src: &[u8]) -> Result<Self, InvalidMetadataKey> {
42         match HeaderName::from_bytes(src) {
43             Ok(name) => {
44                 if !VE::is_valid_key(name.as_str()) {
45                     return Err(InvalidMetadataKey::new());
46                 }
47 
48                 Ok(MetadataKey {
49                     inner: name,
50                     phantom: PhantomData,
51                 })
52             }
53             Err(_) => Err(InvalidMetadataKey::new()),
54         }
55     }
56 
57     /// Converts a static string to a `MetadataKey`.
58     ///
59     /// This function panics when the static string is a invalid metadata key.
60     ///
61     /// This function requires the static string to only contain lowercase
62     /// characters, numerals and symbols, as per the HTTP/2.0 specification
63     /// and header names internal representation within this library.
64     ///
65     ///
66     /// # Examples
67     ///
68     /// ```
69     /// # use tonic::metadata::*;
70     /// // Parsing a metadata key
71     /// let CUSTOM_KEY: &'static str = "custom-key";
72     ///
73     /// let a = AsciiMetadataKey::from_bytes(b"custom-key").unwrap();
74     /// let b = AsciiMetadataKey::from_static(CUSTOM_KEY);
75     /// assert_eq!(a, b);
76     /// ```
77     ///
78     /// ```should_panic
79     /// # use tonic::metadata::*;
80     /// // Parsing a metadata key that contains invalid symbols(s):
81     /// AsciiMetadataKey::from_static("content{}{}length"); // This line panics!
82     /// ```
83     ///
84     /// ```should_panic
85     /// # use tonic::metadata::*;
86     /// // Parsing a metadata key that contains invalid uppercase characters.
87     /// let a = AsciiMetadataKey::from_static("foobar");
88     /// let b = AsciiMetadataKey::from_static("FOOBAR"); // This line panics!
89     /// ```
90     ///
91     /// ```should_panic
92     /// # use tonic::metadata::*;
93     /// // Parsing a -bin metadata key as an Ascii key.
94     /// let b = AsciiMetadataKey::from_static("hello-bin"); // This line panics!
95     /// ```
96     ///
97     /// ```should_panic
98     /// # use tonic::metadata::*;
99     /// // Parsing a non-bin metadata key as an Binary key.
100     /// let b = BinaryMetadataKey::from_static("hello"); // This line panics!
101     /// ```
from_static(src: &'static str) -> Self102     pub fn from_static(src: &'static str) -> Self {
103         let name = HeaderName::from_static(src);
104         if !VE::is_valid_key(name.as_str()) {
105             panic!("invalid metadata key")
106         }
107 
108         MetadataKey {
109             inner: name,
110             phantom: PhantomData,
111         }
112     }
113 
114     /// Returns a `str` representation of the metadata key.
115     ///
116     /// The returned string will always be lower case.
117     #[inline]
as_str(&self) -> &str118     pub fn as_str(&self) -> &str {
119         self.inner.as_str()
120     }
121 
122     /// Converts a HeaderName reference to a MetadataKey. This method assumes
123     /// that the caller has made sure that the header name has the correct
124     /// "-bin" or non-"-bin" suffix, it does not validate its input.
125     #[inline]
unchecked_from_header_name_ref(header_name: &HeaderName) -> &Self126     pub(crate) fn unchecked_from_header_name_ref(header_name: &HeaderName) -> &Self {
127         unsafe { &*(header_name as *const HeaderName as *const Self) }
128     }
129 
130     /// Converts a HeaderName reference to a MetadataKey. This method assumes
131     /// that the caller has made sure that the header name has the correct
132     /// "-bin" or non-"-bin" suffix, it does not validate its input.
133     #[inline]
unchecked_from_header_name(name: HeaderName) -> Self134     pub(crate) fn unchecked_from_header_name(name: HeaderName) -> Self {
135         MetadataKey {
136             inner: name,
137             phantom: PhantomData,
138         }
139     }
140 }
141 
142 impl<VE: ValueEncoding> FromStr for MetadataKey<VE> {
143     type Err = InvalidMetadataKey;
144 
from_str(s: &str) -> Result<Self, InvalidMetadataKey>145     fn from_str(s: &str) -> Result<Self, InvalidMetadataKey> {
146         MetadataKey::from_bytes(s.as_bytes()).map_err(|_| InvalidMetadataKey::new())
147     }
148 }
149 
150 impl<VE: ValueEncoding> AsRef<str> for MetadataKey<VE> {
as_ref(&self) -> &str151     fn as_ref(&self) -> &str {
152         self.as_str()
153     }
154 }
155 
156 impl<VE: ValueEncoding> AsRef<[u8]> for MetadataKey<VE> {
as_ref(&self) -> &[u8]157     fn as_ref(&self) -> &[u8] {
158         self.as_str().as_bytes()
159     }
160 }
161 
162 impl<VE: ValueEncoding> Borrow<str> for MetadataKey<VE> {
borrow(&self) -> &str163     fn borrow(&self) -> &str {
164         self.as_str()
165     }
166 }
167 
168 impl<VE: ValueEncoding> fmt::Debug for MetadataKey<VE> {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result169     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
170         fmt::Debug::fmt(self.as_str(), fmt)
171     }
172 }
173 
174 impl<VE: ValueEncoding> fmt::Display for MetadataKey<VE> {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result175     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
176         fmt::Display::fmt(self.as_str(), fmt)
177     }
178 }
179 
180 impl InvalidMetadataKey {
181     #[doc(hidden)]
new() -> InvalidMetadataKey182     pub fn new() -> InvalidMetadataKey {
183         InvalidMetadataKey { _priv: () }
184     }
185 }
186 
187 impl<'a, VE: ValueEncoding> From<&'a MetadataKey<VE>> for MetadataKey<VE> {
from(src: &'a MetadataKey<VE>) -> MetadataKey<VE>188     fn from(src: &'a MetadataKey<VE>) -> MetadataKey<VE> {
189         src.clone()
190     }
191 }
192 
193 impl<VE: ValueEncoding> From<MetadataKey<VE>> for Bytes {
194     #[inline]
from(name: MetadataKey<VE>) -> Bytes195     fn from(name: MetadataKey<VE>) -> Bytes {
196         Bytes::copy_from_slice(name.inner.as_ref())
197     }
198 }
199 
200 impl<'a, VE: ValueEncoding> PartialEq<&'a MetadataKey<VE>> for MetadataKey<VE> {
201     #[inline]
eq(&self, other: &&'a MetadataKey<VE>) -> bool202     fn eq(&self, other: &&'a MetadataKey<VE>) -> bool {
203         *self == **other
204     }
205 }
206 
207 impl<'a, VE: ValueEncoding> PartialEq<MetadataKey<VE>> for &'a MetadataKey<VE> {
208     #[inline]
eq(&self, other: &MetadataKey<VE>) -> bool209     fn eq(&self, other: &MetadataKey<VE>) -> bool {
210         *other == *self
211     }
212 }
213 
214 impl<VE: ValueEncoding> PartialEq<str> for MetadataKey<VE> {
215     /// Performs a case-insensitive comparison of the string against the header
216     /// name
217     ///
218     /// # Examples
219     ///
220     /// ```
221     /// # use tonic::metadata::*;
222     /// let content_length = AsciiMetadataKey::from_static("content-length");
223     ///
224     /// assert_eq!(content_length, "content-length");
225     /// assert_eq!(content_length, "Content-Length");
226     /// assert_ne!(content_length, "content length");
227     /// ```
228     #[inline]
eq(&self, other: &str) -> bool229     fn eq(&self, other: &str) -> bool {
230         self.inner.eq(other)
231     }
232 }
233 
234 impl<VE: ValueEncoding> PartialEq<MetadataKey<VE>> for str {
235     /// Performs a case-insensitive comparison of the string against the header
236     /// name
237     ///
238     /// # Examples
239     ///
240     /// ```
241     /// # use tonic::metadata::*;
242     /// let content_length = AsciiMetadataKey::from_static("content-length");
243     ///
244     /// assert_eq!(content_length, "content-length");
245     /// assert_eq!(content_length, "Content-Length");
246     /// assert_ne!(content_length, "content length");
247     /// ```
248     #[inline]
eq(&self, other: &MetadataKey<VE>) -> bool249     fn eq(&self, other: &MetadataKey<VE>) -> bool {
250         other.inner == *self
251     }
252 }
253 
254 impl<'a, VE: ValueEncoding> PartialEq<&'a str> for MetadataKey<VE> {
255     /// Performs a case-insensitive comparison of the string against the header
256     /// name
257     #[inline]
eq(&self, other: &&'a str) -> bool258     fn eq(&self, other: &&'a str) -> bool {
259         *self == **other
260     }
261 }
262 
263 impl<'a, VE: ValueEncoding> PartialEq<MetadataKey<VE>> for &'a str {
264     /// Performs a case-insensitive comparison of the string against the header
265     /// name
266     #[inline]
eq(&self, other: &MetadataKey<VE>) -> bool267     fn eq(&self, other: &MetadataKey<VE>) -> bool {
268         *other == *self
269     }
270 }
271 
272 impl fmt::Display for InvalidMetadataKey {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result273     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
274         f.write_str("invalid gRPC metadata key name")
275     }
276 }
277 
278 impl Default for InvalidMetadataKey {
default() -> Self279     fn default() -> Self {
280         Self::new()
281     }
282 }
283 
284 impl Error for InvalidMetadataKey {}
285 
286 #[cfg(test)]
287 mod tests {
288     use super::{AsciiMetadataKey, BinaryMetadataKey};
289 
290     #[test]
test_from_bytes_binary()291     fn test_from_bytes_binary() {
292         assert!(BinaryMetadataKey::from_bytes(b"").is_err());
293         assert!(BinaryMetadataKey::from_bytes(b"\xFF").is_err());
294         assert!(BinaryMetadataKey::from_bytes(b"abc").is_err());
295         assert_eq!(
296             BinaryMetadataKey::from_bytes(b"abc-bin").unwrap().as_str(),
297             "abc-bin"
298         );
299     }
300 
301     #[test]
test_from_bytes_ascii()302     fn test_from_bytes_ascii() {
303         assert!(AsciiMetadataKey::from_bytes(b"").is_err());
304         assert!(AsciiMetadataKey::from_bytes(b"\xFF").is_err());
305         assert_eq!(
306             AsciiMetadataKey::from_bytes(b"abc").unwrap().as_str(),
307             "abc"
308         );
309         assert!(AsciiMetadataKey::from_bytes(b"abc-bin").is_err());
310     }
311 }
312