use super::super::error::H2ParseError;
pub fn decode_integer(buf: &[u8], prefix_bits: u32) -> Result<(u64, &[u8]), H2ParseError> {
if buf.is_empty() {
return Err(H2ParseError::MalformedHeaders);
}
let mask: u8 = ((1u16 << prefix_bits) - 1) as u8;
let prefix = buf[0] & mask;
if prefix < mask {
return Ok((prefix as u64, &buf[1..]));
}
let mut value: u64 = mask as u64;
let mut shift: u32 = 0;
let mut idx: usize = 1;
loop {
if idx >= buf.len() {
return Err(H2ParseError::MalformedHeaders);
}
let b = buf[idx];
idx += 1;
let chunk = (b & 0x7F) as u64;
let shifted = chunk
.checked_shl(shift)
.ok_or(H2ParseError::MalformedHeaders)?;
value = value
.checked_add(shifted)
.ok_or(H2ParseError::MalformedHeaders)?;
if b & 0x80 == 0 {
return Ok((value, &buf[idx..]));
}
shift = shift.checked_add(7).ok_or(H2ParseError::MalformedHeaders)?;
if shift >= 64 {
return Err(H2ParseError::MalformedHeaders);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn decodes_short_form_under_prefix_max() {
let (v, rest) = decode_integer(&[0x0A, 0xAA], 7).unwrap();
assert_eq!(v, 10);
assert_eq!(rest, &[0xAA]);
}
#[test]
fn decodes_multi_octet_form() {
let (v, _) = decode_integer(&[0x7F, 0x05], 7).unwrap();
assert_eq!(v, 127 + 5);
}
#[test]
fn rejects_unbounded_continuation() {
let buf: Vec<u8> = std::iter::once(0x7F)
.chain(std::iter::repeat_n(0xFF, 16))
.collect();
assert!(decode_integer(&buf, 7).is_err());
}
}