1pub use encoder::encode_int;
30pub use encoder::encode_str;
31
32pub const INDEXED: u8 = 0b1000_0000;
33pub const INDEXED_WITH_POST_BASE: u8 = 0b0001_0000;
34pub const LITERAL: u8 = 0b0010_0000;
35pub const LITERAL_WITH_NAME_REF: u8 = 0b0100_0000;
36
37pub type Result<T> = std::result::Result<T, Error>;
44
45#[derive(Clone, Copy, Debug, PartialEq, Eq)]
47pub enum Error {
48 BufferTooShort,
50
51 InvalidHuffmanEncoding,
53
54 InvalidStaticTableIndex,
56
57 InvalidHeaderValue,
59
60 HeaderListTooLarge,
62}
63
64impl std::fmt::Display for Error {
65 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
66 write!(f, "{self:?}")
67 }
68}
69
70impl std::error::Error for Error {
71 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
72 None
73 }
74}
75
76impl From<octets::BufferTooShortError> for Error {
77 fn from(_err: octets::BufferTooShortError) -> Self {
78 Error::BufferTooShort
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use crate::h3::qpack::Error::HeaderListTooLarge;
85 use crate::*;
86
87 use super::*;
88
89 #[test]
90 fn encode_decode() {
91 let mut encoded = [0u8; 240];
92
93 let headers = vec![
94 h3::Header::new(b":path", b"/rsrc.php/v3/yn/r/rIPZ9Qkrdd9.png"),
95 h3::Header::new(b"accept-encoding", b"gzip, deflate, br"),
96 h3::Header::new(b"accept-language", b"en-US,en;q=0.9"),
97 h3::Header::new(b"user-agent", b"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.70 Safari/537.36"),
98 h3::Header::new(b"accept", b"image/webp,image/apng,image/*,*/*;q=0.8"),
99 h3::Header::new(b"referer", b"https://static.xx.fbcdn.net/rsrc.php/v3/yT/l/0,cross/dzXGESIlGQQ.css"),
100 h3::Header::new(b":authority", b"static.xx.fbcdn.net"),
101 h3::Header::new(b":scheme", b"https"),
102 h3::Header::new(b":method", b"GET"),
103 ];
104
105 let mut enc = Encoder::new();
106 assert_eq!(enc.encode(&headers, &mut encoded), Ok(240));
107
108 let mut dec = Decoder::new();
109 assert_eq!(dec.decode(&encoded, u64::MAX), Ok(headers));
110 }
111
112 #[test]
113 fn encode_decode_small_max_field_section_size() {
114 let mut encoded = [0u8; 102];
115
116 const NUM_HDRS: usize = 10;
117
118 let headers = vec![h3::Header::new(b"hello", b"world"); NUM_HDRS];
119
120 let qpack_field_section_size =
125 (b"hello".len() + b"world".len() + 32) * NUM_HDRS;
126
127 let mut enc = Encoder::new();
128 assert_eq!(enc.encode(&headers, &mut encoded), Ok(102));
129
130 let mut dec = Decoder::new();
131
132 assert_eq!(
134 dec.decode(&encoded, qpack_field_section_size as u64),
135 Ok(headers.clone())
136 );
137
138 assert_eq!(
140 dec.decode(&encoded, qpack_field_section_size as u64 + 1),
141 Ok(headers.clone())
142 );
143
144 let wrong_qpack_field_section_size =
146 (b"hello".len() + b"world".len()) * NUM_HDRS;
147 assert_eq!(
148 dec.decode(&encoded, wrong_qpack_field_section_size as u64),
149 Err(HeaderListTooLarge)
150 );
151 }
152
153 #[test]
154 fn lower_case() {
155 let mut encoded = [0u8; 35];
156
157 let headers_expected = vec![
158 h3::Header::new(b":status", b"200"),
159 h3::Header::new(b":path", b"/HeLlO"),
160 h3::Header::new(b"woot", b"woot"),
161 h3::Header::new(b"hello", b"WorlD"),
162 h3::Header::new(b"foo", b"BaR"),
163 ];
164
165 let headers_in = vec![
167 h3::Header::new(b":StAtUs", b"200"),
168 h3::Header::new(b":PaTh", b"/HeLlO"),
169 h3::Header::new(b"WooT", b"woot"),
170 h3::Header::new(b"hello", b"WorlD"),
171 h3::Header::new(b"fOo", b"BaR"),
172 ];
173
174 let mut enc = Encoder::new();
175 assert_eq!(enc.encode(&headers_in, &mut encoded), Ok(35));
176
177 let mut dec = Decoder::new();
178 let headers_out = dec.decode(&encoded, u64::MAX).unwrap();
179
180 assert_eq!(headers_expected, headers_out);
181
182 let headers_in = vec![
184 h3::HeaderRef::new(b":StAtUs", b"200"),
185 h3::HeaderRef::new(b":PaTh", b"/HeLlO"),
186 h3::HeaderRef::new(b"WooT", b"woot"),
187 h3::HeaderRef::new(b"hello", b"WorlD"),
188 h3::HeaderRef::new(b"fOo", b"BaR"),
189 ];
190
191 let mut enc = Encoder::new();
192 assert_eq!(enc.encode(&headers_in, &mut encoded), Ok(35));
193
194 let mut dec = Decoder::new();
195 let headers_out = dec.decode(&encoded, u64::MAX).unwrap();
196
197 assert_eq!(headers_expected, headers_out);
198 }
199
200 #[test]
201 fn lower_ascii_range() {
202 let mut encoded = [0u8; 50];
203 let mut enc = Encoder::new();
204
205 let headers1 = vec![h3::Header::new(b"location", b" ")];
207 assert_eq!(enc.encode(&headers1, &mut encoded), Ok(19));
208
209 let headers2 = vec![h3::Header::new(b"a", b"")];
211 assert_eq!(enc.encode(&headers2, &mut encoded), Ok(20));
212
213 let headers3 = vec![h3::Header::new(b" ", b"hello")];
214 assert_eq!(enc.encode(&headers3, &mut encoded), Ok(24));
215 }
216
217 #[test]
218 fn extended_ascii_range() {
219 let mut encoded = [0u8; 50];
220 let mut enc = Encoder::new();
221
222 let name = b"location";
223 let value = "£££££££££££££££";
224
225 let headers1 = vec![h3::Header::new(name, value.as_bytes())];
227 assert_eq!(enc.encode(&headers1, &mut encoded), Ok(34));
228
229 let value = "ððððððððððððððð";
231 let headers2 = vec![h3::Header::new(b"a", value.as_bytes())];
232 assert_eq!(enc.encode(&headers2, &mut encoded), Ok(35));
233
234 let headers3 = vec![h3::Header::new(value.as_bytes(), b"hello")];
235 assert_eq!(enc.encode(&headers3, &mut encoded), Ok(39));
236 }
237}
238
239pub use decoder::Decoder;
240pub use encoder::Encoder;
241
242mod decoder;
243mod encoder;
244mod static_table;