• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OISF / suricata / 22550237931

01 Mar 2026 06:56PM UTC coverage: 64.812% (-8.9%) from 73.687%
22550237931

Pull #14920

github

web-flow
Merge e05854a6d into 90823fa90
Pull Request #14920: draft: rust based configuration file parser and loader - v4

561 of 789 new or added lines in 4 files covered. (71.1%)

23225 existing lines in 498 files now uncovered.

131605 of 203055 relevant lines covered (64.81%)

2328818.84 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

65.22
/rust/src/detect/transforms/http_headers.rs
1
/* Copyright (C) 2024 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17

18
use crate::detect::SIGMATCH_NOOPT;
19
use suricata_sys::sys::{
20
    DetectEngineCtx, DetectEngineThreadCtx, InspectionBuffer, SCDetectHelperTransformRegister,
21
    SCDetectSignatureAddTransform, SCInspectionBufferCheckAndExpand, SCInspectionBufferTruncate,
22
    SCTransformTableElmt, Signature,
23
};
24

25
use std::os::raw::{c_int, c_void};
26
use std::ptr;
27

28
static mut G_TRANSFORM_HEADER_LOWER_ID: c_int = 0;
29
static mut G_TRANSFORM_STRIP_PSEUDO_ID: c_int = 0;
30

31
unsafe extern "C" fn header_lowersetup(
166✔
32
    _de: *mut DetectEngineCtx, s: *mut Signature, _raw: *const std::os::raw::c_char,
166✔
33
) -> c_int {
166✔
34
    return SCDetectSignatureAddTransform(s, G_TRANSFORM_HEADER_LOWER_ID, ptr::null_mut());
166✔
35
}
166✔
36

UNCOV
37
fn header_lowertransform_do(input: &[u8], output: &mut [u8]) {
×
UNCOV
38
    let mut state_value = false; // false in name, true in value
×
UNCOV
39
    for (i, o) in input.iter().zip(output.iter_mut()) {
×
UNCOV
40
        if !state_value {
×
UNCOV
41
            if (*i) == b':' {
×
UNCOV
42
                state_value = true;
×
UNCOV
43
                *o = *i;
×
UNCOV
44
            } else {
×
UNCOV
45
                *o = (*i).to_ascii_lowercase();
×
UNCOV
46
            }
×
47
        } else {
UNCOV
48
            *o = *i;
×
UNCOV
49
            if (*i) == b'\n' {
×
UNCOV
50
                state_value = false;
×
UNCOV
51
            }
×
52
        }
53
    }
UNCOV
54
}
×
55

UNCOV
56
unsafe extern "C" fn header_lowertransform(
×
UNCOV
57
    _det: *mut DetectEngineThreadCtx, buffer: *mut InspectionBuffer, _ctx: *mut c_void,
×
UNCOV
58
) {
×
UNCOV
59
    let input = (*buffer).inspect;
×
UNCOV
60
    let input_len = (*buffer).inspect_len;
×
UNCOV
61
    if input.is_null() || input_len == 0 {
×
62
        return;
×
UNCOV
63
    }
×
UNCOV
64
    let input = build_slice!(input, input_len as usize);
×
UNCOV
65

×
UNCOV
66
    let output = SCInspectionBufferCheckAndExpand(buffer, input_len);
×
UNCOV
67
    if output.is_null() {
×
68
        // allocation failure
69
        return;
×
UNCOV
70
    }
×
UNCOV
71
    let output = std::slice::from_raw_parts_mut(output, input_len as usize);
×
UNCOV
72

×
UNCOV
73
    header_lowertransform_do(input, output);
×
UNCOV
74

×
UNCOV
75
    SCInspectionBufferTruncate(buffer, input_len);
×
UNCOV
76
}
×
77

78
#[no_mangle]
79
pub unsafe extern "C" fn DetectTransformHeaderLowercaseRegister() {
30✔
80
    let kw = SCTransformTableElmt {
30✔
81
        name: b"header_lowercase\0".as_ptr() as *const libc::c_char,
30✔
82
        desc: b"modify buffer via lowercaseing header names\0".as_ptr() as *const libc::c_char,
30✔
83
        url: b"/rules/transforms.html#header_lowercase\0".as_ptr() as *const libc::c_char,
30✔
84
        Setup: Some(header_lowersetup),
30✔
85
        flags: SIGMATCH_NOOPT,
30✔
86
        Transform: Some(header_lowertransform),
30✔
87
        Free: None,
30✔
88
        TransformValidate: None,
30✔
89
        TransformId: None,
30✔
90
    };
30✔
91
    G_TRANSFORM_HEADER_LOWER_ID = SCDetectHelperTransformRegister(&kw);
30✔
92
    if G_TRANSFORM_HEADER_LOWER_ID < 0 {
30✔
93
        SCLogWarning!("Failed registering transform tolower");
×
94
    }
30✔
95
}
30✔
96

97
unsafe extern "C" fn strip_pseudo_setup(
96✔
98
    _de: *mut DetectEngineCtx, s: *mut Signature, _raw: *const std::os::raw::c_char,
96✔
99
) -> c_int {
96✔
100
    return SCDetectSignatureAddTransform(s, G_TRANSFORM_STRIP_PSEUDO_ID, ptr::null_mut());
96✔
101
}
96✔
102

103
fn strip_pseudo_transform_do(input: &[u8], output: &mut [u8]) -> u32 {
53✔
104
    let mut nb = 0;
53✔
105
    let mut inb = 0;
53✔
106
    let same = std::ptr::eq(output.as_ptr(), input.as_ptr());
53✔
107
    for subslice in input.split_inclusive(|c| *c == b'\n') {
2,471✔
108
        if !subslice.is_empty() && subslice[0] != b':' {
316✔
109
            if same {
310✔
UNCOV
110
                output.copy_within(inb..inb + subslice.len(), nb);
×
111
            } else {
310✔
112
                output[nb..nb + subslice.len()].copy_from_slice(subslice);
310✔
113
            }
310✔
114
            nb += subslice.len();
310✔
115
        }
6✔
116
        inb += subslice.len();
316✔
117
    }
118
    return nb as u32;
53✔
119
}
53✔
120

121
unsafe extern "C" fn strip_pseudo_transform(
53✔
122
    _det: *mut DetectEngineThreadCtx, buffer: *mut InspectionBuffer, _ctx: *mut c_void,
53✔
123
) {
53✔
124
    let input = (*buffer).inspect;
53✔
125
    let input_len = (*buffer).inspect_len;
53✔
126
    if input.is_null() || input_len == 0 {
53✔
127
        return;
×
128
    }
53✔
129
    let input = build_slice!(input, input_len as usize);
53✔
130

53✔
131
    let output = SCInspectionBufferCheckAndExpand(buffer, input_len);
53✔
132
    if output.is_null() {
53✔
133
        // allocation failure
134
        return;
×
135
    }
53✔
136
    let output = std::slice::from_raw_parts_mut(output, input_len as usize);
53✔
137

53✔
138
    let out_len = strip_pseudo_transform_do(input, output);
53✔
139

53✔
140
    SCInspectionBufferTruncate(buffer, out_len);
53✔
141
}
53✔
142

143
#[no_mangle]
144
pub unsafe extern "C" fn DetectTransformStripPseudoHeadersRegister() {
30✔
145
    let kw = SCTransformTableElmt {
30✔
146
        name: b"strip_pseudo_headers\0".as_ptr() as *const libc::c_char,
30✔
147
        desc: b"modify buffer via stripping pseudo headers\0".as_ptr() as *const libc::c_char,
30✔
148
        url: b"/rules/transforms.html#strip_pseudo_headers\0".as_ptr() as *const libc::c_char,
30✔
149
        Setup: Some(strip_pseudo_setup),
30✔
150
        flags: SIGMATCH_NOOPT,
30✔
151
        Transform: Some(strip_pseudo_transform),
30✔
152
        Free: None,
30✔
153
        TransformValidate: None,
30✔
154
        TransformId: None,
30✔
155
    };
30✔
156
    G_TRANSFORM_STRIP_PSEUDO_ID = SCDetectHelperTransformRegister(&kw);
30✔
157
    if G_TRANSFORM_STRIP_PSEUDO_ID < 0 {
30✔
158
        SCLogWarning!("Failed registering transform toupper");
×
159
    }
30✔
160
}
30✔
161

162
#[cfg(test)]
163
mod tests {
164
    use super::*;
165

166
    #[test]
167
    fn test_header_lowertransform() {
168
        let buf = b"Header1: Value1\nheader2:Value2\n";
169
        let mut out = vec![0; buf.len()];
170
        header_lowertransform_do(buf, &mut out);
171
        assert_eq!(out, b"header1: Value1\nheader2:Value2\n");
172
    }
173

174
    #[test]
175
    fn test_strip_pseudo_transform() {
176
        let buf = b"Header1: Value1\n:method:get\nheader2:Value2\n";
177
        let mut out = vec![0; buf.len()];
178
        let nb = strip_pseudo_transform_do(buf, &mut out);
179
        assert_eq!(&out[..nb as usize], b"Header1: Value1\nheader2:Value2\n");
180
        let buf = b":method:get";
181
        let mut out = vec![0; buf.len()];
182
        let nb = strip_pseudo_transform_do(buf, &mut out);
183
        assert_eq!(nb, 0);
184
        let buf = b"Header1: Value1\n:method:get";
185
        let mut out = vec![0; buf.len()];
186
        let nb = strip_pseudo_transform_do(buf, &mut out);
187
        assert_eq!(&out[..nb as usize], b"Header1: Value1\n");
188
        let buf = b":method:get\nheader2:Value2";
189
        let mut out = vec![0; buf.len()];
190
        let nb = strip_pseudo_transform_do(buf, &mut out);
191
        assert_eq!(&out[..nb as usize], b"header2:Value2");
192
        let mut buf = Vec::new();
193
        buf.extend_from_slice(
194
            b"Header1: Value1\n:method:get\nheader2:Value2\n:scheme:https\nheader3:Value3\n",
195
        );
196
        // test in place
197
        let still_buf = unsafe { std::slice::from_raw_parts(buf.as_ptr(), buf.len()) };
198
        let nb = strip_pseudo_transform_do(still_buf, &mut buf);
199
        assert_eq!(
200
            &still_buf[..nb as usize],
201
            b"Header1: Value1\nheader2:Value2\nheader3:Value3\n"
202
        );
203
    }
204
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc