tonic/metadata/key.rs
1use bytes::Bytes;
2use http::header::HeaderName;
3use std::borrow::Borrow;
4use std::error::Error;
5use std::fmt;
6use std::marker::PhantomData;
7use std::str::FromStr;
8
9use 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)]
19pub 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)]
28pub struct InvalidMetadataKey {
29 _priv: (),
30}
31
32/// An ascii metadata key.
33pub type AsciiMetadataKey = MetadataKey<Ascii>;
34/// A binary metadata key.
35pub type BinaryMetadataKey = MetadataKey<Binary>;
36
37impl<VE: ValueEncoding> MetadataKey<VE> {
38 /// Converts a slice of bytes to a `MetadataKey`.
39 ///
40 /// This function normalizes the input.
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 panic!("invalid metadata key")
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 /// ```
102 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]
118 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]
126 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]
134 pub(crate) fn unchecked_from_header_name(name: HeaderName) -> Self {
135 MetadataKey {
136 inner: name,
137 phantom: PhantomData,
138 }
139 }
140}
141
142impl<VE: ValueEncoding> FromStr for MetadataKey<VE> {
143 type Err = InvalidMetadataKey;
144
145 fn from_str(s: &str) -> Result<Self, InvalidMetadataKey> {
146 MetadataKey::from_bytes(s.as_bytes()).map_err(|_| InvalidMetadataKey::new())
147 }
148}
149
150impl<VE: ValueEncoding> AsRef<str> for MetadataKey<VE> {
151 fn as_ref(&self) -> &str {
152 self.as_str()
153 }
154}
155
156impl<VE: ValueEncoding> AsRef<[u8]> for MetadataKey<VE> {
157 fn as_ref(&self) -> &[u8] {
158 self.as_str().as_bytes()
159 }
160}
161
162impl<VE: ValueEncoding> Borrow<str> for MetadataKey<VE> {
163 fn borrow(&self) -> &str {
164 self.as_str()
165 }
166}
167
168impl<VE: ValueEncoding> fmt::Debug for MetadataKey<VE> {
169 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
170 fmt::Debug::fmt(self.as_str(), fmt)
171 }
172}
173
174impl<VE: ValueEncoding> fmt::Display for MetadataKey<VE> {
175 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
176 fmt::Display::fmt(self.as_str(), fmt)
177 }
178}
179
180impl InvalidMetadataKey {
181 #[doc(hidden)]
182 pub fn new() -> InvalidMetadataKey {
183 InvalidMetadataKey { _priv: () }
184 }
185}
186
187impl<'a, VE: ValueEncoding> From<&'a MetadataKey<VE>> for MetadataKey<VE> {
188 fn from(src: &'a MetadataKey<VE>) -> MetadataKey<VE> {
189 src.clone()
190 }
191}
192
193impl<VE: ValueEncoding> From<MetadataKey<VE>> for Bytes {
194 #[inline]
195 fn from(name: MetadataKey<VE>) -> Bytes {
196 Bytes::copy_from_slice(name.inner.as_ref())
197 }
198}
199
200impl<'a, VE: ValueEncoding> PartialEq<&'a MetadataKey<VE>> for MetadataKey<VE> {
201 #[inline]
202 fn eq(&self, other: &&'a MetadataKey<VE>) -> bool {
203 *self == **other
204 }
205}
206
207impl<'a, VE: ValueEncoding> PartialEq<MetadataKey<VE>> for &'a MetadataKey<VE> {
208 #[inline]
209 fn eq(&self, other: &MetadataKey<VE>) -> bool {
210 *other == *self
211 }
212}
213
214impl<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]
229 fn eq(&self, other: &str) -> bool {
230 self.inner.eq(other)
231 }
232}
233
234impl<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]
249 fn eq(&self, other: &MetadataKey<VE>) -> bool {
250 (*other).inner == *self
251 }
252}
253
254impl<'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]
258 fn eq(&self, other: &&'a str) -> bool {
259 *self == **other
260 }
261}
262
263impl<'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]
267 fn eq(&self, other: &MetadataKey<VE>) -> bool {
268 *other == *self
269 }
270}
271
272impl fmt::Display for InvalidMetadataKey {
273 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
274 f.write_str("invalid gRPC metadata key name")
275 }
276}
277
278impl Default for InvalidMetadataKey {
279 fn default() -> Self {
280 Self::new()
281 }
282}
283
284impl Error for InvalidMetadataKey {}