1use asupersync::io::{AsyncRead, AsyncWrite, ReadBuf};
10use asupersync::net::TcpStream;
11use std::collections::VecDeque;
12use std::future::poll_fn;
13use std::io;
14use std::pin::Pin;
15use std::sync::OnceLock;
16use std::task::Poll;
17
18pub const PREFACE: &[u8] = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23#[repr(u8)]
24pub enum FrameType {
25 Data = 0x0,
26 Headers = 0x1,
27 Priority = 0x2,
28 RstStream = 0x3,
29 Settings = 0x4,
30 PushPromise = 0x5,
31 Ping = 0x6,
32 Goaway = 0x7,
33 WindowUpdate = 0x8,
34 Continuation = 0x9,
35 Unknown = 0xFF,
36}
37
38impl FrameType {
39 #[must_use]
40 pub fn from_u8(v: u8) -> Self {
41 match v {
42 0x0 => Self::Data,
43 0x1 => Self::Headers,
44 0x2 => Self::Priority,
45 0x3 => Self::RstStream,
46 0x4 => Self::Settings,
47 0x5 => Self::PushPromise,
48 0x6 => Self::Ping,
49 0x7 => Self::Goaway,
50 0x8 => Self::WindowUpdate,
51 0x9 => Self::Continuation,
52 _ => Self::Unknown,
53 }
54 }
55}
56
57#[derive(Debug, Clone, Copy, PartialEq, Eq)]
59pub struct FrameHeader {
60 pub length: u32, pub frame_type: u8,
62 pub flags: u8,
63 pub stream_id: u32, }
65
66impl FrameHeader {
67 pub const LEN: usize = 9;
68
69 #[must_use]
70 pub fn frame_type(&self) -> FrameType {
71 FrameType::from_u8(self.frame_type)
72 }
73
74 #[must_use]
75 pub fn is_stream_zero(&self) -> bool {
76 self.stream_id == 0
77 }
78}
79
80#[derive(Debug, Clone, PartialEq, Eq)]
82pub struct Frame {
83 pub header: FrameHeader,
84 pub payload: Vec<u8>,
85}
86
87#[derive(Debug)]
88pub enum Http2Error {
89 Io(io::Error),
90 Protocol(&'static str),
91 Hpack(HpackError),
92}
93
94impl std::fmt::Display for Http2Error {
95 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96 match self {
97 Self::Io(e) => write!(f, "http2 I/O error: {e}"),
98 Self::Protocol(m) => write!(f, "http2 protocol error: {m}"),
99 Self::Hpack(e) => write!(f, "hpack error: {e}"),
100 }
101 }
102}
103
104impl std::error::Error for Http2Error {
105 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
106 match self {
107 Self::Io(e) => Some(e),
108 Self::Hpack(e) => Some(e),
109 Self::Protocol(_) => None,
110 }
111 }
112}
113
114impl From<io::Error> for Http2Error {
115 fn from(e: io::Error) -> Self {
116 Self::Io(e)
117 }
118}
119
120impl From<HpackError> for Http2Error {
121 fn from(e: HpackError) -> Self {
122 Self::Hpack(e)
123 }
124}
125
126#[derive(Debug)]
128pub struct FramedH2 {
129 stream: TcpStream,
130 rx: Vec<u8>,
131}
132
133impl FramedH2 {
134 #[must_use]
135 pub fn new(stream: TcpStream, buffered: Vec<u8>) -> Self {
136 Self {
137 stream,
138 rx: buffered,
139 }
140 }
141
142 pub async fn read_frame(&mut self, max_frame_size: u32) -> Result<Frame, Http2Error> {
144 let header_bytes = self.read_exact(FrameHeader::LEN).await?;
145 let length = ((u32::from(header_bytes[0])) << 16)
146 | ((u32::from(header_bytes[1])) << 8)
147 | u32::from(header_bytes[2]);
148 let frame_type = header_bytes[3];
149 let flags = header_bytes[4];
150 let stream_id = u32::from_be_bytes([
151 header_bytes[5],
152 header_bytes[6],
153 header_bytes[7],
154 header_bytes[8],
155 ]) & 0x7FFF_FFFF;
156
157 if length > max_frame_size {
158 return Err(Http2Error::Protocol("frame length exceeds max_frame_size"));
159 }
160
161 let payload = self.read_exact(length as usize).await?;
162 Ok(Frame {
163 header: FrameHeader {
164 length,
165 frame_type,
166 flags,
167 stream_id,
168 },
169 payload,
170 })
171 }
172
173 pub async fn write_frame(
175 &mut self,
176 frame_type: FrameType,
177 flags: u8,
178 stream_id: u32,
179 payload: &[u8],
180 ) -> Result<(), Http2Error> {
181 if stream_id & 0x8000_0000 != 0 {
182 return Err(Http2Error::Protocol("reserved bit set in stream_id"));
183 }
184 let len = u32::try_from(payload.len())
185 .map_err(|_| Http2Error::Protocol("payload length too large"))?;
186 if len > 0x00FF_FFFF {
187 return Err(Http2Error::Protocol("payload length exceeds 24-bit limit"));
188 }
189
190 let mut out = Vec::with_capacity(FrameHeader::LEN + payload.len());
191 out.push(((len >> 16) & 0xff) as u8);
192 out.push(((len >> 8) & 0xff) as u8);
193 out.push((len & 0xff) as u8);
194 out.push(frame_type as u8);
195 out.push(flags);
196 out.extend_from_slice(&(stream_id & 0x7FFF_FFFF).to_be_bytes());
197 out.extend_from_slice(payload);
198
199 write_all(&mut self.stream, &out).await?;
200 flush(&mut self.stream).await?;
201 Ok(())
202 }
203
204 async fn read_exact(&mut self, n: usize) -> io::Result<Vec<u8>> {
205 while self.rx.len() < n {
206 let mut tmp = vec![0u8; 8192];
207 let read = read_once(&mut self.stream, &mut tmp).await?;
208 if read == 0 {
209 return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "EOF"));
210 }
211 self.rx.extend_from_slice(&tmp[..read]);
212 }
213 Ok(self.rx.drain(..n).collect())
214 }
215}
216
217async fn read_once(stream: &mut TcpStream, buffer: &mut [u8]) -> io::Result<usize> {
218 poll_fn(|cx| {
219 let mut read_buf = ReadBuf::new(buffer);
220 match Pin::new(&mut *stream).poll_read(cx, &mut read_buf) {
221 Poll::Ready(Ok(())) => Poll::Ready(Ok(read_buf.filled().len())),
222 Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
223 Poll::Pending => Poll::Pending,
224 }
225 })
226 .await
227}
228
229async fn write_all(stream: &mut TcpStream, mut buf: &[u8]) -> io::Result<()> {
230 while !buf.is_empty() {
231 let n = poll_fn(|cx| Pin::new(&mut *stream).poll_write(cx, buf)).await?;
232 if n == 0 {
233 return Err(io::Error::new(io::ErrorKind::WriteZero, "write zero"));
234 }
235 buf = &buf[n..];
236 }
237 Ok(())
238}
239
240async fn flush(stream: &mut TcpStream) -> io::Result<()> {
241 poll_fn(|cx| Pin::new(&mut *stream).poll_flush(cx)).await
242}
243
244#[derive(Debug, Clone, PartialEq, Eq)]
249pub enum HpackError {
250 InvalidInteger,
251 InvalidString,
252 InvalidIndex,
253 InvalidHuffman,
254 DynamicTableSizeUpdateOutOfRange,
255 HeaderListTooLarge,
256}
257
258impl std::fmt::Display for HpackError {
259 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
260 write!(f, "{self:?}")
261 }
262}
263
264impl std::error::Error for HpackError {}
265
266#[derive(Debug, Clone, PartialEq, Eq)]
267struct HeaderField {
268 name: Vec<u8>,
269 value: Vec<u8>,
270 size: usize,
271}
272
273impl HeaderField {
274 fn new(name: Vec<u8>, value: Vec<u8>) -> Self {
275 let size = 32 + name.len() + value.len();
276 Self { name, value, size }
277 }
278}
279
280#[derive(Debug)]
282pub struct HpackDecoder {
283 dynamic: VecDeque<HeaderField>,
284 dynamic_size: usize,
285 dynamic_max_size: usize,
286 max_header_list_size: usize,
287}
288
289pub type HeaderList = Vec<(Vec<u8>, Vec<u8>)>;
291
292impl Default for HpackDecoder {
293 fn default() -> Self {
294 Self::new()
295 }
296}
297
298impl HpackDecoder {
299 #[must_use]
300 pub fn new() -> Self {
301 Self {
302 dynamic: VecDeque::new(),
303 dynamic_size: 0,
304 dynamic_max_size: 4096,
305 max_header_list_size: 64 * 1024,
306 }
307 }
308
309 pub fn set_dynamic_table_max_size(&mut self, n: usize) {
310 self.dynamic_max_size = n;
311 self.evict_to_max();
312 }
313
314 pub fn set_max_header_list_size(&mut self, n: usize) {
315 self.max_header_list_size = n;
316 }
317
318 pub fn decode(&mut self, block: &[u8]) -> Result<HeaderList, HpackError> {
319 let mut out: HeaderList = Vec::new();
320 let mut i = 0usize;
321
322 while i < block.len() {
323 let b = block[i];
324
325 if (b & 0x80) != 0 {
326 let (index, used) = decode_integer(&block[i..], 7)?;
328 i += used;
329 let (name, value) = self.get_indexed(index)?;
330 out.push((name, value));
331 continue;
332 }
333
334 if (b & 0xC0) == 0x40 {
335 let (name, value, used) = self.decode_literal(&block[i..], 6)?;
337 i += used;
338 self.insert_dynamic(name.clone(), value.clone());
339 out.push((name, value));
340 continue;
341 }
342
343 if (b & 0xE0) == 0x20 {
344 let (new_size, used) = decode_integer(&block[i..], 5)?;
346 i += used;
347 if new_size > self.dynamic_max_size {
348 return Err(HpackError::DynamicTableSizeUpdateOutOfRange);
349 }
350 self.set_dynamic_table_max_size(new_size);
351 continue;
352 }
353
354 let (name, value, used) = self.decode_literal(&block[i..], 4)?;
357 i += used;
358 out.push((name, value));
359 }
360
361 let total_list_bytes: usize = out.iter().map(|(n, v)| n.len() + v.len() + 32).sum();
362 if total_list_bytes > self.max_header_list_size {
363 return Err(HpackError::HeaderListTooLarge);
364 }
365
366 Ok(out)
367 }
368
369 fn decode_literal(
370 &mut self,
371 buf: &[u8],
372 name_prefix_bits: u8,
373 ) -> Result<(Vec<u8>, Vec<u8>, usize), HpackError> {
374 let first = buf[0];
376 let name_index_prefix_mask = (1u8 << name_prefix_bits) - 1;
377 let name_index = usize::from(first & name_index_prefix_mask);
378
379 let mut used = 0usize;
380 let name = if name_index == 0 {
381 used += 1;
382 let (name_bytes, n_used) = decode_string(&buf[used..])?;
383 used += n_used;
384 name_bytes
385 } else {
386 let (index, n_used) = decode_integer(buf, name_prefix_bits)?;
387 used += n_used;
388 let (name, _value) = self.get_indexed(index)?;
389 name
390 };
391
392 let (value, v_used) = decode_string(&buf[used..])?;
393 used += v_used;
394 Ok((name, value, used))
395 }
396
397 fn get_indexed(&self, index: usize) -> Result<(Vec<u8>, Vec<u8>), HpackError> {
398 if index == 0 {
399 return Err(HpackError::InvalidIndex);
400 }
401 let static_len = STATIC_TABLE.len();
402 if index <= static_len {
403 let (n, v) = STATIC_TABLE[index - 1];
404 return Ok((n.to_vec(), v.to_vec()));
405 }
406 let dyn_index = index - static_len - 1;
407 let field = self
408 .dynamic
409 .get(dyn_index)
410 .ok_or(HpackError::InvalidIndex)?;
411 Ok((field.name.clone(), field.value.clone()))
412 }
413
414 fn insert_dynamic(&mut self, name: Vec<u8>, value: Vec<u8>) {
415 let field = HeaderField::new(name, value);
416 if field.size > self.dynamic_max_size {
417 self.dynamic.clear();
418 self.dynamic_size = 0;
419 return;
420 }
421 self.dynamic.push_front(field);
422 self.dynamic_size = self.dynamic.iter().map(|f| f.size).sum();
423 self.evict_to_max();
424 }
425
426 fn evict_to_max(&mut self) {
427 while self.dynamic_size > self.dynamic_max_size {
428 let Some(back) = self.dynamic.pop_back() else {
429 self.dynamic_size = 0;
430 break;
431 };
432 self.dynamic_size = self.dynamic_size.saturating_sub(back.size);
433 }
434 }
435}
436
437fn decode_integer(buf: &[u8], prefix_bits: u8) -> Result<(usize, usize), HpackError> {
438 if buf.is_empty() || prefix_bits == 0 || prefix_bits > 8 {
439 return Err(HpackError::InvalidInteger);
440 }
441 let prefix_max = (1usize << prefix_bits) - 1;
442 let mut value = usize::from(buf[0] & (prefix_max as u8));
443 if value < prefix_max {
444 return Ok((value, 1));
445 }
446 let mut m = 0usize;
447 let mut idx = 1usize;
448 loop {
449 let b = *buf.get(idx).ok_or(HpackError::InvalidInteger)?;
450 idx += 1;
451 value = value
452 .checked_add((usize::from(b & 0x7f)) << m)
453 .ok_or(HpackError::InvalidInteger)?;
454 if (b & 0x80) == 0 {
455 break;
456 }
457 m = m.checked_add(7).ok_or(HpackError::InvalidInteger)?;
458 if m > 63 {
459 return Err(HpackError::InvalidInteger);
460 }
461 }
462 Ok((value, idx))
463}
464
465fn decode_string(buf: &[u8]) -> Result<(Vec<u8>, usize), HpackError> {
466 if buf.is_empty() {
467 return Err(HpackError::InvalidString);
468 }
469 let huffman = (buf[0] & 0x80) != 0;
470 let (len, used) = decode_integer(buf, 7)?;
471 let start = used;
472 let end = start.checked_add(len).ok_or(HpackError::InvalidString)?;
473 let s = buf.get(start..end).ok_or(HpackError::InvalidString)?;
474 if huffman {
475 let decoded = huffman_decode(s)?;
476 Ok((decoded, end))
477 } else {
478 Ok((s.to_vec(), end))
479 }
480}
481
482fn encode_integer(out: &mut Vec<u8>, first: u8, prefix_bits: u8, mut value: usize) {
487 let prefix_max = (1usize << prefix_bits) - 1;
488 if value < prefix_max {
489 out.push(first | (value as u8));
490 return;
491 }
492
493 out.push(first | (prefix_max as u8));
494 value -= prefix_max;
495 while value >= 128 {
496 out.push(((value & 0x7f) as u8) | 0x80);
497 value >>= 7;
498 }
499 out.push(value as u8);
500}
501
502fn encode_string(out: &mut Vec<u8>, bytes: &[u8]) {
503 encode_integer(out, 0x00, 7, bytes.len());
505 out.extend_from_slice(bytes);
506}
507
508pub fn hpack_encode_literal_without_indexing(out: &mut Vec<u8>, name: &[u8], value: &[u8]) {
515 encode_integer(out, 0x00, 4, 0);
519 encode_string(out, name);
520 encode_string(out, value);
521}
522
523const STATIC_TABLE: [(&[u8], &[u8]); 61] = [
526 (b":authority", b""),
527 (b":method", b"GET"),
528 (b":method", b"POST"),
529 (b":path", b"/"),
530 (b":path", b"/index.html"),
531 (b":scheme", b"http"),
532 (b":scheme", b"https"),
533 (b":status", b"200"),
534 (b":status", b"204"),
535 (b":status", b"206"),
536 (b":status", b"304"),
537 (b":status", b"400"),
538 (b":status", b"404"),
539 (b":status", b"500"),
540 (b"accept-charset", b""),
541 (b"accept-encoding", b"gzip, deflate"),
542 (b"accept-language", b""),
543 (b"accept-ranges", b""),
544 (b"accept", b""),
545 (b"access-control-allow-origin", b""),
546 (b"age", b""),
547 (b"allow", b""),
548 (b"authorization", b""),
549 (b"cache-control", b""),
550 (b"content-disposition", b""),
551 (b"content-encoding", b""),
552 (b"content-language", b""),
553 (b"content-length", b""),
554 (b"content-location", b""),
555 (b"content-range", b""),
556 (b"content-type", b""),
557 (b"cookie", b""),
558 (b"date", b""),
559 (b"etag", b""),
560 (b"expect", b""),
561 (b"expires", b""),
562 (b"from", b""),
563 (b"host", b""),
564 (b"if-match", b""),
565 (b"if-modified-since", b""),
566 (b"if-none-match", b""),
567 (b"if-range", b""),
568 (b"if-unmodified-since", b""),
569 (b"last-modified", b""),
570 (b"link", b""),
571 (b"location", b""),
572 (b"max-forwards", b""),
573 (b"proxy-authenticate", b""),
574 (b"proxy-authorization", b""),
575 (b"range", b""),
576 (b"referer", b""),
577 (b"refresh", b""),
578 (b"retry-after", b""),
579 (b"server", b""),
580 (b"set-cookie", b""),
581 (b"strict-transport-security", b""),
582 (b"transfer-encoding", b""),
583 (b"user-agent", b""),
584 (b"vary", b""),
585 (b"via", b""),
586 (b"www-authenticate", b""),
587];
588
589#[derive(Debug, Clone, Copy)]
590struct HuffmanNode {
591 left: Option<usize>,
592 right: Option<usize>,
593 sym: Option<u16>,
594}
595
596fn huffman_tree() -> &'static Vec<HuffmanNode> {
597 static TREE: OnceLock<Vec<HuffmanNode>> = OnceLock::new();
598 TREE.get_or_init(|| {
599 let mut nodes = vec![HuffmanNode {
600 left: None,
601 right: None,
602 sym: None,
603 }];
604
605 for (sym, (&code, &bits)) in HUFFMAN_CODES.iter().zip(HUFFMAN_BITS.iter()).enumerate() {
606 let mut cur = 0usize;
607 for bit_index in (0..bits).rev() {
608 let bit = (code >> bit_index) & 1;
609 let next_idx = if bit == 0 {
610 nodes[cur].left
611 } else {
612 nodes[cur].right
613 };
614
615 cur = if let Some(idx) = next_idx {
616 idx
617 } else {
618 let idx = nodes.len();
619 nodes.push(HuffmanNode {
620 left: None,
621 right: None,
622 sym: None,
623 });
624 if bit == 0 {
625 nodes[cur].left = Some(idx);
626 } else {
627 nodes[cur].right = Some(idx);
628 }
629 idx
630 };
631 }
632 nodes[cur].sym = Some(u16::try_from(sym).unwrap_or(256));
633 }
634
635 nodes
636 })
637}
638
639fn eos_prefix_nodes() -> &'static Vec<bool> {
640 static NODES: OnceLock<Vec<bool>> = OnceLock::new();
641 NODES.get_or_init(|| {
642 let tree = huffman_tree();
643 let mut is_prefix = vec![false; tree.len()];
644 let eos_code = HUFFMAN_CODES[256];
645 let eos_bits = HUFFMAN_BITS[256];
646
647 let mut cur = 0usize;
648 is_prefix[cur] = true;
649 for bit_index in (0..eos_bits).rev() {
650 let bit = (eos_code >> bit_index) & 1;
651 cur = if bit == 0 {
652 tree[cur].left.expect("eos left")
653 } else {
654 tree[cur].right.expect("eos right")
655 };
656 if cur >= is_prefix.len() {
657 break;
658 }
659 is_prefix[cur] = true;
660 }
661 is_prefix
662 })
663}
664
665fn huffman_decode(bytes: &[u8]) -> Result<Vec<u8>, HpackError> {
666 let tree = huffman_tree();
667 let eos_prefix = eos_prefix_nodes();
668
669 let mut out = Vec::with_capacity(bytes.len());
670 let mut cur = 0usize;
671
672 for &byte in bytes {
673 for bit_shift in (0..8).rev() {
674 let bit = (byte >> bit_shift) & 1;
675 cur = if bit == 0 {
676 tree[cur].left.ok_or(HpackError::InvalidHuffman)?
677 } else {
678 tree[cur].right.ok_or(HpackError::InvalidHuffman)?
679 };
680 if let Some(sym) = tree[cur].sym {
681 if sym == 256 {
682 return Err(HpackError::InvalidHuffman);
684 }
685 out.push(u8::try_from(sym).map_err(|_| HpackError::InvalidHuffman)?);
686 cur = 0;
687 }
688 }
689 }
690
691 if cur != 0 && !eos_prefix.get(cur).copied().unwrap_or(false) {
693 return Err(HpackError::InvalidHuffman);
694 }
695
696 Ok(out)
697}
698
699#[rustfmt::skip]
704#[allow(clippy::unreadable_literal)]
705const HUFFMAN_CODES: [u32; 257] = [
706 0x1ff8,0x7fffd8,0xfffffe2,0xfffffe3,0xfffffe4,0xfffffe5,0xfffffe6,0xfffffe7,
707 0xfffffe8,0xffffea,0x3ffffffc,0xfffffe9,0xfffffea,0x3ffffffd,0xfffffeb,0xfffffec,
708 0xfffffed,0xfffffee,0xfffffef,0xffffff0,0xffffff1,0xffffff2,0x3ffffffe,0xffffff3,
709 0xffffff4,0xffffff5,0xffffff6,0xffffff7,0xffffff8,0xffffff9,0xffffffa,0xffffffb,
710 0x14,0x3f8,0x3f9,0xffa,0x1ff9,0x15,0xf8,0x7fa,0x3fa,0x3fb,0xf9,0x7fb,0xfa,
711 0x16,0x17,0x18,0x0,0x1,0x2,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x5c,0xfb,
712 0x7ffc,0x20,0xffb,0x3fc,0x1ffa,0x21,0x5d,0x5e,0x5f,0x60,0x61,0x62,0x63,
713 0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,
714 0x72,0xfc,0x73,0xfd,0x1ffb,0x7fff0,0x1ffc,0x3ffc,0x22,0x7ffd,0x3,0x23,0x4,
715 0x24,0x5,0x25,0x26,0x27,0x6,0x74,0x75,0x28,0x29,0x2a,0x7,0x2b,0x76,0x2c,
716 0x8,0x9,0x2d,0x77,0x78,0x79,0x7a,0x7b,0x7ffe,0x7fc,0x3ffd,0x1ffd,0xffffffc,
717 0xfffe6,0x3fffd2,0xfffe7,0xfffe8,0x3fffd3,0x3fffd4,0x3fffd5,0x7fffd9,0x3fffd6,
718 0x7fffda,0x7fffdb,0x7fffdc,0x7fffdd,0x7fffde,0xffffeb,0x7fffdf,0xffffec,0xffffed,
719 0x3fffd7,0x7fffe0,0xffffee,0x7fffe1,0x7fffe2,0x7fffe3,0x7fffe4,0x1fffdc,0x3fffd8,
720 0x7fffe5,0x3fffd9,0x7fffe6,0x7fffe7,0xffffef,0x3fffda,0x1fffdd,0xfffe9,0x3fffdb,
721 0x3fffdc,0x7fffe8,0x7fffe9,0x1fffde,0x7fffea,0x3fffdd,0x3fffde,0xfffff0,0x1fffdf,
722 0x3fffdf,0x7fffeb,0x7fffec,0x1fffe0,0x1fffe1,0x3fffe0,0x1fffe2,0x7fffed,0x3fffe1,
723 0x7fffee,0x7fffef,0xfffea,0x3fffe2,0x3fffe3,0x3fffe4,0x7ffff0,0x3fffe5,0x3fffe6,
724 0x7ffff1,0x3ffffe0,0x3ffffe1,0xfffeb,0x7fff1,0x3fffe7,0x7ffff2,0x3fffe8,0x1ffffec,
725 0x3ffffe2,0x3ffffe3,0x3ffffe4,0x7ffffde,0x7ffffdf,0x3ffffe5,0xfffff1,0x1ffffed,
726 0x7fff2,0x1fffe3,0x3ffffe6,0x7ffffe0,0x7ffffe1,0x3ffffe7,0x7ffffe2,0xfffff2,
727 0x1fffe4,0x1fffe5,0x3ffffe8,0x3ffffe9,0xffffffd,0x7ffffe3,0x7ffffe4,0x7ffffe5,
728 0xfffec,0xfffff3,0xfffed,0x1fffe6,0x3fffe9,0x1fffe7,0x1fffe8,0x7ffff3,0x3fffea,
729 0x3fffeb,0x1ffffee,0x1ffffef,0xfffff4,0xfffff5,0x3ffffea,0x7ffff4,0x3ffffeb,
730 0x7ffffe6,0x3ffffec,0x3ffffed,0x7ffffe7,0x7ffffe8,0x7ffffe9,0x7ffffea,0x7ffffeb,
731 0xffffffe,0x7ffffec,0x7ffffed,0x7ffffee,0x7ffffef,0x7fffff0,0x3ffffee,0x3fffffff,
732];
733
734#[rustfmt::skip]
735const HUFFMAN_BITS: [u8; 257] = [
736 13,23,28,28,28,28,28,28,28,24,30,28,28,30,28,28,
737 28,28,28,28,28,28,30,28,28,28,28,28,28,28,28,28,
738 6,10,10,12,13,6,8,11,10,10,8,11,8,6,6,6,
739 5,5,5,6,6,6,6,6,6,6,7,8,15,6,12,10,
740 13,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
741 7,7,7,7,7,7,7,7,8,7,8,13,19,13,14,6,
742 15,5,6,5,6,5,6,6,6,5,7,7,6,6,6,5,
743 6,7,6,5,5,6,7,7,7,7,7,15,11,14,13,28,
744 20,22,20,20,22,22,22,23,22,23,23,23,23,23,24,23,
745 24,24,22,23,24,23,23,23,23,21,22,23,22,23,23,24,
746 22,21,20,22,22,23,23,21,23,22,22,24,21,22,23,23,
747 21,21,22,21,23,22,23,23,20,22,22,22,23,22,22,23,
748 26,26,20,19,22,23,22,25,26,26,26,27,27,26,24,25,
749 19,21,26,27,27,26,27,24,21,21,26,26,28,27,27,27,
750 20,24,20,21,22,21,21,23,22,22,25,25,24,24,26,23,
751 26,27,26,26,27,27,27,27,27,28,27,27,27,27,27,26,
752 30,
753];
754
755pub const DEFAULT_INITIAL_WINDOW_SIZE: u32 = 65_535;
761
762const WINDOW_UPDATE_THRESHOLD_DIVISOR: u32 = 2;
766
767#[derive(Debug)]
773pub struct H2FlowControl {
774 conn_window: i64,
776 conn_consumed: u32,
779 initial_window_size: u32,
782 send_conn_window: i64,
784 peer_initial_window_size: u32,
786}
787
788impl H2FlowControl {
789 #[must_use]
791 pub fn new() -> Self {
792 Self {
793 conn_window: i64::from(DEFAULT_INITIAL_WINDOW_SIZE),
794 conn_consumed: 0,
795 initial_window_size: DEFAULT_INITIAL_WINDOW_SIZE,
796 send_conn_window: i64::from(DEFAULT_INITIAL_WINDOW_SIZE),
797 peer_initial_window_size: DEFAULT_INITIAL_WINDOW_SIZE,
798 }
799 }
800
801 pub fn set_initial_window_size(&mut self, size: u32) {
805 self.initial_window_size = size;
806 }
807
808 pub fn data_received_connection(&mut self, n: u32) -> u32 {
812 self.conn_window -= i64::from(n);
813 self.conn_consumed += n;
814
815 let threshold = self.initial_window_size / WINDOW_UPDATE_THRESHOLD_DIVISOR;
816 if self.conn_consumed >= threshold {
817 let increment = self.conn_consumed;
818 self.conn_window += i64::from(increment);
819 self.conn_consumed = 0;
820 increment
821 } else {
822 0
823 }
824 }
825
826 pub fn stream_window_update(&self, total_received: u32) -> u32 {
835 let threshold = self.initial_window_size / WINDOW_UPDATE_THRESHOLD_DIVISOR;
836 if total_received >= threshold {
837 total_received
838 } else {
839 0
840 }
841 }
842
843 #[must_use]
845 pub fn initial_window_size(&self) -> u32 {
846 self.initial_window_size
847 }
848
849 pub fn set_peer_initial_window_size(&mut self, size: u32) {
854 self.peer_initial_window_size = size;
855 }
856
857 #[must_use]
859 pub fn peer_initial_window_size(&self) -> u32 {
860 self.peer_initial_window_size
861 }
862
863 #[must_use]
865 pub fn send_conn_window(&self) -> i64 {
866 self.send_conn_window
867 }
868
869 pub fn peer_window_update_connection(&mut self, increment: u32) {
872 self.send_conn_window += i64::from(increment);
873 }
874
875 pub fn consume_send_conn_window(&mut self, n: u32) {
877 self.send_conn_window -= i64::from(n);
878 }
879}
880
881impl Default for H2FlowControl {
882 fn default() -> Self {
883 Self::new()
884 }
885}
886
887#[cfg(test)]
888mod tests {
889 use super::*;
890
891 #[test]
892 fn hpack_rfc_vector_first_request() {
893 let block: [u8; 17] = [
895 0x82, 0x86, 0x84, 0x41, 0x8c, 0xf1, 0xe3, 0xc2, 0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab,
896 0x90, 0xf4, 0xff,
897 ];
898 let mut dec = HpackDecoder::new();
899 let headers = dec.decode(&block).unwrap();
900
901 assert!(headers.contains(&(b":method".to_vec(), b"GET".to_vec())));
902 assert!(headers.contains(&(b":scheme".to_vec(), b"http".to_vec())));
903 assert!(headers.contains(&(b":path".to_vec(), b"/".to_vec())));
904 assert!(headers.contains(&(b":authority".to_vec(), b"www.example.com".to_vec())));
905 }
906
907 #[test]
908 fn hpack_rejects_eos_symbol() {
909 let buf: [u8; 5] = [0x80 | 4, 0xff, 0xff, 0xff, 0xff];
914 let res = decode_string(&buf);
915 assert!(matches!(res, Err(HpackError::InvalidHuffman)));
916 }
917
918 #[test]
919 fn preface_constant_matches_rfc() {
920 assert_eq!(PREFACE, b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n");
921 assert_eq!(PREFACE.len(), 24);
922 }
923
924 #[test]
925 fn flow_control_no_update_below_threshold() {
926 let mut fc = H2FlowControl::new();
927 let increment = fc.data_received_connection(1000);
929 assert_eq!(increment, 0);
930 }
931
932 #[test]
933 fn flow_control_emits_update_at_threshold() {
934 let mut fc = H2FlowControl::new();
935 let increment = fc.data_received_connection(32_767);
937 assert_eq!(increment, 32_767);
938 }
939
940 #[test]
941 fn flow_control_accumulates_across_calls() {
942 let mut fc = H2FlowControl::new();
943 assert_eq!(fc.data_received_connection(20_000), 0);
945 assert_eq!(fc.data_received_connection(20_000), 40_000);
946 }
947
948 #[test]
949 fn flow_control_resets_consumed_after_update() {
950 let mut fc = H2FlowControl::new();
951 assert_eq!(fc.data_received_connection(40_000), 40_000);
952 assert_eq!(fc.data_received_connection(1_000), 0);
954 }
955
956 #[test]
957 fn flow_control_stream_below_threshold() {
958 let fc = H2FlowControl::new();
959 assert_eq!(fc.stream_window_update(1_000), 0);
960 }
961
962 #[test]
963 fn flow_control_stream_at_threshold() {
964 let fc = H2FlowControl::new();
965 assert_eq!(fc.stream_window_update(32_767), 32_767);
966 }
967
968 #[test]
969 fn flow_control_custom_initial_window() {
970 let mut fc = H2FlowControl::new();
971 fc.set_initial_window_size(100_000);
972 assert_eq!(fc.data_received_connection(49_999), 0);
974 assert_eq!(fc.data_received_connection(1), 50_000);
975 }
976}