From d34443d342adab279690affc55b03608e2eff02a Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Mon, 12 Oct 2026 20:47:35 +0200 Subject: [PATCH 1/5] http2: remove unneeded mut Ticket: 9209 Detection should not modify transactions --- rust/src/http2/detect.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/rust/src/http2/detect.rs b/rust/src/http2/detect.rs index 689d2144c5..ecf4e12ed4 100644 --- a/rust/src/http2/detect.rs +++ b/rust/src/http2/detect.rs @@ -359,7 +359,7 @@ pub unsafe extern "C" fn SCHttp2TxGetHeaderName( } fn http2_frames_get_header_firstvalue<'a>( - tx: &'a mut HTTP2Transaction, direction: Direction, name: &str, + tx: &'a HTTP2Transaction, direction: Direction, name: &str, ) -> Result<&'a [u8], ()> { let frames = if direction == Direction::ToServer { &tx.frames_ts @@ -532,7 +532,7 @@ pub unsafe extern "C" fn SCHttp2TxGetResponseLine( #[no_mangle] pub unsafe extern "C" fn SCHttp2TxGetUri( - tx: &mut HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, + tx: &HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { if let Ok(value) = http2_frames_get_header_firstvalue(tx, Direction::ToServer, ":path") { *buffer = value.as_ptr(); //unsafe @@ -544,7 +544,7 @@ pub unsafe extern "C" fn SCHttp2TxGetUri( #[no_mangle] pub unsafe extern "C" fn SCHttp2TxGetMethod( - tx: &mut HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, + tx: &HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { if let Ok(value) = http2_frames_get_header_firstvalue(tx, Direction::ToServer, ":method") { *buffer = value.as_ptr(); //unsafe @@ -556,7 +556,7 @@ pub unsafe extern "C" fn SCHttp2TxGetMethod( #[no_mangle] pub unsafe extern "C" fn SCHttp2TxGetHost( - tx: &mut HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, tbuf: *mut c_void, + tx: &HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, tbuf: *mut c_void, ) -> u8 { let tbuf = cast_pointer!(tbuf, DetectThreadBuf); if let Some(value) = http2_get_host(tx) { @@ -648,7 +648,7 @@ fn http2_get_host(tx: &HTTP2Transaction) -> Option> { #[no_mangle] pub unsafe extern "C" fn SCHttp2TxGetHostNorm( - tx: &mut HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, tbuf: *mut c_void, + tx: &HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, tbuf: *mut c_void, ) -> u8 { let tbuf = cast_pointer!(tbuf, DetectThreadBuf); if let Some(value) = http2_get_host(tx) { @@ -671,7 +671,7 @@ pub unsafe extern "C" fn SCHttp2TxGetHostNorm( #[no_mangle] pub unsafe extern "C" fn SCHttp2TxGetUserAgent( - tx: &mut HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, tbuf: *mut c_void, + tx: &HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, tbuf: *mut c_void, ) -> u8 { let tbuf = cast_pointer!(tbuf, DetectThreadBuf); if let Some(value) = http2_frames_get_header_value(tx, Direction::ToServer, "user-agent") { @@ -694,7 +694,7 @@ pub unsafe extern "C" fn SCHttp2TxGetUserAgent( #[no_mangle] pub unsafe extern "C" fn SCHttp2TxGetStatus( - tx: &mut HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, + tx: &HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { if let Ok(value) = http2_frames_get_header_firstvalue(tx, Direction::ToClient, ":status") { *buffer = value.as_ptr(); //unsafe @@ -706,7 +706,7 @@ pub unsafe extern "C" fn SCHttp2TxGetStatus( #[no_mangle] pub unsafe extern "C" fn SCHttp2TxGetCookie( - tx: &mut HTTP2Transaction, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32, + tx: &HTTP2Transaction, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32, tbuf: *mut c_void, ) -> u8 { let tbuf = cast_pointer!(tbuf, DetectThreadBuf); @@ -747,7 +747,7 @@ pub unsafe extern "C" fn SCHttp2TxGetCookie( #[no_mangle] pub unsafe extern "C" fn SCHttp2TxGetHeaderValue( - tx: &mut HTTP2Transaction, direction: u8, strname: *const std::os::raw::c_char, + tx: &HTTP2Transaction, direction: u8, strname: *const std::os::raw::c_char, buffer: *mut *const u8, buffer_len: *mut u32, tbuf: *mut c_void, ) -> u8 { let tbuf = cast_pointer!(tbuf, DetectThreadBuf); @@ -785,7 +785,7 @@ fn http2_escape_header(blocks: &[parser::HTTP2FrameHeaderBlock], i: u32, vec: &m #[no_mangle] pub unsafe extern "C" fn SCHttp2TxGetHeaderNames( - tx: &mut HTTP2Transaction, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32, + tx: &HTTP2Transaction, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32, tbuf: *mut c_void, ) -> u8 { let tbuf = cast_pointer!(tbuf, DetectThreadBuf); @@ -849,7 +849,7 @@ fn http2_header_trimspaces(value: &[u8]) -> &[u8] { #[no_mangle] pub unsafe extern "C" fn SCHttp2TxGetHeaders( - tx: &mut HTTP2Transaction, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32, + tx: &HTTP2Transaction, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32, tbuf: *mut c_void, ) -> u8 { let tbuf = cast_pointer!(tbuf, DetectThreadBuf); @@ -883,7 +883,7 @@ pub unsafe extern "C" fn SCHttp2TxGetHeaders( #[no_mangle] pub unsafe extern "C" fn SCHttp2TxGetHeadersRaw( - tx: &mut HTTP2Transaction, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32, + tx: &HTTP2Transaction, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32, tbuf: *mut c_void, ) -> u8 { let tbuf = cast_pointer!(tbuf, DetectThreadBuf); From d135cdc9c76488e8978e325b072f1354554384db Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Wed, 14 Oct 2026 10:38:03 +0200 Subject: [PATCH 2/5] http2: do not update progress on END_STREAM without END_HEADERS As more continuation frames are expected. Next commit will update progress for those continuation frames. Ticket: 9217 --- rust/src/http2/http2.rs | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/rust/src/http2/http2.rs b/rust/src/http2/http2.rs index de51ff4aab..cf286a4773 100644 --- a/rust/src/http2/http2.rs +++ b/rust/src/http2/http2.rs @@ -566,8 +566,10 @@ impl HTTP2Transaction { &mut stream_tx.progress_tc }; match data { - HTTP2FrameTypeData::HEADERS(_) | HTTP2FrameTypeData::DATA => { - if header.flags & parser::HTTP2_FLAG_HEADER_EOS != 0 { + HTTP2FrameTypeData::HEADERS(_) => { + if header.flags & parser::HTTP2_FLAG_HEADER_EOS != 0 + && header.flags & parser::HTTP2_FLAG_HEADER_END_HEADERS != 0 + { if *state < HTTP2TxProgress::HTTP2ProgClosed { *state = HTTP2TxProgress::HTTP2ProgClosed; if stream_tx.progress_ts == HTTP2TxProgress::HTTP2ProgClosed @@ -577,15 +579,26 @@ impl HTTP2Transaction { stream_tx.progress_tc = HTTP2TxProgress::HTTP2ProgComplete; } } - } else if header.ftype == parser::HTTP2FrameType::Data as u8 { - //not end of stream - if *state < HTTP2TxProgress::HTTP2ProgData { - *state = HTTP2TxProgress::HTTP2ProgData; - } } else if *state < HTTP2TxProgress::HTTP2ProgHeaders { *state = HTTP2TxProgress::HTTP2ProgHeaders; } } + HTTP2FrameTypeData::DATA => { + if header.flags & parser::HTTP2_FLAG_HEADER_EOS != 0 { + if *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; + } + } + } else if *state < HTTP2TxProgress::HTTP2ProgData { + //not end of stream + *state = HTTP2TxProgress::HTTP2ProgData; + } + } _ => {} } } From 6d9bb18177e870f35dde3bec79e41b8a889ee2e2 Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Wed, 14 Oct 2026 10:45:27 +0200 Subject: [PATCH 3/5] http2: update progress after continuation frame ended stream Ticket: 9217 --- rust/src/http2/http2.rs | 29 ++++++++++++++++++++++++++--- rust/src/http2/parser.rs | 12 +++++++++++- 2 files changed, 37 insertions(+), 4 deletions(-) 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)] From 22dfd9759fb2ce31116077ffa3c6cf9eb38d0dfa Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Fri, 16 Oct 2026 09:14:33 +0200 Subject: [PATCH 4/5] http2: anomaly event on continuation frame without preceding headers Ticket: 9217 --- rules/http2-events.rules | 1 + rust/src/http2/http2.rs | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/rules/http2-events.rules b/rules/http2-events.rules index 4ff172ee9b..5559212d9a 100644 --- a/rules/http2-events.rules +++ b/rules/http2-events.rules @@ -28,3 +28,4 @@ alert http2 any any -> any any (msg:"SURICATA HTTP2 data on stream zero"; flow:e # alert http2 any any -> any any (msg:"SURICATA HTTP2 too many frames"; flow:established; app-layer-event:http2.too_many_frames; classtype:protocol-command-decode; sid:2290019; rev:1;) alert http2 any any -> any any (msg:"SURICATA HTTP2 compression bomb"; flow:established; app-layer-event:http2.compression_bomb; classtype:protocol-command-decode; sid:2290020; rev:1;) alert http2 any any -> any any (msg:"SURICATA HTTP2 headers table overflow"; flow:established; app-layer-event:http2.header_table_overflow; classtype:protocol-command-decode; sid:2290021; rev:1;) +alert http2 any any -> any any (msg:"SURICATA HTTP2 continuation without headers"; flow:established; app-layer-event:http2.continuation_without_headers; classtype:protocol-command-decode; sid:2290022; rev:1;) diff --git a/rust/src/http2/http2.rs b/rust/src/http2/http2.rs index e64a51a1c7..399341a960 100644 --- a/rust/src/http2/http2.rs +++ b/rust/src/http2/http2.rs @@ -711,6 +711,7 @@ pub enum HTTP2Event { DataStreamZero, TooManyFrames, CompressionBomb, + ContinuationWithoutHeaders, } pub struct HTTP2DynTable { @@ -1261,7 +1262,10 @@ impl HTTP2State { }; return (HTTP2FrameTypeData::CONTINUATION(hs), events); } - } // else try to parse anyways + } else { + events.push(HTTP2Event::ContinuationWithoutHeaders); + } + // else try to parse anyways let input_reass = if head.stream_id == buf.stream_id { &buf.data } else { From d6a36f8eb21aa08a40f3cb969db6cd2f8bd91999 Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Fri, 16 Oct 2026 10:36:18 +0200 Subject: [PATCH 5/5] detect/http2: use DetectThreadBuf fr request/response line Instead of modifying the tx at detect time Ticket: 9209 --- rust/src/http2/detect.rs | 49 ++++++++++++++------------------- rust/src/http2/http2.rs | 5 ---- src/detect-http-request-line.c | 10 ++++++- src/detect-http-response-line.c | 8 +++++- 4 files changed, 37 insertions(+), 35 deletions(-) diff --git a/rust/src/http2/detect.rs b/rust/src/http2/detect.rs index ecf4e12ed4..49bd35d5cc 100644 --- a/rust/src/http2/detect.rs +++ b/rust/src/http2/detect.rs @@ -465,20 +465,16 @@ fn http2_frames_get_header_value<'a>( } // we mutate the tx to cache req_line -fn http2_tx_get_req_line(tx: &mut HTTP2Transaction) { - if !tx.req_line.is_empty() { - return; - } +fn http2_tx_get_req_line(tx: &HTTP2Transaction, tbuf: &mut DetectThreadBuf) { let empty = Vec::new(); - let mut req_line = Vec::new(); let method = if let Ok(value) = http2_frames_get_header_firstvalue(tx, Direction::ToServer, ":method") { value } else { &empty }; - req_line.extend(method); - req_line.push(b' '); + tbuf.data.extend(method); + tbuf.data.push(b' '); let uri = if let Ok(value) = http2_frames_get_header_firstvalue(tx, Direction::ToServer, ":path") { @@ -486,47 +482,44 @@ fn http2_tx_get_req_line(tx: &mut HTTP2Transaction) { } else { &empty }; - req_line.extend(uri); - req_line.extend(b" HTTP/2\r\n"); - tx.req_line.extend(req_line) + tbuf.data.extend(uri); + tbuf.data.extend(b" HTTP/2\r\n"); } #[no_mangle] pub unsafe extern "C" fn SCHttp2TxGetRequestLine( - tx: &mut HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, + tx: &HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, tbuf: *mut c_void, ) -> u8 { - http2_tx_get_req_line(tx); - *buffer = tx.req_line.as_ptr(); //unsafe - *buffer_len = tx.req_line.len() as u32; + let tbuf = cast_pointer!(tbuf, DetectThreadBuf); + tbuf.data.clear(); + http2_tx_get_req_line(tx, tbuf); + *buffer = tbuf.data.as_ptr(); //unsafe + *buffer_len = tbuf.data.len() as u32; return 1; } -fn http2_tx_get_resp_line(tx: &mut HTTP2Transaction) { - if !tx.resp_line.is_empty() { - return; - } +fn http2_tx_get_resp_line(tx: &HTTP2Transaction, tbuf: &mut DetectThreadBuf) { let empty = Vec::new(); - let mut resp_line: Vec = Vec::new(); - let status = if let Ok(value) = http2_frames_get_header_firstvalue(tx, Direction::ToClient, ":status") { value } else { &empty }; - resp_line.extend(b"HTTP/2 "); - resp_line.extend(status); - resp_line.extend(b"\r\n"); - tx.resp_line.extend(resp_line) + tbuf.data.extend(b"HTTP/2 "); + tbuf.data.extend(status); + tbuf.data.extend(b"\r\n"); } #[no_mangle] pub unsafe extern "C" fn SCHttp2TxGetResponseLine( - tx: &mut HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, + tx: &HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, tbuf: *mut c_void, ) -> u8 { - http2_tx_get_resp_line(tx); - *buffer = tx.resp_line.as_ptr(); //unsafe - *buffer_len = tx.resp_line.len() as u32; + let tbuf = cast_pointer!(tbuf, DetectThreadBuf); + tbuf.data.clear(); + http2_tx_get_resp_line(tx, tbuf); + *buffer = tbuf.data.as_ptr(); //unsafe + *buffer_len = tbuf.data.len() as u32; return 1; } diff --git a/rust/src/http2/http2.rs b/rust/src/http2/http2.rs index 399341a960..f53939bb3d 100644 --- a/rust/src/http2/http2.rs +++ b/rust/src/http2/http2.rs @@ -300,9 +300,6 @@ pub struct HTTP2Transaction { pub ft_tc: FileTransferTracker, pub ft_ts: FileTransferTracker, - pub req_line: Vec, - pub resp_line: Vec, - pub doh: Option, } @@ -333,8 +330,6 @@ impl HTTP2Transaction { tx_data: AppLayerTxData::new(), ft_tc: FileTransferTracker::new(), ft_ts: FileTransferTracker::new(), - req_line: Vec::new(), - resp_line: Vec::new(), doh: None, } } diff --git a/src/detect-http-request-line.c b/src/detect-http-request-line.c index e30bd39c9a..74770a410a 100644 --- a/src/detect-http-request-line.c +++ b/src/detect-http-request-line.c @@ -69,6 +69,7 @@ static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, Flow *_f, const uint8_t _flow_flags, void *txv, const int list_id); static int g_http_request_line_buffer_id = 0; +static int g_http2_thread_id = 0; static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, @@ -81,7 +82,11 @@ static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, uint32_t b_len = 0; const uint8_t *b = NULL; - if (SCHttp2TxGetRequestLine(txv, &b, &b_len) != 1) + void *thread_buf = SCDetectThreadCtxGetGlobalKeywordThreadCtx(det_ctx, g_http2_thread_id); + if (thread_buf == NULL) + return NULL; + + if (SCHttp2TxGetRequestLine(txv, &b, &b_len, thread_buf) != 1) return NULL; if (b == NULL || b_len == 0) return NULL; @@ -125,6 +130,9 @@ void DetectHttpRequestLineRegister(void) "http request line"); g_http_request_line_buffer_id = DetectBufferTypeGetByName("http_request_line"); + + g_http2_thread_id = SCDetectRegisterThreadCtxGlobalFuncs( + "http.request_line", SCDetectThreadBufDataInit, NULL, SCDetectThreadBufDataFree); } /** diff --git a/src/detect-http-response-line.c b/src/detect-http-response-line.c index d275178c1a..5d88938a1c 100644 --- a/src/detect-http-response-line.c +++ b/src/detect-http-response-line.c @@ -69,6 +69,7 @@ static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, Flow *_f, const uint8_t _flow_flags, void *txv, const int list_id); static int g_http_response_line_id = 0; +static int g_http2_thread_id = 0; static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, @@ -81,7 +82,10 @@ static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, uint32_t b_len = 0; const uint8_t *b = NULL; - if (SCHttp2TxGetResponseLine(txv, &b, &b_len) != 1) + void *thread_buf = SCDetectThreadCtxGetGlobalKeywordThreadCtx(det_ctx, g_http2_thread_id); + if (thread_buf == NULL) + return NULL; + if (SCHttp2TxGetResponseLine(txv, &b, &b_len, thread_buf) != 1) return NULL; if (b == NULL || b_len == 0) return NULL; @@ -124,6 +128,8 @@ void DetectHttpResponseLineRegister(void) "http response line"); g_http_response_line_id = DetectBufferTypeGetByName("http_response_line"); + g_http2_thread_id = SCDetectRegisterThreadCtxGlobalFuncs( + "http.response_line", SCDetectThreadBufDataInit, NULL, SCDetectThreadBufDataFree); } /**