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#[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 fn is_valid_key(key: &str) -> bool;
53}
54
55#[derive(Clone, Debug, Eq, PartialEq, Hash)]
64#[non_exhaustive]
65pub enum Ascii {}
66
67#[derive(Clone, Debug, Eq, PartialEq, Hash)]
75#[non_exhaustive]
76pub enum Binary {}
77
78impl 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 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
189impl 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#[derive(Debug, Hash)]
208pub struct InvalidMetadataValueBytes(InvalidMetadataValue);
209
210impl 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 {}