diff --git a/rust/htp/src/decompressors.rs b/rust/htp/src/decompressors.rs index 3d66b14a5b..57c6bd2b23 100644 --- a/rust/htp/src/decompressors.rs +++ b/rust/htp/src/decompressors.rs @@ -478,18 +478,22 @@ impl GzipBufWriter { } } +fn take_with_finalzero(parse: &[u8]) -> nom::IResult<&[u8], &[u8]> { + use nom::bytes::streaming::{tag, take_until}; + let (parse, _) = take_until::<&[u8], &[u8], nom::error::Error<&[u8]>>(b"\0" as &[u8])(parse)?; + tag(&b"\0"[..])(parse) +} + impl Write for GzipBufWriter { fn write(&mut self, data: &[u8]) -> std::io::Result { - use nom::bytes::streaming::{tag, take_until}; use nom::number::streaming::le_u16; - use nom::sequence::tuple; const FHCRC: u8 = 1 << 1; const FEXTRA: u8 = 1 << 2; const FNAME: u8 = 1 << 3; const FCOMMENT: u8 = 1 << 4; - let (mut parse, direct) = if !self.buffer.is_empty() && self.state == GzState::Start { + let (mut parse, direct) = if !self.buffer.is_empty() && self.state != GzState::AfterHeader { self.buffer.extend_from_slice(data); (self.buffer.as_ref(), false) } else { @@ -525,7 +529,12 @@ impl Write for GzipBufWriter { self.xlen = xlen; } Err(nom::Err::Incomplete(_)) => { - return Ok(data.len() - parse.len()); + let pending = parse.to_vec(); + self.buffer.clear(); + self.buffer.extend_from_slice(&pending); + // need to consume all bytes and not return Ok(0) + // so we buffer the one byte already there + return Ok(data.len()); } Err(_) => { return Err(std::io::Error::new( @@ -541,6 +550,7 @@ impl Write for GzipBufWriter { if self.xlen > 0 { if parse.len() < self.xlen as usize { self.xlen -= parse.len() as u16; + self.buffer.clear(); return Ok(data.len()); } parse = &parse[self.xlen as usize..]; @@ -549,15 +559,12 @@ impl Write for GzipBufWriter { } GzState::Filename => { if self.flags & FNAME != 0 { - match tuple(( - take_until::<&[u8], &[u8], nom::error::Error<&[u8]>>(b"\0" as &[u8]), - tag(b"\0"), - ))(parse) - { + match take_with_finalzero(parse) { Ok((rest, _)) => { parse = rest; } Err(nom::Err::Incomplete(_)) => { + self.buffer.clear(); return Ok(data.len()); } Err(_) => { @@ -572,15 +579,12 @@ impl Write for GzipBufWriter { } GzState::Comment => { if self.flags & FCOMMENT != 0 { - match tuple(( - take_until::<&[u8], &[u8], nom::error::Error<&[u8]>>(b"\0" as &[u8]), - tag(b"\0"), - ))(parse) - { + match take_with_finalzero(parse) { Ok((rest, _)) => { parse = rest; } Err(nom::Err::Incomplete(_)) => { + self.buffer.clear(); return Ok(data.len()); } Err(_) => { @@ -600,7 +604,12 @@ impl Write for GzipBufWriter { parse = rest; } Err(nom::Err::Incomplete(_)) => { - return Ok(data.len() - parse.len()); + let pending = parse.to_vec(); + self.buffer.clear(); + self.buffer.extend_from_slice(&pending); + // need to consume all bytes and not return Ok(0) + // so we buffer the one byte already there + return Ok(data.len()); } Err(_) => { return Err(std::io::Error::new( @@ -1124,11 +1133,11 @@ fn test_gz_header() { let input = b"\x1f\x8b\x08\x1e\x00\x00\x00\x00\x00\x00\x05\x00extrafilename\x00comment\x00\x34"; let buf = BlockingCursor::new(); let mut gzw = GzipBufWriter::new(buf); - assert_eq!(gzw.write(input).unwrap(), input.len() - 1); + assert_eq!(gzw.write(input).unwrap(), input.len()); assert_eq!(gzw.state, GzState::Crc); // final missing CRC in header let input = b"\x34\xee"; - assert_eq!(gzw.write(input).unwrap(), input.len()); + assert_eq!(gzw.write(input).unwrap(), input.len() - 1); assert_eq!(gzw.state, GzState::AfterHeader); let input = b"\x1f\x8b\x08\x01\x00\x00\x00\x00\x00"; let buf = BlockingCursor::new();