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

OISF / suricata / 22618661228

02 Mar 2026 09:33PM UTC coverage: 42.258% (-34.4%) from 76.611%
22618661228

push

github

victorjulien
github-actions: bump actions/download-artifact from 7.0.0 to 8.0.0

Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 7.0.0 to 8.0.0.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/37930b1c2...70fc10c6e)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: 8.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

91511 of 216553 relevant lines covered (42.26%)

3416852.41 hits per line

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

86.01
/rust/src/http2/logger.rs
1
/* Copyright (C) 2020 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 super::http2::{HTTP2Frame, HTTP2FrameTypeData, HTTP2Transaction};
19
use super::parser;
20
use crate::detect::EnumString;
21
use crate::jsonbuilder::{JsonBuilder, JsonError};
22
use std;
23
use std::collections::{HashMap, HashSet};
24
use std::rc::Rc;
25

26
#[derive(Hash, PartialEq, Eq, Debug)]
27
enum HeaderName {
28
    Method,
29
    Path,
30
    Host,
31
    UserAgent,
32
    Status,
33
    ContentLength,
34
}
35

36
fn log_http2_headers<'a>(
410✔
37
    blocks: &'a [parser::HTTP2FrameHeaderBlock], js: &mut JsonBuilder,
410✔
38
    common: &mut HashMap<HeaderName, &'a Vec<u8>>,
410✔
39
) -> Result<(), JsonError> {
410✔
40
    let mut logged_headers = HashSet::new();
410✔
41
    for block in blocks {
4,268✔
42
        // delay js.start_object() because we skip suplicate headers
43
        match block.error {
3,858✔
44
            parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSuccess => {
45
                if Rc::strong_count(&block.name) > 2 {
3,842✔
46
                    // more than one reference in headers table + current headers
47
                    let ptr = Rc::as_ptr(&block.name) as usize;
1,265✔
48
                    if !logged_headers.insert(ptr) {
1,265✔
49
                        // only log once
50
                        continue;
6✔
51
                    }
1,259✔
52
                }
2,577✔
53
                js.start_object()?;
3,836✔
54
                js.set_string_from_bytes("name", &block.name)?;
3,836✔
55
                js.set_string_from_bytes("value", &block.value)?;
3,836✔
56
                if let Ok(name) = std::str::from_utf8(&block.name) {
3,836✔
57
                    match name.to_lowercase().as_ref() {
3,836✔
58
                        ":method" => {
3,836✔
59
                            common.insert(HeaderName::Method, &block.value);
177✔
60
                        }
177✔
61
                        ":path" => {
3,659✔
62
                            common.insert(HeaderName::Path, &block.value);
177✔
63
                        }
177✔
64
                        ":status" => {
3,482✔
65
                            common.insert(HeaderName::Status, &block.value);
165✔
66
                        }
165✔
67
                        "user-agent" => {
3,317✔
68
                            common.insert(HeaderName::UserAgent, &block.value);
175✔
69
                        }
175✔
70
                        "host" => {
3,142✔
71
                            common.insert(HeaderName::Host, &block.value);
4✔
72
                        }
4✔
73
                        "content-length" => {
3,138✔
74
                            common.insert(HeaderName::ContentLength, &block.value);
280✔
75
                        }
280✔
76
                        _ => {}
2,858✔
77
                    }
78
                }
×
79
            }
80
            parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSizeUpdate => {
81
                js.start_object()?;
16✔
82
                js.set_uint("table_size_update", block.sizeupdate)?;
16✔
83
            }
84
            _ => {
85
                js.start_object()?;
×
86
                js.set_string("error", &block.error.to_string())?;
×
87
            }
88
        }
89
        js.close()?;
3,852✔
90
    }
91
    return Ok(());
410✔
92
}
410✔
93

94
fn log_headers<'a>(
562✔
95
    frames: &'a Vec<HTTP2Frame>, js: &mut JsonBuilder,
562✔
96
    common: &mut HashMap<HeaderName, &'a Vec<u8>>,
562✔
97
) -> Result<bool, JsonError> {
562✔
98
    let mut has_headers = false;
562✔
99
    for frame in frames {
1,794✔
100
        match &frame.data {
1,232✔
101
            HTTP2FrameTypeData::HEADERS(hd) => {
406✔
102
                log_http2_headers(&hd.blocks, js, common)?;
406✔
103
                has_headers = true;
406✔
104
            }
105
            HTTP2FrameTypeData::PUSHPROMISE(hd) => {
×
106
                log_http2_headers(&hd.blocks, js, common)?;
×
107
                has_headers = true;
×
108
            }
109
            HTTP2FrameTypeData::CONTINUATION(hd) => {
4✔
110
                log_http2_headers(&hd.blocks, js, common)?;
4✔
111
                has_headers = true;
4✔
112
            }
113
            _ => {}
822✔
114
        }
115
    }
116
    Ok(has_headers)
562✔
117
}
562✔
118

119
fn log_http2_frames(frames: &[HTTP2Frame], js: &mut JsonBuilder) -> Result<bool, JsonError> {
562✔
120
    let mut has_settings = false;
562✔
121
    for frame in frames {
1,794✔
122
        if let HTTP2FrameTypeData::SETTINGS(set) = &frame.data {
1,232✔
123
            if !has_settings {
33✔
124
                js.open_array("settings")?;
33✔
125
                has_settings = true;
33✔
126
            }
×
127
            for e in set {
144✔
128
                js.start_object()?;
111✔
129
                js.set_string(
111✔
130
                    "settings_id",
111✔
131
                    &format!("SETTINGS{}", &e.id.to_string().to_uppercase()),
111✔
132
                )?;
111✔
133
                js.set_uint("settings_value", e.value as u64)?;
111✔
134
                js.close()?;
111✔
135
            }
136
        }
1,199✔
137
    }
138
    if has_settings {
562✔
139
        js.close()?;
33✔
140
    }
529✔
141

142
    let mut has_error_code = false;
562✔
143
    let mut has_priority = false;
562✔
144
    let mut has_multiple = false;
562✔
145
    for frame in frames {
1,794✔
146
        match &frame.data {
1,232✔
147
            HTTP2FrameTypeData::GOAWAY(goaway) => {
6✔
148
                if !has_error_code {
6✔
149
                    if let Some(errcode) = parser::HTTP2ErrorCode::from_u(goaway.errorcode) {
6✔
150
                        js.set_string("error_code", errcode.to_str())?;
6✔
151
                    } else {
152
                        js.set_string("error_code", &format!("unknown-{}", goaway.errorcode))?;
×
153
                    }
154
                    has_error_code = true;
6✔
155
                } else if !has_multiple {
×
156
                    js.set_string("has_multiple", "error_code")?;
×
157
                    has_multiple = true;
×
158
                }
×
159
            }
160
            HTTP2FrameTypeData::RSTSTREAM(rst) => {
23✔
161
                if !has_error_code {
23✔
162
                    if let Some(errcode) = parser::HTTP2ErrorCode::from_u(rst.errorcode) {
16✔
163
                        js.set_string("error_code", errcode.to_str())?;
16✔
164
                    } else {
165
                        js.set_string("error_code", &format!("unknown-{}", rst.errorcode))?;
×
166
                    }
167
                    has_error_code = true;
16✔
168
                } else if !has_multiple {
7✔
169
                    js.set_string("has_multiple", "error_code")?;
1✔
170
                    has_multiple = true;
1✔
171
                }
6✔
172
            }
173
            HTTP2FrameTypeData::PRIORITY(priority) => {
6✔
174
                if !has_priority {
6✔
175
                    js.set_uint("priority", priority.weight as u64)?;
6✔
176
                    has_priority = true;
6✔
177
                } else if !has_multiple {
×
178
                    js.set_string("has_multiple", "priority")?;
×
179
                    has_multiple = true;
×
180
                }
×
181
            }
182
            HTTP2FrameTypeData::HEADERS(hd) => {
406✔
183
                if let Some(ref priority) = hd.priority {
406✔
184
                    if !has_priority {
148✔
185
                        js.set_uint("priority", priority.weight as u64)?;
148✔
186
                        has_priority = true;
148✔
187
                    } else if !has_multiple {
×
188
                        js.set_string("has_multiple", "priority")?;
×
189
                        has_multiple = true;
×
190
                    }
×
191
                }
258✔
192
            }
193
            _ => {}
791✔
194
        }
195
    }
196
    return Ok(has_settings || has_error_code || has_priority);
562✔
197
}
562✔
198

199
fn log_http2(tx: &HTTP2Transaction, js: &mut JsonBuilder) -> Result<bool, JsonError> {
281✔
200
    js.open_object("http")?;
281✔
201
    js.set_string("version", "2")?;
281✔
202

203
    let mut common: HashMap<HeaderName, &Vec<u8>> = HashMap::new();
281✔
204

281✔
205
    let mut has_headers = false;
281✔
206

281✔
207
    // Request headers.
281✔
208
    let mark = js.get_mark();
281✔
209
    js.open_array("request_headers")?;
281✔
210
    if log_headers(&tx.frames_ts, js, &mut common)? {
281✔
211
        js.close()?;
175✔
212
        has_headers = true;
175✔
213
    } else {
214
        js.restore_mark(&mark)?;
106✔
215
    }
216

217
    // Response headers.
218
    let mark = js.get_mark();
281✔
219
    js.open_array("response_headers")?;
281✔
220
    if log_headers(&tx.frames_tc, js, &mut common)? {
281✔
221
        js.close()?;
165✔
222
        has_headers = true;
165✔
223
    } else {
224
        js.restore_mark(&mark)?;
116✔
225
    }
226

227
    for (name, value) in common {
1,138✔
228
        match name {
857✔
229
            HeaderName::Method => {
230
                js.set_string_from_bytes("http_method", value)?;
175✔
231
            }
232
            HeaderName::Path => {
233
                js.set_string_from_bytes("url", value)?;
175✔
234
            }
235
            HeaderName::Host => {
236
                js.set_string_from_bytes("hostname", value)?;
4✔
237
            }
238
            HeaderName::UserAgent => {
239
                js.set_string_from_bytes("http_user_agent", value)?;
175✔
240
            }
241
            HeaderName::ContentLength => {
242
                if let Ok(value) = std::str::from_utf8(value) {
163✔
243
                    if let Ok(value) = value.parse::<u64>() {
163✔
244
                        js.set_uint("length", value)?;
163✔
245
                    }
×
246
                }
×
247
            }
248
            HeaderName::Status => {
249
                if let Ok(value) = std::str::from_utf8(value) {
165✔
250
                    if let Ok(value) = value.parse::<u64>() {
165✔
251
                        js.set_uint("status", value)?;
165✔
252
                    }
×
253
                }
×
254
            }
255
        }
256
    }
257

258
    // The rest of http2 logging is placed in an "http2" object.
259
    js.open_object("http2")?;
281✔
260

261
    js.set_uint("stream_id", tx.stream_id as u64)?;
281✔
262
    let mark = js.get_mark();
281✔
263
    js.open_object("request")?;
281✔
264
    let has_request = log_http2_frames(&tx.frames_ts, js)?;
281✔
265
    if has_request {
281✔
266
        js.close()?;
177✔
267
    } else {
268
        js.restore_mark(&mark)?;
104✔
269
    }
270

271
    let mark = js.get_mark();
281✔
272
    js.open_object("response")?;
281✔
273
    let has_response = log_http2_frames(&tx.frames_tc, js)?;
281✔
274
    if has_response {
281✔
275
        js.close()?;
30✔
276
    } else {
277
        js.restore_mark(&mark)?;
251✔
278
    }
279

280
    js.close()?; // http2
281✔
281
    js.close()?; // http
281✔
282

283
    return Ok(has_request || has_response || has_headers);
281✔
284
}
281✔
285

286
#[no_mangle]
287
pub unsafe extern "C" fn SCHttp2LogJson(
281✔
288
    tx: *mut std::os::raw::c_void, js: &mut JsonBuilder,
281✔
289
) -> bool {
281✔
290
    let tx = cast_pointer!(tx, HTTP2Transaction);
281✔
291
    if let Ok(x) = log_http2(tx, js) {
281✔
292
        return x;
281✔
293
    }
×
294
    return false;
×
295
}
281✔
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