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