tonic/metadata/
encoding.rs

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