http2: variable size integers decoded everywhere

pull/5464/head
Philippe Antoine 4 years ago committed by Victor Julien
parent b21acfbf21
commit 1a21eea0e9

@ -210,7 +210,7 @@ named!(pub http2_parse_headers_priority<HTTP2FrameHeadersPriority>,
pub const HTTP2_STATIC_HEADERS_NUMBER: usize = 61;
fn http2_frame_header_static(
n: u8, dyn_headers: &Vec<HTTP2FrameHeaderBlock>,
n: u64, dyn_headers: &Vec<HTTP2FrameHeaderBlock>,
) -> Option<HTTP2FrameHeaderBlock> {
let (name, value) = match n {
1 => (":authority", ""),
@ -350,9 +350,13 @@ fn http2_parse_headers_block_indexed<'a>(
)
}
let (i2, indexed) = parser(input)?;
match http2_frame_header_static(indexed.1, dyn_headers) {
Some(h) => Ok((i2, h)),
_ => Err(Err::Error((i2, ErrorKind::MapOpt))),
let (i3, indexreal) = http2_parse_var_uint(i2, indexed.1 as u64, 0x7F)?;
if indexreal == 0 && indexed.1 == 0x7F {
return Err(Err::Error((i3, ErrorKind::LengthValue)));
}
match http2_frame_header_static(indexreal, dyn_headers) {
Some(h) => Ok((i3, h)),
_ => Err(Err::Error((i3, ErrorKind::MapOpt))),
}
}
@ -361,19 +365,10 @@ fn http2_parse_headers_block_string(input: &[u8]) -> IResult<&[u8], Vec<u8>> {
bits!(input, tuple!(take_bits!(1u8), take_bits!(7u8)))
}
let (i1, huffslen) = parser(input)?;
let (i2, stringlen) = if huffslen.1 == 0x7F {
let (i3, maxsize2) = take_while_m_n!(i1, 0, 9, |ch| (ch & 0x80) != 0)?;
let (i4, maxsize3) = be_u8(i3)?;
let mut maxsize = 0x7F as u64;
for i in 0..maxsize2.len() {
maxsize += ((maxsize2[i] & 0x7F) as u64) << (7 * i);
}
maxsize += (maxsize3 as u64) << (7 * maxsize2.len());
(i4, maxsize)
} else {
(i1, huffslen.1 as u64)
};
let (i2, stringlen) = http2_parse_var_uint(i1, huffslen.1 as u64, 0x7F)?;
if stringlen == 0 && huffslen.1 == 0x7F {
return Err(Err::Error((i2, ErrorKind::LengthValue)));
}
let (i3, data) = take!(i2, stringlen as usize)?;
if huffslen.0 == 0 {
return Ok((i3, data.to_vec()));
@ -384,7 +379,7 @@ fn http2_parse_headers_block_string(input: &[u8]) -> IResult<&[u8], Vec<u8>> {
}
fn http2_parse_headers_block_literal_common<'a>(
input: &'a [u8], index: u8, dyn_headers: &Vec<HTTP2FrameHeaderBlock>,
input: &'a [u8], index: u64, dyn_headers: &Vec<HTTP2FrameHeaderBlock>,
) -> IResult<&'a [u8], HTTP2FrameHeaderBlock> {
let (i3, name, error) = if index == 0 {
match http2_parse_headers_block_string(input) {
@ -430,11 +425,10 @@ fn http2_parse_headers_block_literal_incindex<'a>(
)
}
let (i2, indexed) = parser(input)?;
let (i3, indexreal) = if indexed.1 == 0x3F {
map!(i2, be_u8, |i| i + 0x3F)
} else {
Ok((i2, indexed.1))
}?;
let (i3, indexreal) = http2_parse_var_uint(i2, indexed.1 as u64, 0x3F)?;
if indexreal == 0 && indexed.1 == 0x3F {
return Err(Err::Error((i3, ErrorKind::LengthValue)));
}
let r = http2_parse_headers_block_literal_common(i3, indexreal, dyn_headers);
match r {
Ok((r, head)) => {
@ -445,10 +439,16 @@ fn http2_parse_headers_block_literal_incindex<'a>(
sizeupdate: 0,
};
dyn_headers.push(headcopy);
if dyn_headers.len() > 255 - HTTP2_STATIC_HEADERS_NUMBER {
let mut dynsize = 0;
//we may spend less CPU by storing in memory
for i in 0..dyn_headers.len() {
dynsize += 32 + dyn_headers[i].name.len() + dyn_headers[i].value.len();
}
//TODO keep track of settings + updates instead of magic default value
while dynsize > 4096 {
dynsize -= 32 + dyn_headers[0].name.len() + dyn_headers[0].value.len();
dyn_headers.remove(0);
}
//we do not limit the dynamic table size
return Ok((r, head));
}
Err(e) => {
@ -470,12 +470,10 @@ fn http2_parse_headers_block_literal_noindex<'a>(
)
}
let (i2, indexed) = parser(input)?;
//undocumented in RFC ?! found with wireshark
let (i3, indexreal) = if indexed.1 == 0xF {
map!(i2, be_u8, |i| i + 0xF)
} else {
Ok((i2, indexed.1))
}?;
let (i3, indexreal) = http2_parse_var_uint(i2, indexed.1 as u64, 0xF)?;
if indexreal == 0 && indexed.1 == 0xF {
return Err(Err::Error((i3, ErrorKind::LengthValue)));
}
let r = http2_parse_headers_block_literal_common(i3, indexreal, dyn_headers);
return r;
}
@ -493,15 +491,36 @@ fn http2_parse_headers_block_literal_neverindex<'a>(
)
}
let (i2, indexed) = parser(input)?;
let (i3, indexreal) = if indexed.1 == 0xF {
map!(i2, be_u8, |i| i + 0xF)
} else {
Ok((i2, indexed.1))
}?;
let (i3, indexreal) = http2_parse_var_uint(i2, indexed.1 as u64, 0xF)?;
if indexreal == 0 && indexed.1 == 0xF {
return Err(Err::Error((i3, ErrorKind::LengthValue)));
}
let r = http2_parse_headers_block_literal_common(i3, indexreal, dyn_headers);
return r;
}
fn http2_parse_var_uint(input: &[u8], value: u64, max: u64) -> IResult<&[u8], u64> {
if value < max {
return Ok((input, value));
}
let (i2, varia) = take_while!(input, |ch| (ch & 0x80) != 0)?;
let (i3, finalv) = be_u8(i2)?;
if varia.len() > 9 || (varia.len() == 9 && finalv > 1) {
// this will overflow u64
return Ok((i3, 0));
}
let mut varval = max;
for i in 0..varia.len() {
varval += ((varia[i] & 0x7F) as u64) << (7 * i);
}
varval += (finalv as u64) << (7 * varia.len());
if varval < max {
// this has overflown u64
return Ok((i3, 0));
}
return Ok((i3, varval));
}
fn http2_parse_headers_block_dynamic_size(input: &[u8]) -> IResult<&[u8], HTTP2FrameHeaderBlock> {
fn parser(input: &[u8]) -> IResult<&[u8], (u8, u8)> {
bits!(
@ -513,13 +532,10 @@ fn http2_parse_headers_block_dynamic_size(input: &[u8]) -> IResult<&[u8], HTTP2F
)
}
let (i2, maxsize) = parser(input)?;
if maxsize.1 == 31 {
let (i3, maxsize2) = take_while!(i2, |ch| (ch & 0x80) != 0)?;
let (i4, maxsize3) = be_u8(i3)?;
//9 is maximum size to encode a variable length u64
if maxsize2.len() > 9 {
let (i3, maxsize2) = http2_parse_var_uint(i2, maxsize.1 as u64, 0x1F)?;
if maxsize2 == 0 && maxsize.1 == 0x1F {
return Ok((
i4,
i3,
HTTP2FrameHeaderBlock {
name: Vec::new(),
value: Vec::new(),
@ -528,28 +544,13 @@ fn http2_parse_headers_block_dynamic_size(input: &[u8]) -> IResult<&[u8], HTTP2F
},
));
}
let mut sizeupdate = 31 as u64;
for i in 0..maxsize2.len() {
sizeupdate += ((maxsize2[i] & 0x7F) as u64) << (7 * i);
}
sizeupdate += (maxsize3 as u64) << (7 * maxsize2.len());
return Ok((
i4,
HTTP2FrameHeaderBlock {
name: Vec::new(),
value: Vec::new(),
error: HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSizeUpdate,
sizeupdate: sizeupdate,
},
));
}
return Ok((
i2,
i3,
HTTP2FrameHeaderBlock {
name: Vec::new(),
value: Vec::new(),
error: HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSizeUpdate,
sizeupdate: maxsize.1 as u64,
sizeupdate: maxsize2,
},
));
}

Loading…
Cancel
Save