1use crate::{Context, Key, KeyValue, Value};
18use once_cell::sync::Lazy;
19use std::collections::{hash_map, HashMap};
20use std::fmt;
21
22static DEFAULT_BAGGAGE: Lazy<Baggage> = Lazy::new(Baggage::default);
23
24const MAX_KEY_VALUE_PAIRS: usize = 180;
25const MAX_BYTES_FOR_ONE_PAIR: usize = 4096;
26const MAX_LEN_OF_ALL_PAIRS: usize = 8192;
27
28#[derive(Debug, Default)]
52pub struct Baggage {
53 inner: HashMap<Key, (Value, BaggageMetadata)>,
54 kv_content_len: usize, }
56
57impl Baggage {
58 pub fn new() -> Self {
60 Baggage {
61 inner: HashMap::default(),
62 kv_content_len: 0,
63 }
64 }
65
66 pub fn get<K: AsRef<str>>(&self, key: K) -> Option<&Value> {
79 self.inner.get(key.as_ref()).map(|(value, _metadata)| value)
80 }
81
82 pub fn get_with_metadata<K: AsRef<str>>(&self, key: K) -> Option<&(Value, BaggageMetadata)> {
95 self.inner.get(key.as_ref())
96 }
97
98 pub fn insert<K, V>(&mut self, key: K, value: V) -> Option<Value>
114 where
115 K: Into<Key>,
116 V: Into<Value>,
117 {
118 self.insert_with_metadata(key, value, BaggageMetadata::default())
119 .map(|pair| pair.0)
120 }
121
122 pub fn insert_with_metadata<K, V, S>(
138 &mut self,
139 key: K,
140 value: V,
141 metadata: S,
142 ) -> Option<(Value, BaggageMetadata)>
143 where
144 K: Into<Key>,
145 V: Into<Value>,
146 S: Into<BaggageMetadata>,
147 {
148 let (key, value, metadata) = (key.into(), value.into(), metadata.into());
149 if self.insertable(&key, &value, &metadata) {
150 self.inner.insert(key, (value, metadata))
151 } else {
152 None
153 }
154 }
155
156 pub fn remove<K: Into<Key>>(&mut self, key: K) -> Option<(Value, BaggageMetadata)> {
159 self.inner.remove(&key.into())
160 }
161
162 pub fn len(&self) -> usize {
164 self.inner.len()
165 }
166
167 pub fn is_empty(&self) -> bool {
169 self.inner.is_empty()
170 }
171
172 pub fn iter(&self) -> Iter<'_> {
174 self.into_iter()
175 }
176
177 fn insertable(&mut self, key: &Key, value: &Value, metadata: &BaggageMetadata) -> bool {
180 if !key.as_str().is_ascii() {
181 return false;
182 }
183 let value = value.as_str();
184 if key_value_metadata_bytes_size(key.as_str(), value.as_ref(), metadata.as_str())
185 < MAX_BYTES_FOR_ONE_PAIR
186 {
187 match self.inner.get(key) {
188 None => {
189 if self.kv_content_len
191 + metadata.as_str().len()
192 + value.len()
193 + key.as_str().len()
194 > MAX_LEN_OF_ALL_PAIRS
195 {
196 return false;
197 }
198 if self.inner.len() + 1 > MAX_KEY_VALUE_PAIRS {
200 return false;
201 }
202 self.kv_content_len +=
203 metadata.as_str().len() + value.len() + key.as_str().len()
204 }
205 Some((old_value, old_metadata)) => {
206 let old_value = old_value.as_str();
207 if self.kv_content_len - old_metadata.as_str().len() - old_value.len()
208 + metadata.as_str().len()
209 + value.len()
210 > MAX_LEN_OF_ALL_PAIRS
211 {
212 return false;
213 }
214 self.kv_content_len =
215 self.kv_content_len - old_metadata.as_str().len() - old_value.len()
216 + metadata.as_str().len()
217 + value.len()
218 }
219 }
220 true
221 } else {
222 false
223 }
224 }
225}
226
227fn key_value_metadata_bytes_size(key: &str, value: &str, metadata: &str) -> usize {
229 key.bytes().len() + value.bytes().len() + metadata.bytes().len()
230}
231
232#[derive(Debug)]
234pub struct Iter<'a>(hash_map::Iter<'a, Key, (Value, BaggageMetadata)>);
235
236impl<'a> Iterator for Iter<'a> {
237 type Item = (&'a Key, &'a (Value, BaggageMetadata));
238
239 fn next(&mut self) -> Option<Self::Item> {
240 self.0.next()
241 }
242}
243
244impl<'a> IntoIterator for &'a Baggage {
245 type Item = (&'a Key, &'a (Value, BaggageMetadata));
246 type IntoIter = Iter<'a>;
247
248 fn into_iter(self) -> Self::IntoIter {
249 Iter(self.inner.iter())
250 }
251}
252
253impl FromIterator<(Key, (Value, BaggageMetadata))> for Baggage {
254 fn from_iter<I: IntoIterator<Item = (Key, (Value, BaggageMetadata))>>(iter: I) -> Self {
255 let mut baggage = Baggage::default();
256 for (key, (value, metadata)) in iter.into_iter() {
257 baggage.insert_with_metadata(key, value, metadata);
258 }
259 baggage
260 }
261}
262
263impl FromIterator<KeyValue> for Baggage {
264 fn from_iter<I: IntoIterator<Item = KeyValue>>(iter: I) -> Self {
265 let mut baggage = Baggage::default();
266 for kv in iter.into_iter() {
267 baggage.insert(kv.key, kv.value);
268 }
269 baggage
270 }
271}
272
273impl FromIterator<KeyValueMetadata> for Baggage {
274 fn from_iter<I: IntoIterator<Item = KeyValueMetadata>>(iter: I) -> Self {
275 let mut baggage = Baggage::default();
276 for kvm in iter.into_iter() {
277 baggage.insert_with_metadata(kvm.key, kvm.value, kvm.metadata);
278 }
279 baggage
280 }
281}
282
283fn encode(s: &str) -> String {
284 let mut encoded_string = String::with_capacity(s.len());
285
286 for byte in s.as_bytes() {
287 match *byte {
288 b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'.' | b'-' | b'_' | b'~' => {
289 encoded_string.push(*byte as char)
290 }
291 b' ' => encoded_string.push_str("%20"),
292 _ => encoded_string.push_str(&format!("%{:02X}", byte)),
293 }
294 }
295 encoded_string
296}
297
298impl fmt::Display for Baggage {
299 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
300 for (i, (k, v)) in self.into_iter().enumerate() {
301 write!(f, "{}={}", k, encode(v.0.as_str().as_ref()))?;
302 if !v.1.as_str().is_empty() {
303 write!(f, ";{}", v.1)?;
304 }
305
306 if i < self.len() - 1 {
307 write!(f, ",")?;
308 }
309 }
310
311 Ok(())
312 }
313}
314
315pub trait BaggageExt {
317 fn with_baggage<T: IntoIterator<Item = I>, I: Into<KeyValueMetadata>>(
334 &self,
335 baggage: T,
336 ) -> Self;
337
338 fn current_with_baggage<T: IntoIterator<Item = I>, I: Into<KeyValueMetadata>>(
353 baggage: T,
354 ) -> Self;
355
356 fn with_cleared_baggage(&self) -> Self;
368
369 fn baggage(&self) -> &Baggage;
372}
373
374impl BaggageExt for Context {
375 fn with_baggage<T: IntoIterator<Item = I>, I: Into<KeyValueMetadata>>(
376 &self,
377 baggage: T,
378 ) -> Self {
379 let mut merged: Baggage = self
380 .baggage()
381 .iter()
382 .map(|(key, (value, metadata))| {
383 KeyValueMetadata::new(key.clone(), value.clone(), metadata.clone())
384 })
385 .collect();
386 for kvm in baggage.into_iter().map(|kv| kv.into()) {
387 merged.insert_with_metadata(kvm.key, kvm.value, kvm.metadata);
388 }
389
390 self.with_value(merged)
391 }
392
393 fn current_with_baggage<T: IntoIterator<Item = I>, I: Into<KeyValueMetadata>>(kvs: T) -> Self {
394 Context::map_current(|cx| cx.with_baggage(kvs))
395 }
396
397 fn with_cleared_baggage(&self) -> Self {
398 self.with_value(Baggage::new())
399 }
400
401 fn baggage(&self) -> &Baggage {
402 self.get::<Baggage>().unwrap_or(&DEFAULT_BAGGAGE)
403 }
404}
405
406#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Default)]
412pub struct BaggageMetadata(String);
413
414impl BaggageMetadata {
415 pub fn as_str(&self) -> &str {
417 self.0.as_str()
418 }
419}
420
421impl From<String> for BaggageMetadata {
422 fn from(s: String) -> BaggageMetadata {
423 BaggageMetadata(s.trim().to_string())
424 }
425}
426
427impl From<&str> for BaggageMetadata {
428 fn from(s: &str) -> Self {
429 BaggageMetadata(s.trim().to_string())
430 }
431}
432
433impl fmt::Display for BaggageMetadata {
434 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
435 Ok(write!(f, "{}", self.as_str())?)
436 }
437}
438
439#[derive(Clone, Debug, PartialEq)]
441pub struct KeyValueMetadata {
442 pub key: Key,
444 pub value: Value,
446 pub metadata: BaggageMetadata,
448}
449
450impl KeyValueMetadata {
451 pub fn new<K, V, S>(key: K, value: V, metadata: S) -> Self
453 where
454 K: Into<Key>,
455 V: Into<Value>,
456 S: Into<BaggageMetadata>,
457 {
458 KeyValueMetadata {
459 key: key.into(),
460 value: value.into(),
461 metadata: metadata.into(),
462 }
463 }
464}
465
466impl From<KeyValue> for KeyValueMetadata {
467 fn from(kv: KeyValue) -> Self {
468 KeyValueMetadata {
469 key: kv.key,
470 value: kv.value,
471 metadata: BaggageMetadata::default(),
472 }
473 }
474}
475
476#[cfg(test)]
477mod tests {
478 use crate::StringValue;
479
480 use super::*;
481
482 #[test]
483 fn insert_non_ascii_key() {
484 let mut baggage = Baggage::new();
485 baggage.insert("🚫", "not ascii key");
486 assert_eq!(baggage.len(), 0, "did not insert invalid key");
487 }
488
489 #[test]
490 fn test_ascii_values() {
491 let string1 = "test_ 123";
492 let string2 = "Hello123";
493 let string3 = "This & That = More";
494 let string4 = "Unicode: 😊";
495 let string5 = "Non-ASCII: áéíóú";
496 let string6 = "Unsafe: ~!@#$%^&*()_+{}[];:'\\\"<>?,./";
497 let string7: &str = "🚀Unicode:";
498 let string8 = "ΑΒΓ";
499
500 assert_eq!(encode(string1), "test_%20123");
501 assert_eq!(encode(string2), "Hello123");
502 assert_eq!(encode(string3), "This%20%26%20That%20%3D%20More");
503 assert_eq!(encode(string4), "Unicode%3A%20%F0%9F%98%8A");
504 assert_eq!(
505 encode(string5),
506 "Non-ASCII%3A%20%C3%A1%C3%A9%C3%AD%C3%B3%C3%BA"
507 );
508 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");
509 assert_eq!(encode(string7), "%F0%9F%9A%80Unicode%3A");
510 assert_eq!(encode(string8), "%CE%91%CE%92%CE%93");
511 }
512
513 #[test]
514 fn insert_too_much_baggage() {
515 let over_limit = MAX_KEY_VALUE_PAIRS + 1;
517 let mut data = Vec::with_capacity(over_limit);
518 for i in 0..over_limit {
519 data.push(KeyValue::new(format!("key{i}"), format!("key{i}")))
520 }
521 let baggage = data.into_iter().collect::<Baggage>();
522 assert_eq!(baggage.len(), MAX_KEY_VALUE_PAIRS)
523 }
524
525 #[test]
526 fn insert_too_long_pair() {
527 let pair = KeyValue::new(
528 "test",
529 String::from_utf8_lossy(vec![12u8; MAX_BYTES_FOR_ONE_PAIR].as_slice()).to_string(),
530 );
531 let mut baggage = Baggage::default();
532 baggage.insert(pair.key.clone(), pair.value.clone());
533 assert_eq!(
534 baggage.len(),
535 0,
536 "The input pair is too long to insert into baggage"
537 );
538
539 baggage.insert("test", "value");
540 baggage.insert(pair.key.clone(), pair.value);
541 assert_eq!(
542 baggage.get(pair.key),
543 Some(&Value::from("value")),
544 "If the input pair is too long, then don't replace entry with same key"
545 )
546 }
547
548 #[test]
549 fn insert_pairs_length_exceed() {
550 let mut data = vec![];
551 for letter in vec!['a', 'b', 'c', 'd'].into_iter() {
552 data.push(KeyValue::new(
553 (0..MAX_LEN_OF_ALL_PAIRS / 3)
554 .map(|_| letter)
555 .collect::<String>(),
556 "",
557 ));
558 }
559 let baggage = data.into_iter().collect::<Baggage>();
560 assert_eq!(baggage.len(), 3)
561 }
562
563 #[test]
564 fn serialize_baggage_as_string() {
565 let b = Baggage::default();
567 assert_eq!("", b.to_string());
568
569 let mut b = Baggage::default();
571 b.insert("foo", StringValue::from(""));
572 assert_eq!("foo=", b.to_string());
573
574 let mut b = Baggage::default();
576 b.insert("foo", StringValue::from("1"));
577 assert_eq!("foo=1", b.to_string());
578
579 let mut b = Baggage::default();
581 b.insert("foo", StringValue::from("1=1"));
582 assert_eq!("foo=1%3D1", b.to_string());
583
584 let mut b = Baggage::default();
586 b.insert_with_metadata(
587 "foo",
588 StringValue::from(""),
589 BaggageMetadata::from("red;state=on"),
590 );
591 assert_eq!("foo=;red;state=on", b.to_string());
592
593 let mut b = Baggage::default();
595 b.insert_with_metadata("foo", StringValue::from("1"), "red;state=on;z=z=z");
596 assert_eq!("foo=1;red;state=on;z=z=z", b.to_string());
597
598 let mut b = Baggage::default();
600 b.insert_with_metadata("foo", StringValue::from("1"), "red;state=on");
601 b.insert_with_metadata("bar", StringValue::from("2"), "yellow");
602 assert!(b.to_string().contains("bar=2;yellow"));
603 assert!(b.to_string().contains("foo=1;red;state=on"));
604 }
605}