• 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

83.45
/rust/src/http2/decompression.rs
1
/* Copyright (C) 2021 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::direction::Direction;
19
use brotli;
20
use flate2::read::{DeflateDecoder, GzDecoder};
21
use std;
22
use std::io;
23
use std::io::{Cursor, Read, Write};
24

25
pub const HTTP2_DECOMPRESSION_CHUNK_SIZE: usize = 0x1000; // 4096
26

27
#[repr(u8)]
28
#[derive(Copy, Clone, PartialOrd, PartialEq, Eq, Debug)]
29
pub enum HTTP2ContentEncoding {
30
    Unknown = 0,
31
    Gzip = 1,
32
    Br = 2,
33
    Deflate = 3,
34
    Unrecognized = 4,
35
}
36

37
//a cursor turning EOF into blocking errors
38
#[derive(Debug)]
39
pub struct HTTP2cursor {
40
    pub cursor: Cursor<Vec<u8>>,
41
}
42

43
impl HTTP2cursor {
44
    pub fn new() -> HTTP2cursor {
11✔
45
        HTTP2cursor {
11✔
46
            cursor: Cursor::new(Vec::new()),
11✔
47
        }
11✔
48
    }
11✔
49

50
    pub fn set_position(&mut self, pos: u64) {
22✔
51
        return self.cursor.set_position(pos);
22✔
52
    }
22✔
53

54
    pub fn clear(&mut self) {
22✔
55
        self.cursor.get_mut().clear();
22✔
56
        self.cursor.set_position(0);
22✔
57
    }
22✔
58
}
59

60
// we need to implement this as flate2 and brotli crates
61
// will read from this object
62
impl Read for HTTP2cursor {
63
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
26✔
64
        //use the cursor, except it turns eof into blocking error
26✔
65
        let r = self.cursor.read(buf);
26✔
66
        match r {
26✔
67
            Err(ref err) => {
×
68
                if err.kind() == io::ErrorKind::UnexpectedEof {
×
69
                    return Err(io::ErrorKind::WouldBlock.into());
×
70
                }
×
71
            }
72
            Ok(0) => {
73
                //regular EOF turned into blocking error
74
                return Err(io::ErrorKind::WouldBlock.into());
12✔
75
            }
76
            Ok(_n) => {}
14✔
77
        }
78
        return r;
14✔
79
    }
26✔
80
}
81

82
pub enum HTTP2Decompresser {
83
    Unassigned,
84
    // Box because large.
85
    Gzip(Box<GzDecoder<HTTP2cursor>>),
86
    // Box because large.
87
    Brotli(Box<brotli::Decompressor<HTTP2cursor>>),
88
    // This one is not so large, at 88 bytes as of doing this, but box
89
    // for consistency.
90
    Deflate(Box<DeflateDecoder<HTTP2cursor>>),
91
}
92

93
impl std::fmt::Debug for HTTP2Decompresser {
94
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
×
95
        match self {
×
96
            HTTP2Decompresser::Unassigned => write!(f, "UNASSIGNED"),
×
97
            HTTP2Decompresser::Gzip(_) => write!(f, "GZIP"),
×
98
            HTTP2Decompresser::Brotli(_) => write!(f, "BROTLI"),
×
99
            HTTP2Decompresser::Deflate(_) => write!(f, "DEFLATE"),
×
100
        }
101
    }
×
102
}
103

104
#[derive(Debug)]
105
struct HTTP2DecoderHalf {
106
    encoding: HTTP2ContentEncoding,
107
    decoder: HTTP2Decompresser,
108
}
109

110
pub trait GetMutCursor {
111
    fn get_mut(&mut self) -> &mut HTTP2cursor;
112
}
113

114
impl GetMutCursor for GzDecoder<HTTP2cursor> {
115
    fn get_mut(&mut self) -> &mut HTTP2cursor {
48✔
116
        return self.get_mut();
48✔
117
    }
48✔
118
}
119

120
impl GetMutCursor for DeflateDecoder<HTTP2cursor> {
121
    fn get_mut(&mut self) -> &mut HTTP2cursor {
3✔
122
        return self.get_mut();
3✔
123
    }
3✔
124
}
125

126
impl GetMutCursor for brotli::Decompressor<HTTP2cursor> {
127
    fn get_mut(&mut self) -> &mut HTTP2cursor {
15✔
128
        return self.get_mut();
15✔
129
    }
15✔
130
}
131

132
fn http2_decompress<'a>(
22✔
133
    decoder: &mut (impl Read + GetMutCursor), input: &'a [u8], output: &'a mut Vec<u8>,
22✔
134
) -> io::Result<&'a [u8]> {
22✔
135
    match decoder.get_mut().cursor.write_all(input) {
22✔
136
        Ok(()) => {}
22✔
137
        Err(e) => {
×
138
            return Err(e);
×
139
        }
140
    }
141
    let mut offset = 0;
22✔
142
    decoder.get_mut().set_position(0);
22✔
143
    output.resize(HTTP2_DECOMPRESSION_CHUNK_SIZE, 0);
22✔
144
    loop {
145
        match decoder.read(&mut output[offset..]) {
41✔
146
            Ok(0) => {
147
                break;
18✔
148
            }
149
            Ok(n) => {
19✔
150
                offset += n;
19✔
151
                if offset == output.len() {
19✔
152
                    output.resize(output.len() + HTTP2_DECOMPRESSION_CHUNK_SIZE, 0);
7✔
153
                }
12✔
154
            }
155
            Err(e) => {
4✔
156
                if e.kind() == io::ErrorKind::WouldBlock {
4✔
157
                    break;
4✔
158
                }
×
159
                return Err(e);
×
160
            }
161
        }
162
    }
163
    //brotli does not consume all input if it reaches some end
164
    decoder.get_mut().clear();
22✔
165
    return Ok(&output[..offset]);
22✔
166
}
22✔
167

168
impl HTTP2DecoderHalf {
169
    pub fn new() -> HTTP2DecoderHalf {
340✔
170
        HTTP2DecoderHalf {
340✔
171
            encoding: HTTP2ContentEncoding::Unknown,
340✔
172
            decoder: HTTP2Decompresser::Unassigned,
340✔
173
        }
340✔
174
    }
340✔
175

176
    pub fn http2_encoding_fromvec(&mut self, input: &[u8]) {
11✔
177
        //use first encoding...
11✔
178
        if self.encoding == HTTP2ContentEncoding::Unknown {
11✔
179
            if input == b"gzip" {
11✔
180
                self.encoding = HTTP2ContentEncoding::Gzip;
8✔
181
                self.decoder =
8✔
182
                    HTTP2Decompresser::Gzip(Box::new(GzDecoder::new(HTTP2cursor::new())));
8✔
183
            } else if input == b"deflate" {
8✔
184
                self.encoding = HTTP2ContentEncoding::Deflate;
1✔
185
                self.decoder =
1✔
186
                    HTTP2Decompresser::Deflate(Box::new(DeflateDecoder::new(HTTP2cursor::new())));
1✔
187
            } else if input == b"br" {
2✔
188
                self.encoding = HTTP2ContentEncoding::Br;
2✔
189
                self.decoder = HTTP2Decompresser::Brotli(Box::new(brotli::Decompressor::new(
2✔
190
                    HTTP2cursor::new(),
2✔
191
                    HTTP2_DECOMPRESSION_CHUNK_SIZE,
2✔
192
                )));
2✔
193
            } else {
2✔
194
                self.encoding = HTTP2ContentEncoding::Unrecognized;
×
195
            }
×
196
        }
×
197
    }
11✔
198

199
    pub fn decompress<'a>(
274✔
200
        &mut self, input: &'a [u8], output: &'a mut Vec<u8>,
274✔
201
    ) -> io::Result<&'a [u8]> {
274✔
202
        match self.decoder {
274✔
203
            HTTP2Decompresser::Gzip(ref mut gzip_decoder) => {
16✔
204
                let r = http2_decompress(&mut *gzip_decoder.as_mut(), input, output);
16✔
205
                if r.is_err() {
16✔
206
                    self.decoder = HTTP2Decompresser::Unassigned;
×
207
                }
16✔
208
                return r;
16✔
209
            }
210
            HTTP2Decompresser::Brotli(ref mut br_decoder) => {
5✔
211
                let r = http2_decompress(&mut *br_decoder.as_mut(), input, output);
5✔
212
                if r.is_err() {
5✔
213
                    self.decoder = HTTP2Decompresser::Unassigned;
×
214
                }
5✔
215
                return r;
5✔
216
            }
217
            HTTP2Decompresser::Deflate(ref mut df_decoder) => {
1✔
218
                let r = http2_decompress(&mut *df_decoder.as_mut(), input, output);
1✔
219
                if r.is_err() {
1✔
220
                    self.decoder = HTTP2Decompresser::Unassigned;
×
221
                }
1✔
222
                return r;
1✔
223
            }
224
            _ => {}
252✔
225
        }
252✔
226
        return Ok(input);
252✔
227
    }
274✔
228
}
229

230
#[derive(Debug)]
231
pub struct HTTP2Decoder {
232
    decoder_tc: HTTP2DecoderHalf,
233
    decoder_ts: HTTP2DecoderHalf,
234
}
235

236
impl HTTP2Decoder {
237
    pub fn new() -> HTTP2Decoder {
170✔
238
        HTTP2Decoder {
170✔
239
            decoder_tc: HTTP2DecoderHalf::new(),
170✔
240
            decoder_ts: HTTP2DecoderHalf::new(),
170✔
241
        }
170✔
242
    }
170✔
243

244
    pub fn http2_encoding_fromvec(&mut self, input: &[u8], dir: Direction) {
11✔
245
        if dir == Direction::ToClient {
11✔
246
            self.decoder_tc.http2_encoding_fromvec(input);
11✔
247
        } else {
11✔
248
            self.decoder_ts.http2_encoding_fromvec(input);
×
249
        }
×
250
    }
11✔
251

252
    pub fn decompress<'a>(
274✔
253
        &mut self, input: &'a [u8], output: &'a mut Vec<u8>, dir: Direction,
274✔
254
    ) -> io::Result<&'a [u8]> {
274✔
255
        if dir == Direction::ToClient {
274✔
256
            return self.decoder_tc.decompress(input, output);
221✔
257
        } else {
258
            return self.decoder_ts.decompress(input, output);
53✔
259
        }
260
    }
274✔
261
}
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