tonic/metadata/
encoding.rs1use base64::Engine as _;
26use bytes::Bytes;
27use http::header::HeaderValue;
28use std::error::Error;
29use std::fmt;
30use std::hash::Hash;
31
32#[derive(Debug, Hash)]
35pub struct InvalidMetadataValue {
36 _priv: (),
37}
38
39mod value_encoding {
40 use super::InvalidMetadataValueBytes;
41 use bytes::Bytes;
42 use http::header::HeaderValue;
43 use std::fmt;
44
45 pub trait Sealed {
46 #[doc(hidden)]
47 fn is_empty(value: &[u8]) -> bool;
48
49 #[doc(hidden)]
50 fn from_bytes(value: &[u8]) -> Result<HeaderValue, InvalidMetadataValueBytes>;
51
52 #[doc(hidden)]
53 fn from_shared(value: Bytes) -> Result<HeaderValue, InvalidMetadataValueBytes>;
54
55 #[doc(hidden)]
56 fn from_static(value: &'static str) -> HeaderValue;
57
58 #[doc(hidden)]
59 fn decode(value: &[u8]) -> Result<Bytes, InvalidMetadataValueBytes>;
60
61 #[doc(hidden)]
62 fn equals(a: &HeaderValue, b: &[u8]) -> bool;
63
64 #[doc(hidden)]
65 fn values_equal(a: &HeaderValue, b: &HeaderValue) -> bool;
66
67 #[doc(hidden)]
68 fn fmt(value: &HeaderValue, f: &mut fmt::Formatter<'_>) -> fmt::Result;
69 }
70}
71
72pub trait ValueEncoding: Clone + Eq + PartialEq + Hash + self::value_encoding::Sealed {
73 fn is_valid_key(key: &str) -> bool;
77}
78
79#[derive(Clone, Debug, Eq, PartialEq, Hash)]
88#[non_exhaustive]
89pub enum Ascii {}
90
91#[derive(Clone, Debug, Eq, PartialEq, Hash)]
99#[non_exhaustive]
100pub enum Binary {}
101
102impl self::value_encoding::Sealed for Ascii {
105 fn is_empty(value: &[u8]) -> bool {
106 value.is_empty()
107 }
108
109 fn from_bytes(value: &[u8]) -> Result<HeaderValue, InvalidMetadataValueBytes> {
110 HeaderValue::from_bytes(value).map_err(|_| InvalidMetadataValueBytes::new())
111 }
112
113 fn from_shared(value: Bytes) -> Result<HeaderValue, InvalidMetadataValueBytes> {
114 HeaderValue::from_maybe_shared(value).map_err(|_| InvalidMetadataValueBytes::new())
115 }
116
117 fn from_static(value: &'static str) -> HeaderValue {
118 HeaderValue::from_static(value)
119 }
120
121 fn decode(value: &[u8]) -> Result<Bytes, InvalidMetadataValueBytes> {
122 Ok(Bytes::copy_from_slice(value))
123 }
124
125 fn equals(a: &HeaderValue, b: &[u8]) -> bool {
126 a.as_bytes() == b
127 }
128
129 fn values_equal(a: &HeaderValue, b: &HeaderValue) -> bool {
130 a == b
131 }
132
133 fn fmt(value: &HeaderValue, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134 fmt::Debug::fmt(value, f)
135 }
136}
137
138impl ValueEncoding for Ascii {
139 fn is_valid_key(key: &str) -> bool {
140 !Binary::is_valid_key(key)
141 }
142}
143
144impl self::value_encoding::Sealed for Binary {
145 fn is_empty(value: &[u8]) -> bool {
146 for c in value {
147 if *c != b'=' {
148 return false;
149 }
150 }
151 true
152 }
153
154 fn from_bytes(value: &[u8]) -> Result<HeaderValue, InvalidMetadataValueBytes> {
155 let encoded_value: String = crate::util::base64::STANDARD_NO_PAD.encode(value);
156 HeaderValue::from_maybe_shared(Bytes::from(encoded_value))
157 .map_err(|_| InvalidMetadataValueBytes::new())
158 }
159
160 fn from_shared(value: Bytes) -> Result<HeaderValue, InvalidMetadataValueBytes> {
161 Self::from_bytes(value.as_ref())
162 }
163
164 fn from_static(value: &'static str) -> HeaderValue {
165 if crate::util::base64::STANDARD.decode(value).is_err() {
166 panic!("Invalid base64 passed to from_static: {value}");
167 }
168 unsafe {
169 HeaderValue::from_maybe_shared_unchecked(Bytes::from_static(value.as_ref()))
172 }
173 }
174
175 fn decode(value: &[u8]) -> Result<Bytes, InvalidMetadataValueBytes> {
176 crate::util::base64::STANDARD
177 .decode(value)
178 .map(|bytes_vec| bytes_vec.into())
179 .map_err(|_| InvalidMetadataValueBytes::new())
180 }
181
182 fn equals(a: &HeaderValue, b: &[u8]) -> bool {
183 if let Ok(decoded) = crate::util::base64::STANDARD.decode(a.as_bytes()) {
184 decoded == b
185 } else {
186 a.as_bytes() == b
187 }
188 }
189
190 fn values_equal(a: &HeaderValue, b: &HeaderValue) -> bool {
191 match (Self::decode(a.as_bytes()), Self::decode(b.as_bytes())) {
192 (Ok(a), Ok(b)) => a == b,
193 (Err(_), Err(_)) => true,
194 _ => false,
195 }
196 }
197
198 fn fmt(value: &HeaderValue, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199 if let Ok(decoded) = Self::decode(value.as_bytes()) {
200 write!(f, "{decoded:?}")
201 } else {
202 write!(f, "b[invalid]{value:?}")
203 }
204 }
205}
206
207impl ValueEncoding for Binary {
208 fn is_valid_key(key: &str) -> bool {
209 key.ends_with("-bin")
210 }
211}
212
213impl InvalidMetadataValue {
216 pub(crate) fn new() -> Self {
217 InvalidMetadataValue { _priv: () }
218 }
219}
220
221impl fmt::Display for InvalidMetadataValue {
222 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
223 f.write_str("failed to parse metadata value")
224 }
225}
226
227impl Error for InvalidMetadataValue {}
228
229#[derive(Debug, Hash)]
232pub struct InvalidMetadataValueBytes(InvalidMetadataValue);
233
234impl InvalidMetadataValueBytes {
237 pub(crate) fn new() -> Self {
238 InvalidMetadataValueBytes(InvalidMetadataValue::new())
239 }
240}
241
242impl fmt::Display for InvalidMetadataValueBytes {
243 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244 self.0.fmt(f)
245 }
246}
247
248impl Error for InvalidMetadataValueBytes {}