diff --git a/rust/src/http2/http2.rs b/rust/src/http2/http2.rs index cf286a4773..e64a51a1c7 100644 --- a/rust/src/http2/http2.rs +++ b/rust/src/http2/http2.rs @@ -566,6 +566,17 @@ impl HTTP2Transaction { &mut stream_tx.progress_tc }; match data { + HTTP2FrameTypeData::CONTINUATION(c) => { + if c.end_stream && *state < HTTP2TxProgress::HTTP2ProgClosed { + *state = HTTP2TxProgress::HTTP2ProgClosed; + if stream_tx.progress_ts == HTTP2TxProgress::HTTP2ProgClosed + && stream_tx.progress_tc == HTTP2TxProgress::HTTP2ProgClosed + { + stream_tx.progress_ts = HTTP2TxProgress::HTTP2ProgComplete; + stream_tx.progress_tc = HTTP2TxProgress::HTTP2ProgComplete; + } + } + } HTTP2FrameTypeData::HEADERS(_) => { if header.flags & parser::HTTP2_FLAG_HEADER_EOS != 0 && header.flags & parser::HTTP2_FLAG_HEADER_END_HEADERS != 0 @@ -730,6 +741,7 @@ impl HTTP2DynTable { struct HTTP2HeaderReassemblyBuffer { data: Vec, stream_id: u32, + end_stream: bool, } pub struct HTTP2State { @@ -1243,7 +1255,10 @@ impl HTTP2State { *reass_limit_reached = true; } if head.flags & parser::HTTP2_FLAG_HEADER_END_HEADERS == 0 { - let hs = parser::HTTP2FrameContinuation { blocks: Vec::new() }; + let hs = parser::HTTP2FrameContinuation { + blocks: Vec::new(), + end_stream: false, + }; return (HTTP2FrameTypeData::CONTINUATION(hs), events); } } // else try to parse anyways @@ -1259,11 +1274,16 @@ impl HTTP2State { &mut self.dynamic_headers_ts }; match parser::http2_parse_frame_continuation(input_reass, dyn_headers) { - Ok((_, hs)) => { - if head.stream_id == buf.stream_id { + Ok((_, mut hs)) => { + let same = head.stream_id == buf.stream_id; + if same { buf.stream_id = 0; buf.data.clear(); } + hs.end_stream = buf.end_stream; + if same { + buf.end_stream = false; + } events.extend(self.process_headers(&hs.blocks, dir)); return (HTTP2FrameTypeData::CONTINUATION(hs), events); } @@ -1271,6 +1291,7 @@ impl HTTP2State { if head.stream_id == buf.stream_id { buf.stream_id = 0; buf.data.clear(); + buf.end_stream = false; } if complete { events.push(HTTP2Event::InvalidFrameData); @@ -1293,6 +1314,7 @@ impl HTTP2State { if head.stream_id == buf.stream_id { buf.stream_id = 0; buf.data.clear(); + buf.end_stream = false; } events.push(HTTP2Event::InvalidFrameData); return ( @@ -1312,6 +1334,7 @@ impl HTTP2State { &mut self.c2s_buf }; buf.data.clear(); + buf.end_stream = head.flags & parser::HTTP2_FLAG_HEADER_EOS != 0; if let Ok((rem_hpack, hs)) = parser::get_frame_headers_hpack(input, hflags) { // store only the HPACK fragment: skip Pad Length, Priority, and trailing padding buf.data.extend(rem_hpack); diff --git a/rust/src/http2/parser.rs b/rust/src/http2/parser.rs index 527cd1be25..212c298447 100644 --- a/rust/src/http2/parser.rs +++ b/rust/src/http2/parser.rs @@ -680,13 +680,23 @@ pub fn http2_parse_frame_push_promise<'a>( #[derive(Clone, Debug)] pub struct HTTP2FrameContinuation { pub blocks: Vec, + // not in the contination frame itself, + // but inherited from parent headers frame, + // so as to update progress + pub end_stream: bool, } pub fn http2_parse_frame_continuation<'a>( input: &'a [u8], dyn_headers: &mut HTTP2DynTable, ) -> IResult<&'a [u8], HTTP2FrameContinuation> { let (i3, blocks) = http2_parse_headers_blocks(input, dyn_headers)?; - return Ok((i3, HTTP2FrameContinuation { blocks })); + return Ok(( + i3, + HTTP2FrameContinuation { + blocks, + end_stream: false, + }, + )); } #[repr(u16)]