1use crate::{Context, Key, KeyValue, StringValue};
22use std::collections::hash_map::Entry;
23use std::collections::{hash_map, HashMap};
24use std::fmt;
25use std::sync::OnceLock;
26
27static DEFAULT_BAGGAGE: OnceLock<Baggage> = OnceLock::new();
28
29const MAX_KEY_VALUE_PAIRS: usize = 64;
30const MAX_LEN_OF_ALL_PAIRS: usize = 8192;
31
32const INVALID_ASCII_KEY_CHARS: [u8; 17] = [
34 b'(', b')', b',', b'/', b':', b';', b'<', b'=', b'>', b'?', b'@', b'[', b'\\', b']', b'{',
35 b'}', b'"',
36];
37
38#[inline]
40fn get_default_baggage() -> &'static Baggage {
41 DEFAULT_BAGGAGE.get_or_init(Baggage::default)
42}
43
44#[derive(Debug, Default)]
67pub struct Baggage {
68 inner: HashMap<Key, (StringValue, BaggageMetadata)>,
69 kv_content_len: usize, }
71
72impl Baggage {
73 pub fn new() -> Self {
75 Baggage {
76 inner: HashMap::default(),
77 kv_content_len: 0,
78 }
79 }
80
81 pub fn get<K: AsRef<str>>(&self, key: K) -> Option<&StringValue> {
94 self.inner.get(key.as_ref()).map(|(value, _metadata)| value)
95 }
96
97 pub fn get_with_metadata<K: AsRef<str>>(
110 &self,
111 key: K,
112 ) -> Option<&(StringValue, BaggageMetadata)> {
113 self.inner.get(key.as_ref())
114 }
115
116 pub fn insert<K, V>(&mut self, key: K, value: V) -> Option<StringValue>
132 where
133 K: Into<Key>,
134 V: Into<StringValue>,
135 {
136 self.insert_with_metadata(key, value, BaggageMetadata::default())
137 .map(|pair| pair.0)
138 }
139
140 pub fn insert_with_metadata<K, V, S>(
158 &mut self,
159 key: K,
160 value: V,
161 metadata: S,
162 ) -> Option<(StringValue, BaggageMetadata)>
163 where
164 K: Into<Key>,
165 V: Into<StringValue>,
166 S: Into<BaggageMetadata>,
167 {
168 let (key, value, metadata) = (key.into(), value.into(), metadata.into());
169 let entries_count = self.inner.len();
170 match self.inner.entry(key) {
171 Entry::Occupied(mut occupied_entry) => {
172 let key_str = occupied_entry.key().as_str();
173 let entry_content_len =
174 key_value_metadata_bytes_size(key_str, value.as_str(), metadata.as_str());
175 let prev_content_len = key_value_metadata_bytes_size(
176 key_str,
177 occupied_entry.get().0.as_str(),
178 occupied_entry.get().1.as_str(),
179 );
180 let new_content_len = self.kv_content_len + entry_content_len - prev_content_len;
181 if new_content_len > MAX_LEN_OF_ALL_PAIRS {
182 return None;
183 }
184 self.kv_content_len = new_content_len;
185 Some(occupied_entry.insert((value, metadata)))
186 }
187 Entry::Vacant(vacant_entry) => {
188 let key_str = vacant_entry.key().as_str();
189 if !Self::is_key_valid(key_str.as_bytes()) {
190 return None;
191 }
192 if entries_count == MAX_KEY_VALUE_PAIRS {
193 return None;
194 }
195 let entry_content_len =
196 key_value_metadata_bytes_size(key_str, value.as_str(), metadata.as_str());
197 let new_content_len = self.kv_content_len + entry_content_len;
198 if new_content_len > MAX_LEN_OF_ALL_PAIRS {
199 return None;
200 }
201 self.kv_content_len = new_content_len;
202 vacant_entry.insert((value, metadata));
203 None
204 }
205 }
206 }
207
208 pub fn remove<K: AsRef<str>>(&mut self, key: K) -> Option<(StringValue, BaggageMetadata)> {
211 self.inner.remove(key.as_ref())
212 }
213
214 pub fn len(&self) -> usize {
216 self.inner.len()
217 }
218
219 pub fn is_empty(&self) -> bool {
221 self.inner.is_empty()
222 }
223
224 pub fn iter(&self) -> Iter<'_> {
226 self.into_iter()
227 }
228
229 fn is_key_valid(key: &[u8]) -> bool {
230 !key.is_empty()
231 && key
232 .iter()
233 .all(|b| b.is_ascii_graphic() && !INVALID_ASCII_KEY_CHARS.contains(b))
234 }
235}
236
237fn key_value_metadata_bytes_size(key: &str, value: &str, metadata: &str) -> usize {
239 key.len() + value.len() + metadata.len()
240}
241
242#[derive(Debug)]
244pub struct Iter<'a>(hash_map::Iter<'a, Key, (StringValue, BaggageMetadata)>);
245
246impl<'a> Iterator for Iter<'a> {
247 type Item = (&'a Key, &'a (StringValue, BaggageMetadata));
248
249 fn next(&mut self) -> Option<Self::Item> {
250 self.0.next()
251 }
252}
253
254impl<'a> IntoIterator for &'a Baggage {
255 type Item = (&'a Key, &'a (StringValue, BaggageMetadata));
256 type IntoIter = Iter<'a>;
257
258 fn into_iter(self) -> Self::IntoIter {
259 Iter(self.inner.iter())
260 }
261}
262
263impl FromIterator<(Key, (StringValue, BaggageMetadata))> for Baggage {
264 fn from_iter<I: IntoIterator<Item = (Key, (StringValue, BaggageMetadata))>>(iter: I) -> Self {
265 let mut baggage = Baggage::default();
266 for (key, (value, metadata)) in iter.into_iter() {
267 baggage.insert_with_metadata(key, value, metadata);
268 }
269 baggage
270 }
271}
272
273impl FromIterator<KeyValue> for Baggage {
274 fn from_iter<I: IntoIterator<Item = KeyValue>>(iter: I) -> Self {
275 let mut baggage = Baggage::default();
276 for kv in iter.into_iter() {
277 baggage.insert(kv.key, kv.value);
278 }
279 baggage
280 }
281}
282
283impl FromIterator<KeyValueMetadata> for Baggage {
284 fn from_iter<I: IntoIterator<Item = KeyValueMetadata>>(iter: I) -> Self {
285 let mut baggage = Baggage::default();
286 for kvm in iter.into_iter() {
287 baggage.insert_with_metadata(kvm.key, kvm.value, kvm.metadata);
288 }
289 baggage
290 }
291}
292
293impl<I> From<I> for Baggage
294where
295 I: IntoIterator,
296 I::Item: Into<KeyValueMetadata>,
297{
298 fn from(value: I) -> Self {
299 value.into_iter().map(Into::into).collect()
300 }
301}
302
303fn encode(s: &str) -> String {
304 let mut encoded_string = String::with_capacity(s.len());
305
306 for byte in s.as_bytes() {
307 match *byte {
308 b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'.' | b'-' | b'_' | b'~' => {
309 encoded_string.push(*byte as char)
310 }
311 b' ' => encoded_string.push_str("%20"),
312 _ => encoded_string.push_str(&format!("%{:02X}", byte)),
313 }
314 }
315 encoded_string
316}
317
318impl fmt::Display for Baggage {
319 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
320 for (i, (k, v)) in self.into_iter().enumerate() {
321 write!(f, "{}={}", k, encode(v.0.as_str()))?;
322 if !v.1.as_str().is_empty() {
323 write!(f, ";{}", v.1)?;
324 }
325
326 if i < self.len() - 1 {
327 write!(f, ",")?;
328 }
329 }
330
331 Ok(())
332 }
333}
334
335pub trait BaggageExt {
337 fn with_baggage<T: Into<Baggage>>(&self, baggage: T) -> Self;
363
364 fn current_with_baggage<T: Into<Baggage>>(baggage: T) -> Self;
382
383 fn with_cleared_baggage(&self) -> Self;
395
396 fn baggage(&self) -> &Baggage;
399}
400
401#[derive(Debug)]
403struct BaggageContextValue(Baggage);
404
405impl BaggageExt for Context {
406 fn with_baggage<T: Into<Baggage>>(&self, baggage: T) -> Self {
407 self.with_value(BaggageContextValue(baggage.into()))
408 }
409
410 fn current_with_baggage<T: Into<Baggage>>(baggage: T) -> Self {
411 Context::map_current(|cx| cx.with_baggage(baggage))
412 }
413
414 fn with_cleared_baggage(&self) -> Self {
415 self.with_value(Baggage::new())
416 }
417
418 fn baggage(&self) -> &Baggage {
419 self.get::<BaggageContextValue>()
420 .map_or(get_default_baggage(), |b| &b.0)
421 }
422}
423
424#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Default)]
430pub struct BaggageMetadata(String);
431
432impl BaggageMetadata {
433 pub fn as_str(&self) -> &str {
435 self.0.as_str()
436 }
437}
438
439impl From<String> for BaggageMetadata {
440 fn from(s: String) -> BaggageMetadata {
441 BaggageMetadata(s.trim().to_string())
442 }
443}
444
445impl From<&str> for BaggageMetadata {
446 fn from(s: &str) -> Self {
447 BaggageMetadata(s.trim().to_string())
448 }
449}
450
451impl fmt::Display for BaggageMetadata {
452 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
453 Ok(write!(f, "{}", self.as_str())?)
454 }
455}
456
457#[derive(Clone, Debug, PartialEq)]
459pub struct KeyValueMetadata {
460 pub(crate) key: Key,
462 pub(crate) value: StringValue,
464 pub(crate) metadata: BaggageMetadata,
466}
467
468impl KeyValueMetadata {
469 pub fn new<K, V, S>(key: K, value: V, metadata: S) -> Self
471 where
472 K: Into<Key>,
473 V: Into<StringValue>,
474 S: Into<BaggageMetadata>,
475 {
476 KeyValueMetadata {
477 key: key.into(),
478 value: value.into(),
479 metadata: metadata.into(),
480 }
481 }
482}
483
484impl From<KeyValue> for KeyValueMetadata {
485 fn from(kv: KeyValue) -> Self {
486 KeyValueMetadata {
487 key: kv.key,
488 value: kv.value.into(),
489 metadata: BaggageMetadata::default(),
490 }
491 }
492}
493
494#[cfg(test)]
495mod tests {
496 use crate::StringValue;
497
498 use super::*;
499
500 #[test]
501 fn insert_non_ascii_key() {
502 let mut baggage = Baggage::new();
503 baggage.insert("🚫", "not ascii key");
504 assert_eq!(baggage.len(), 0, "did not insert invalid key");
505 }
506
507 #[test]
508 fn test_ascii_values() {
509 let string1 = "test_ 123";
510 let string2 = "Hello123";
511 let string3 = "This & That = More";
512 let string4 = "Unicode: 😊";
513 let string5 = "Non-ASCII: áéÃóú";
514 let string6 = "Unsafe: ~!@#$%^&*()_+{}[];:'\\\"<>?,./";
515 let string7: &str = "🚀Unicode:";
516 let string8 = "ΑΒΓ";
517
518 assert_eq!(encode(string1), "test_%20123");
519 assert_eq!(encode(string2), "Hello123");
520 assert_eq!(encode(string3), "This%20%26%20That%20%3D%20More");
521 assert_eq!(encode(string4), "Unicode%3A%20%F0%9F%98%8A");
522 assert_eq!(
523 encode(string5),
524 "Non-ASCII%3A%20%C3%A1%C3%A9%C3%AD%C3%B3%C3%BA"
525 );
526 assert_eq!(encode(string6), "Unsafe%3A%20~%21%40%23%24%25%5E%26%2A%28%29_%2B%7B%7D%5B%5D%3B%3A%27%5C%22%3C%3E%3F%2C.%2F");
527 assert_eq!(encode(string7), "%F0%9F%9A%80Unicode%3A");
528 assert_eq!(encode(string8), "%CE%91%CE%92%CE%93");
529 }
530
531 #[test]
532 fn insert_too_much_baggage() {
533 let over_limit = MAX_KEY_VALUE_PAIRS + 1;
535 let mut data = Vec::with_capacity(over_limit);
536 for i in 0..over_limit {
537 data.push(KeyValue::new(format!("key{i}"), format!("key{i}")))
538 }
539 let baggage = data.into_iter().collect::<Baggage>();
540 assert_eq!(baggage.len(), MAX_KEY_VALUE_PAIRS)
541 }
542
543 #[test]
544 fn insert_pairs_length_exceed() {
545 let mut data = vec![];
546 for letter in vec!['a', 'b', 'c', 'd'].into_iter() {
547 data.push(KeyValue::new(
548 (0..MAX_LEN_OF_ALL_PAIRS / 3)
549 .map(|_| letter)
550 .collect::<String>(),
551 "",
552 ));
553 }
554 let baggage = data.into_iter().collect::<Baggage>();
555 assert_eq!(baggage.len(), 3)
556 }
557
558 #[test]
559 fn serialize_baggage_as_string() {
560 let b = Baggage::default();
562 assert_eq!("", b.to_string());
563
564 let mut b = Baggage::default();
566 b.insert("foo", StringValue::from(""));
567 assert_eq!("foo=", b.to_string());
568
569 let mut b = Baggage::default();
571 b.insert("foo", StringValue::from("1"));
572 assert_eq!("foo=1", b.to_string());
573
574 let mut b = Baggage::default();
576 b.insert("foo", StringValue::from("1=1"));
577 assert_eq!("foo=1%3D1", b.to_string());
578
579 let mut b = Baggage::default();
581 b.insert_with_metadata(
582 "foo",
583 StringValue::from(""),
584 BaggageMetadata::from("red;state=on"),
585 );
586 assert_eq!("foo=;red;state=on", b.to_string());
587
588 let mut b = Baggage::default();
590 b.insert_with_metadata("foo", StringValue::from("1"), "red;state=on;z=z=z");
591 assert_eq!("foo=1;red;state=on;z=z=z", b.to_string());
592
593 let mut b = Baggage::default();
595 b.insert_with_metadata("foo", StringValue::from("1"), "red;state=on");
596 b.insert_with_metadata("bar", StringValue::from("2"), "yellow");
597 assert!(b.to_string().contains("bar=2;yellow"));
598 assert!(b.to_string().contains("foo=1;red;state=on"));
599 }
600
601 #[test]
602 fn replace_existing_key() {
603 let half_minus2: StringValue = (0..MAX_LEN_OF_ALL_PAIRS / 2 - 2)
604 .map(|_| 'x')
605 .collect::<String>()
606 .into();
607
608 let mut b = Baggage::default();
609 b.insert("a", half_minus2.clone()); b.insert("b", half_minus2); b.insert("c", StringValue::from(".")); assert!(b.get("a").is_some());
613 assert!(b.get("b").is_some());
614 assert!(b.get("c").is_some());
615 assert!(b.insert("c", StringValue::from("..")).is_none()); assert_eq!(b.insert("c", StringValue::from("!")).unwrap(), ".".into()); }
618
619 #[test]
620 fn test_crud_operations() {
621 let mut baggage = Baggage::default();
622 assert!(baggage.is_empty());
623
624 baggage.insert("foo", "1");
626 assert_eq!(baggage.len(), 1);
627
628 assert_eq!(baggage.get("foo"), Some(&StringValue::from("1")));
630
631 baggage.insert("foo", "2");
633 assert_eq!(baggage.get("foo"), Some(&StringValue::from("2")));
634
635 baggage.remove("foo");
637 assert!(baggage.is_empty());
638 }
639
640 #[test]
641 fn test_insert_invalid_key() {
642 let mut baggage = Baggage::default();
643
644 baggage.insert("", "1");
646 assert!(baggage.is_empty());
647
648 baggage.insert("Grüße", "1");
650 assert!(baggage.is_empty());
651
652 baggage.insert("(example)", "1");
654 assert!(baggage.is_empty());
655 }
656}