wtransport_proto/
headers.rs1use crate::error::ErrorCode;
2use crate::frame::Frame;
3use crate::frame::FrameKind;
4use crate::qpack::Decoder;
5use crate::qpack::Encoder;
6use std::borrow::Cow;
7use std::collections::HashMap;
8
9#[derive(Debug)]
11pub struct Headers(HashMap<String, String>);
12
13impl Headers {
14 pub fn with_frame(frame: &Frame) -> Result<Self, ErrorCode> {
20 assert!(matches!(frame.kind(), FrameKind::Headers));
21
22 let headers = Decoder::decode(frame.payload()).map_err(|_| ErrorCode::Decompression)?;
23
24 Ok(Self(headers))
25 }
26
27 pub fn generate_frame(&self) -> Frame<'static> {
29 let headers = self.sorted_headers();
30 let payload = Encoder::encode(headers);
31 Frame::new_headers(Cow::Owned(payload.to_vec()))
32 }
33
34 pub fn get<K>(&self, key: K) -> Option<&str>
36 where
37 K: AsRef<str>,
38 {
39 self.0.get(key.as_ref()).map(|s| s.as_str())
40 }
41
42 pub fn insert<K, V>(&mut self, key: K, value: V)
46 where
47 K: ToString,
48 V: ToString,
49 {
50 self.0.insert(key.to_string(), value.to_string());
51 }
52
53 fn sorted_headers(&self) -> Vec<(&str, &str)> {
54 let mut headers = self
55 .0
56 .iter()
57 .map(|(k, v)| (k.as_str(), v.as_str()))
58 .collect::<Vec<_>>();
59
60 headers.sort_by_key(|(name, _)| (!name.starts_with(':'), *name));
61
62 headers
63 }
64}
65
66impl<K, V> FromIterator<(K, V)> for Headers
67where
68 K: ToString,
69 V: ToString,
70{
71 fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
72 Self(
73 iter.into_iter()
74 .map(|(k, v)| (k.to_string(), v.to_string()))
75 .collect(),
76 )
77 }
78}
79
80impl AsRef<HashMap<String, String>> for Headers {
81 fn as_ref(&self) -> &HashMap<String, String> {
82 &self.0
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 #[test]
91 fn generate_frame_kind() {
92 let headers = [("key1", "value1"), ("key2", "value2")]
93 .into_iter()
94 .collect::<Headers>();
95
96 let frame = headers.generate_frame();
97 assert!(matches!(frame.kind(), FrameKind::Headers));
98 }
99
100 #[test]
101 fn get() {
102 let headers = [("key1", "value1"), ("key2", "value2")]
103 .into_iter()
104 .collect::<Headers>();
105
106 assert_eq!(headers.get("key1"), Some("value1"));
107 assert_eq!(headers.get("key2"), Some("value2"));
108 assert_eq!(headers.get("key3"), None);
109 }
110
111 #[test]
112 fn insert() {
113 let mut headers = [("key1", "value1"), ("key2", "value2")]
114 .into_iter()
115 .collect::<Headers>();
116
117 assert_eq!(headers.get("key1"), Some("value1"));
118 headers.insert("key1", "value1bis");
119 assert_eq!(headers.get("key1"), Some("value1bis"));
120
121 assert_eq!(headers.get("key3"), None);
122 headers.insert("key3", "value3");
123 assert_eq!(headers.get("key3"), Some("value3"));
124 }
125
126 #[test]
127 fn idempotence() {
128 let headers = [("key1", "value1"), ("key2", "value2")]
129 .into_iter()
130 .collect::<Headers>();
131
132 let frame = headers.generate_frame();
133
134 assert_eq!(
135 headers.as_ref(),
136 Headers::with_frame(&frame).unwrap().as_ref()
137 );
138 }
139}