tonic/metadata/
encoding.rs

1use base64::Engine as _;
2use bytes::Bytes;
3use http::header::HeaderValue;
4use std::error::Error;
5use std::fmt;
6use std::hash::Hash;
7
8/// A possible error when converting a `MetadataValue` from a string or byte
9/// slice.
10#[derive(Debug, Hash)]
11pub struct InvalidMetadataValue {
12    _priv: (),
13}
14
15mod value_encoding {
16    use super::InvalidMetadataValueBytes;
17    use bytes::Bytes;
18    use http::header::HeaderValue;
19    use std::fmt;
20
21    pub trait Sealed {
22        #[doc(hidden)]
23        fn is_empty(value: &[u8]) -> bool;
24
25        #[doc(hidden)]
26        fn from_bytes(value: &[u8]) -> Result<HeaderValue, InvalidMetadataValueBytes>;
27
28        #[doc(hidden)]
29        fn from_shared(value: Bytes) -> Result<HeaderValue, InvalidMetadataValueBytes>;
30
31        #[doc(hidden)]
32        fn from_static(value: &'static str) -> HeaderValue;
33
34        #[doc(hidden)]
35        fn decode(value: &[u8]) -> Result<Bytes, InvalidMetadataValueBytes>;
36
37        #[doc(hidden)]
38        fn equals(a: &HeaderValue, b: &[u8]) -> bool;
39
40        #[doc(hidden)]
41        fn values_equal(a: &HeaderValue, b: &HeaderValue) -> bool;
42
43        #[doc(hidden)]
44        fn fmt(value: &HeaderValue, f: &mut fmt::Formatter<'_>) -> fmt::Result;
45    }
46}
47
48pub trait ValueEncoding: Clone + Eq + PartialEq + Hash + self::value_encoding::Sealed {
49    /// Returns true if the provided key is valid for this ValueEncoding type.
50    /// For example, `Ascii::is_valid_key("a") == true`,
51    /// `Ascii::is_valid_key("a-bin") == false`.
52    fn is_valid_key(key: &str) -> bool;
53}
54
55/// gRPC metadata values can be either ASCII strings or binary. Note that only
56/// visible ASCII characters (32-127) are permitted.
57/// This type should never be instantiated -- in fact, it's impossible
58/// to, because there's no variants to instantiate. Instead, it's just used as
59/// a type parameter for [`MetadataKey`] and [`MetadataValue`].
60///
61/// [`MetadataKey`]: struct.MetadataKey.html
62/// [`MetadataValue`]: struct.MetadataValue.html
63#[derive(Clone, Debug, Eq, PartialEq, Hash)]
64#[non_exhaustive]
65pub enum Ascii {}
66
67/// gRPC metadata values can be either ASCII strings or binary.
68/// This type should never be instantiated -- in fact, it's impossible
69/// to, because there's no variants to instantiate. Instead, it's just used as
70/// a type parameter for [`MetadataKey`] and [`MetadataValue`].
71///
72/// [`MetadataKey`]: struct.MetadataKey.html
73/// [`MetadataValue`]: struct.MetadataValue.html
74#[derive(Clone, Debug, Eq, PartialEq, Hash)]
75#[non_exhaustive]
76pub enum Binary {}
77
78// ===== impl ValueEncoding =====
79
80impl self::value_encoding::Sealed for Ascii {
81    fn is_empty(value: &[u8]) -> bool {
82        value.is_empty()
83    }
84
85    fn from_bytes(value: &[u8]) -> Result<HeaderValue, InvalidMetadataValueBytes> {
86        HeaderValue::from_bytes(value).map_err(|_| InvalidMetadataValueBytes::new())
87    }
88
89    fn from_shared(value: Bytes) -> Result<HeaderValue, InvalidMetadataValueBytes> {
90        HeaderValue::from_maybe_shared(value).map_err(|_| InvalidMetadataValueBytes::new())
91    }
92
93    fn from_static(value: &'static str) -> HeaderValue {
94        HeaderValue::from_static(value)
95    }
96
97    fn decode(value: &[u8]) -> Result<Bytes, InvalidMetadataValueBytes> {
98        Ok(Bytes::copy_from_slice(value))
99    }
100
101    fn equals(a: &HeaderValue, b: &[u8]) -> bool {
102        a.as_bytes() == b
103    }
104
105    fn values_equal(a: &HeaderValue, b: &HeaderValue) -> bool {
106        a == b
107    }
108
109    fn fmt(value: &HeaderValue, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110        fmt::Debug::fmt(value, f)
111    }
112}
113
114impl ValueEncoding for Ascii {
115    fn is_valid_key(key: &str) -> bool {
116        !Binary::is_valid_key(key)
117    }
118}
119
120impl self::value_encoding::Sealed for Binary {
121    fn is_empty(value: &[u8]) -> bool {
122        for c in value {
123            if *c != b'=' {
124                return false;
125            }
126        }
127        true
128    }
129
130    fn from_bytes(value: &[u8]) -> Result<HeaderValue, InvalidMetadataValueBytes> {
131        let encoded_value: String = crate::util::base64::STANDARD_NO_PAD.encode(value);
132        HeaderValue::from_maybe_shared(Bytes::from(encoded_value))
133            .map_err(|_| InvalidMetadataValueBytes::new())
134    }
135
136    fn from_shared(value: Bytes) -> Result<HeaderValue, InvalidMetadataValueBytes> {
137        Self::from_bytes(value.as_ref())
138    }
139
140    fn from_static(value: &'static str) -> HeaderValue {
141        if crate::util::base64::STANDARD.decode(value).is_err() {
142            panic!("Invalid base64 passed to from_static: {}", value);
143        }
144        unsafe {
145            // Because this is valid base64 this must be a valid HTTP header value,
146            // no need to check again by calling from_shared.
147            HeaderValue::from_maybe_shared_unchecked(Bytes::from_static(value.as_ref()))
148        }
149    }
150
151    fn decode(value: &[u8]) -> Result<Bytes, InvalidMetadataValueBytes> {
152        crate::util::base64::STANDARD
153            .decode(value)
154            .map(|bytes_vec| bytes_vec.into())
155            .map_err(|_| InvalidMetadataValueBytes::new())
156    }
157
158    fn equals(a: &HeaderValue, b: &[u8]) -> bool {
159        if let Ok(decoded) = crate::util::base64::STANDARD.decode(a.as_bytes()) {
160            decoded == b
161        } else {
162            a.as_bytes() == b
163        }
164    }
165
166    fn values_equal(a: &HeaderValue, b: &HeaderValue) -> bool {
167        match (Self::decode(a.as_bytes()), Self::decode(b.as_bytes())) {
168            (Ok(a), Ok(b)) => a == b,
169            (Err(_), Err(_)) => true,
170            _ => false,
171        }
172    }
173
174    fn fmt(value: &HeaderValue, f: &mut fmt::Formatter<'_>) -> fmt::Result {
175        if let Ok(decoded) = Self::decode(value.as_bytes()) {
176            write!(f, "{:?}", decoded)
177        } else {
178            write!(f, "b[invalid]{:?}", value)
179        }
180    }
181}
182
183impl ValueEncoding for Binary {
184    fn is_valid_key(key: &str) -> bool {
185        key.ends_with("-bin")
186    }
187}
188
189// ===== impl InvalidMetadataValue =====
190
191impl InvalidMetadataValue {
192    pub(crate) fn new() -> Self {
193        InvalidMetadataValue { _priv: () }
194    }
195}
196
197impl fmt::Display for InvalidMetadataValue {
198    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199        f.write_str("failed to parse metadata value")
200    }
201}
202
203impl Error for InvalidMetadataValue {}
204
205/// A possible error when converting a `MetadataValue` from a string or byte
206/// slice.
207#[derive(Debug, Hash)]
208pub struct InvalidMetadataValueBytes(InvalidMetadataValue);
209
210// ===== impl InvalidMetadataValueBytes =====
211
212impl InvalidMetadataValueBytes {
213    pub(crate) fn new() -> Self {
214        InvalidMetadataValueBytes(InvalidMetadataValue::new())
215    }
216}
217
218impl fmt::Display for InvalidMetadataValueBytes {
219    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
220        self.0.fmt(f)
221    }
222}
223
224impl Error for InvalidMetadataValueBytes {}