Coverage Report

Created: 2026-02-14 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/flate2-1.0.35/src/gz/mod.rs
Line
Count
Source
1
use std::ffi::CString;
2
use std::io::{BufRead, Error, ErrorKind, Read, Result, Write};
3
use std::time;
4
5
use crate::bufreader::BufReader;
6
use crate::{Compression, Crc};
7
8
pub static FHCRC: u8 = 1 << 1;
9
pub static FEXTRA: u8 = 1 << 2;
10
pub static FNAME: u8 = 1 << 3;
11
pub static FCOMMENT: u8 = 1 << 4;
12
pub static FRESERVED: u8 = 1 << 5 | 1 << 6 | 1 << 7;
13
14
pub mod bufread;
15
pub mod read;
16
pub mod write;
17
18
// The maximum length of the header filename and comment fields. More than
19
// enough for these fields in reasonable use, but prevents possible attacks.
20
const MAX_HEADER_BUF: usize = 65535;
21
22
/// A structure representing the header of a gzip stream.
23
///
24
/// The header can contain metadata about the file that was compressed, if
25
/// present.
26
#[derive(PartialEq, Clone, Debug, Default)]
27
pub struct GzHeader {
28
    extra: Option<Vec<u8>>,
29
    filename: Option<Vec<u8>>,
30
    comment: Option<Vec<u8>>,
31
    operating_system: u8,
32
    mtime: u32,
33
}
34
35
impl GzHeader {
36
    /// Returns the `filename` field of this gzip stream's header, if present.
37
0
    pub fn filename(&self) -> Option<&[u8]> {
38
0
        self.filename.as_ref().map(|s| &s[..])
Unexecuted instantiation: <flate2::gz::GzHeader>::filename::{closure#0}
Unexecuted instantiation: <flate2::gz::GzHeader>::filename::{closure#0}
39
0
    }
Unexecuted instantiation: <flate2::gz::GzHeader>::filename
Unexecuted instantiation: <flate2::gz::GzHeader>::filename
40
41
    /// Returns the `extra` field of this gzip stream's header, if present.
42
0
    pub fn extra(&self) -> Option<&[u8]> {
43
0
        self.extra.as_ref().map(|s| &s[..])
Unexecuted instantiation: <flate2::gz::GzHeader>::extra::{closure#0}
Unexecuted instantiation: <flate2::gz::GzHeader>::extra::{closure#0}
44
0
    }
Unexecuted instantiation: <flate2::gz::GzHeader>::extra
Unexecuted instantiation: <flate2::gz::GzHeader>::extra
45
46
    /// Returns the `comment` field of this gzip stream's header, if present.
47
0
    pub fn comment(&self) -> Option<&[u8]> {
48
0
        self.comment.as_ref().map(|s| &s[..])
Unexecuted instantiation: <flate2::gz::GzHeader>::comment::{closure#0}
Unexecuted instantiation: <flate2::gz::GzHeader>::comment::{closure#0}
49
0
    }
Unexecuted instantiation: <flate2::gz::GzHeader>::comment
Unexecuted instantiation: <flate2::gz::GzHeader>::comment
50
51
    /// Returns the `operating_system` field of this gzip stream's header.
52
    ///
53
    /// There are predefined values for various operating systems.
54
    /// 255 means that the value is unknown.
55
0
    pub fn operating_system(&self) -> u8 {
56
0
        self.operating_system
57
0
    }
Unexecuted instantiation: <flate2::gz::GzHeader>::operating_system
Unexecuted instantiation: <flate2::gz::GzHeader>::operating_system
58
59
    /// This gives the most recent modification time of the original file being compressed.
60
    ///
61
    /// The time is in Unix format, i.e., seconds since 00:00:00 GMT, Jan. 1, 1970.
62
    /// (Note that this may cause problems for MS-DOS and other systems that use local
63
    /// rather than Universal time.) If the compressed data did not come from a file,
64
    /// `mtime` is set to the time at which compression started.
65
    /// `mtime` = 0 means no time stamp is available.
66
    ///
67
    /// The usage of `mtime` is discouraged because of Year 2038 problem.
68
0
    pub fn mtime(&self) -> u32 {
69
0
        self.mtime
70
0
    }
Unexecuted instantiation: <flate2::gz::GzHeader>::mtime
Unexecuted instantiation: <flate2::gz::GzHeader>::mtime
71
72
    /// Returns the most recent modification time represented by a date-time type.
73
    /// Returns `None` if the value of the underlying counter is 0,
74
    /// indicating no time stamp is available.
75
    ///
76
    ///
77
    /// The time is measured as seconds since 00:00:00 GMT, Jan. 1 1970.
78
    /// See [`mtime`](#method.mtime) for more detail.
79
0
    pub fn mtime_as_datetime(&self) -> Option<time::SystemTime> {
80
0
        if self.mtime == 0 {
81
0
            None
82
        } else {
83
0
            let duration = time::Duration::new(u64::from(self.mtime), 0);
84
0
            let datetime = time::UNIX_EPOCH + duration;
85
0
            Some(datetime)
86
        }
87
0
    }
Unexecuted instantiation: <flate2::gz::GzHeader>::mtime_as_datetime
Unexecuted instantiation: <flate2::gz::GzHeader>::mtime_as_datetime
88
}
89
90
#[derive(Debug)]
91
pub enum GzHeaderState {
92
    Start(u8, [u8; 10]),
93
    Xlen(Option<Box<Crc>>, u8, [u8; 2]),
94
    Extra(Option<Box<Crc>>, u16),
95
    Filename(Option<Box<Crc>>),
96
    Comment(Option<Box<Crc>>),
97
    Crc(Option<Box<Crc>>, u8, [u8; 2]),
98
    Complete,
99
}
100
101
impl Default for GzHeaderState {
102
22.4k
    fn default() -> Self {
103
22.4k
        Self::Complete
104
22.4k
    }
<flate2::gz::GzHeaderState as core::default::Default>::default
Line
Count
Source
102
13.5k
    fn default() -> Self {
103
13.5k
        Self::Complete
104
13.5k
    }
<flate2::gz::GzHeaderState as core::default::Default>::default
Line
Count
Source
102
8.93k
    fn default() -> Self {
103
8.93k
        Self::Complete
104
8.93k
    }
105
}
106
107
#[derive(Debug, Default)]
108
pub struct GzHeaderParser {
109
    state: GzHeaderState,
110
    flags: u8,
111
    header: GzHeader,
112
}
113
114
impl GzHeaderParser {
115
35.8k
    fn new() -> Self {
116
35.8k
        GzHeaderParser {
117
35.8k
            state: GzHeaderState::Start(0, [0; 10]),
118
35.8k
            flags: 0,
119
35.8k
            header: GzHeader::default(),
120
35.8k
        }
121
35.8k
    }
<flate2::gz::GzHeaderParser>::new
Line
Count
Source
115
23.9k
    fn new() -> Self {
116
23.9k
        GzHeaderParser {
117
23.9k
            state: GzHeaderState::Start(0, [0; 10]),
118
23.9k
            flags: 0,
119
23.9k
            header: GzHeader::default(),
120
23.9k
        }
121
23.9k
    }
<flate2::gz::GzHeaderParser>::new
Line
Count
Source
115
11.9k
    fn new() -> Self {
116
11.9k
        GzHeaderParser {
117
11.9k
            state: GzHeaderState::Start(0, [0; 10]),
118
11.9k
            flags: 0,
119
11.9k
            header: GzHeader::default(),
120
11.9k
        }
121
11.9k
    }
122
123
113k
    fn parse<'a, R: Read>(&mut self, r: &'a mut R) -> Result<()> {
124
        loop {
125
260k
            match &mut self.state {
126
106k
                GzHeaderState::Start(count, buffer) => {
127
176k
                    while (*count as usize) < buffer.len() {
128
141k
                        *count += read_into(r, &mut buffer[*count as usize..])? as u8;
129
                    }
130
                    // Gzip identification bytes
131
34.7k
                    if buffer[0] != 0x1f || buffer[1] != 0x8b {
132
2.57k
                        return Err(bad_header());
133
32.1k
                    }
134
                    // Gzip compression method (8 = deflate)
135
32.1k
                    if buffer[2] != 8 {
136
526
                        return Err(bad_header());
137
31.6k
                    }
138
31.6k
                    self.flags = buffer[3];
139
                    // RFC1952: "must give an error indication if any reserved bit is non-zero"
140
31.6k
                    if self.flags & FRESERVED != 0 {
141
772
                        return Err(bad_header());
142
30.8k
                    }
143
30.8k
                    self.header.mtime = ((buffer[4] as u32) << 0)
144
30.8k
                        | ((buffer[5] as u32) << 8)
145
30.8k
                        | ((buffer[6] as u32) << 16)
146
30.8k
                        | ((buffer[7] as u32) << 24);
147
30.8k
                    let _xfl = buffer[8];
148
30.8k
                    self.header.operating_system = buffer[9];
149
30.8k
                    let crc = if self.flags & FHCRC != 0 {
150
7.53k
                        let mut crc = Box::new(Crc::new());
151
7.53k
                        crc.update(buffer);
152
7.53k
                        Some(crc)
153
                    } else {
154
23.3k
                        None
155
                    };
156
30.8k
                    self.state = GzHeaderState::Xlen(crc, 0, [0; 2]);
157
                }
158
31.4k
                GzHeaderState::Xlen(crc, count, buffer) => {
159
31.4k
                    if self.flags & FEXTRA != 0 {
160
29.9k
                        while (*count as usize) < buffer.len() {
161
16.8k
                            *count += read_into(r, &mut buffer[*count as usize..])? as u8;
162
                        }
163
13.1k
                        if let Some(crc) = crc {
164
4.22k
                            crc.update(buffer);
165
8.91k
                        }
166
13.1k
                        let xlen = parse_le_u16(&buffer);
167
13.1k
                        self.header.extra = Some(vec![0; xlen as usize]);
168
13.1k
                        self.state = GzHeaderState::Extra(crc.take(), 0);
169
16.2k
                    } else {
170
16.2k
                        self.state = GzHeaderState::Filename(crc.take());
171
16.2k
                    }
172
                }
173
15.4k
                GzHeaderState::Extra(crc, count) => {
174
15.4k
                    debug_assert!(self.header.extra.is_some());
175
15.4k
                    let extra = self.header.extra.as_mut().unwrap();
176
25.6k
                    while (*count as usize) < extra.len() {
177
13.9k
                        *count += read_into(r, &mut extra[*count as usize..])? as u16;
178
                    }
179
11.6k
                    if let Some(crc) = crc {
180
3.22k
                        crc.update(extra);
181
8.41k
                    }
182
11.6k
                    self.state = GzHeaderState::Filename(crc.take());
183
                }
184
29.5k
                GzHeaderState::Filename(crc) => {
185
29.5k
                    if self.flags & FNAME != 0 {
186
13.9k
                        let filename = self.header.filename.get_or_insert_with(Vec::new);
187
13.9k
                        read_to_nul(r, filename)?;
188
11.0k
                        if let Some(crc) = crc {
189
3.54k
                            crc.update(filename);
190
3.54k
                            crc.update(b"\0");
191
7.47k
                        }
192
15.5k
                    }
193
26.5k
                    self.state = GzHeaderState::Comment(crc.take());
194
                }
195
28.1k
                GzHeaderState::Comment(crc) => {
196
28.1k
                    if self.flags & FCOMMENT != 0 {
197
11.9k
                        let comment = self.header.comment.get_or_insert_with(Vec::new);
198
11.9k
                        read_to_nul(r, comment)?;
199
9.67k
                        if let Some(crc) = crc {
200
2.46k
                            crc.update(comment);
201
2.46k
                            crc.update(b"\0");
202
7.20k
                        }
203
16.1k
                    }
204
25.8k
                    self.state = GzHeaderState::Crc(crc.take(), 0, [0; 2]);
205
                }
206
26.9k
                GzHeaderState::Crc(crc, count, buffer) => {
207
26.9k
                    if let Some(crc) = crc {
208
4.66k
                        debug_assert!(self.flags & FHCRC != 0);
209
8.36k
                        while (*count as usize) < buffer.len() {
210
5.99k
                            *count += read_into(r, &mut buffer[*count as usize..])? as u8;
211
                        }
212
2.37k
                        let stored_crc = parse_le_u16(&buffer);
213
2.37k
                        let calced_crc = crc.sum() as u16;
214
2.37k
                        if stored_crc != calced_crc {
215
2.17k
                            return Err(corrupt());
216
196
                        }
217
22.2k
                    }
218
22.4k
                    self.state = GzHeaderState::Complete;
219
                }
220
                GzHeaderState::Complete => {
221
22.4k
                    return Ok(());
222
                }
223
            }
224
        }
225
113k
    }
<flate2::gz::GzHeaderParser>::parse::<flate2::bufreader::BufReader<suricata::http2::decompression::HTTP2cursor>>
Line
Count
Source
123
75.2k
    fn parse<'a, R: Read>(&mut self, r: &'a mut R) -> Result<()> {
124
        loop {
125
167k
            match &mut self.state {
126
70.7k
                GzHeaderState::Start(count, buffer) => {
127
117k
                    while (*count as usize) < buffer.len() {
128
94.1k
                        *count += read_into(r, &mut buffer[*count as usize..])? as u8;
129
                    }
130
                    // Gzip identification bytes
131
22.9k
                    if buffer[0] != 0x1f || buffer[1] != 0x8b {
132
1.95k
                        return Err(bad_header());
133
21.0k
                    }
134
                    // Gzip compression method (8 = deflate)
135
21.0k
                    if buffer[2] != 8 {
136
440
                        return Err(bad_header());
137
20.5k
                    }
138
20.5k
                    self.flags = buffer[3];
139
                    // RFC1952: "must give an error indication if any reserved bit is non-zero"
140
20.5k
                    if self.flags & FRESERVED != 0 {
141
567
                        return Err(bad_header());
142
19.9k
                    }
143
19.9k
                    self.header.mtime = ((buffer[4] as u32) << 0)
144
19.9k
                        | ((buffer[5] as u32) << 8)
145
19.9k
                        | ((buffer[6] as u32) << 16)
146
19.9k
                        | ((buffer[7] as u32) << 24);
147
19.9k
                    let _xfl = buffer[8];
148
19.9k
                    self.header.operating_system = buffer[9];
149
19.9k
                    let crc = if self.flags & FHCRC != 0 {
150
5.99k
                        let mut crc = Box::new(Crc::new());
151
5.99k
                        crc.update(buffer);
152
5.99k
                        Some(crc)
153
                    } else {
154
14.0k
                        None
155
                    };
156
19.9k
                    self.state = GzHeaderState::Xlen(crc, 0, [0; 2]);
157
                }
158
20.2k
                GzHeaderState::Xlen(crc, count, buffer) => {
159
20.2k
                    if self.flags & FEXTRA != 0 {
160
20.4k
                        while (*count as usize) < buffer.len() {
161
11.8k
                            *count += read_into(r, &mut buffer[*count as usize..])? as u8;
162
                        }
163
8.62k
                        if let Some(crc) = crc {
164
2.81k
                            crc.update(buffer);
165
5.81k
                        }
166
8.62k
                        let xlen = parse_le_u16(&buffer);
167
8.62k
                        self.header.extra = Some(vec![0; xlen as usize]);
168
8.62k
                        self.state = GzHeaderState::Extra(crc.take(), 0);
169
10.0k
                    } else {
170
10.0k
                        self.state = GzHeaderState::Filename(crc.take());
171
10.0k
                    }
172
                }
173
10.1k
                GzHeaderState::Extra(crc, count) => {
174
10.1k
                    debug_assert!(self.header.extra.is_some());
175
10.1k
                    let extra = self.header.extra.as_mut().unwrap();
176
15.4k
                    while (*count as usize) < extra.len() {
177
8.07k
                        *count += read_into(r, &mut extra[*count as usize..])? as u16;
178
                    }
179
7.33k
                    if let Some(crc) = crc {
180
1.89k
                        crc.update(extra);
181
5.43k
                    }
182
7.33k
                    self.state = GzHeaderState::Filename(crc.take());
183
                }
184
18.0k
                GzHeaderState::Filename(crc) => {
185
18.0k
                    if self.flags & FNAME != 0 {
186
9.93k
                        let filename = self.header.filename.get_or_insert_with(Vec::new);
187
9.93k
                        read_to_nul(r, filename)?;
188
8.40k
                        if let Some(crc) = crc {
189
2.65k
                            crc.update(filename);
190
2.65k
                            crc.update(b"\0");
191
5.75k
                        }
192
8.07k
                    }
193
16.4k
                    self.state = GzHeaderState::Comment(crc.take());
194
                }
195
17.6k
                GzHeaderState::Comment(crc) => {
196
17.6k
                    if self.flags & FCOMMENT != 0 {
197
6.47k
                        let comment = self.header.comment.get_or_insert_with(Vec::new);
198
6.47k
                        read_to_nul(r, comment)?;
199
4.67k
                        if let Some(crc) = crc {
200
1.46k
                            crc.update(comment);
201
1.46k
                            crc.update(b"\0");
202
3.20k
                        }
203
11.1k
                    }
204
15.8k
                    self.state = GzHeaderState::Crc(crc.take(), 0, [0; 2]);
205
                }
206
16.7k
                GzHeaderState::Crc(crc, count, buffer) => {
207
16.7k
                    if let Some(crc) = crc {
208
3.35k
                        debug_assert!(self.flags & FHCRC != 0);
209
5.94k
                        while (*count as usize) < buffer.len() {
210
4.14k
                            *count += read_into(r, &mut buffer[*count as usize..])? as u8;
211
                        }
212
1.80k
                        let stored_crc = parse_le_u16(&buffer);
213
1.80k
                        let calced_crc = crc.sum() as u16;
214
1.80k
                        if stored_crc != calced_crc {
215
1.61k
                            return Err(corrupt());
216
196
                        }
217
13.3k
                    }
218
13.5k
                    self.state = GzHeaderState::Complete;
219
                }
220
                GzHeaderState::Complete => {
221
13.5k
                    return Ok(());
222
                }
223
            }
224
        }
225
75.2k
    }
Unexecuted instantiation: <flate2::gz::GzHeaderParser>::parse::<_>
<flate2::gz::GzHeaderParser>::parse::<flate2::bufreader::BufReader<suricata::http2::decompression::HTTP2cursor>>
Line
Count
Source
123
38.5k
    fn parse<'a, R: Read>(&mut self, r: &'a mut R) -> Result<()> {
124
        loop {
125
93.5k
            match &mut self.state {
126
35.7k
                GzHeaderState::Start(count, buffer) => {
127
59.3k
                    while (*count as usize) < buffer.len() {
128
47.5k
                        *count += read_into(r, &mut buffer[*count as usize..])? as u8;
129
                    }
130
                    // Gzip identification bytes
131
11.7k
                    if buffer[0] != 0x1f || buffer[1] != 0x8b {
132
615
                        return Err(bad_header());
133
11.1k
                    }
134
                    // Gzip compression method (8 = deflate)
135
11.1k
                    if buffer[2] != 8 {
136
86
                        return Err(bad_header());
137
11.0k
                    }
138
11.0k
                    self.flags = buffer[3];
139
                    // RFC1952: "must give an error indication if any reserved bit is non-zero"
140
11.0k
                    if self.flags & FRESERVED != 0 {
141
205
                        return Err(bad_header());
142
10.8k
                    }
143
10.8k
                    self.header.mtime = ((buffer[4] as u32) << 0)
144
10.8k
                        | ((buffer[5] as u32) << 8)
145
10.8k
                        | ((buffer[6] as u32) << 16)
146
10.8k
                        | ((buffer[7] as u32) << 24);
147
10.8k
                    let _xfl = buffer[8];
148
10.8k
                    self.header.operating_system = buffer[9];
149
10.8k
                    let crc = if self.flags & FHCRC != 0 {
150
1.54k
                        let mut crc = Box::new(Crc::new());
151
1.54k
                        crc.update(buffer);
152
1.54k
                        Some(crc)
153
                    } else {
154
9.31k
                        None
155
                    };
156
10.8k
                    self.state = GzHeaderState::Xlen(crc, 0, [0; 2]);
157
                }
158
11.2k
                GzHeaderState::Xlen(crc, count, buffer) => {
159
11.2k
                    if self.flags & FEXTRA != 0 {
160
9.55k
                        while (*count as usize) < buffer.len() {
161
5.03k
                            *count += read_into(r, &mut buffer[*count as usize..])? as u8;
162
                        }
163
4.52k
                        if let Some(crc) = crc {
164
1.41k
                            crc.update(buffer);
165
3.10k
                        }
166
4.52k
                        let xlen = parse_le_u16(&buffer);
167
4.52k
                        self.header.extra = Some(vec![0; xlen as usize]);
168
4.52k
                        self.state = GzHeaderState::Extra(crc.take(), 0);
169
6.25k
                    } else {
170
6.25k
                        self.state = GzHeaderState::Filename(crc.take());
171
6.25k
                    }
172
                }
173
5.36k
                GzHeaderState::Extra(crc, count) => {
174
5.36k
                    debug_assert!(self.header.extra.is_some());
175
5.36k
                    let extra = self.header.extra.as_mut().unwrap();
176
10.2k
                    while (*count as usize) < extra.len() {
177
5.92k
                        *count += read_into(r, &mut extra[*count as usize..])? as u16;
178
                    }
179
4.30k
                    if let Some(crc) = crc {
180
1.32k
                        crc.update(extra);
181
2.97k
                    }
182
4.30k
                    self.state = GzHeaderState::Filename(crc.take());
183
                }
184
11.5k
                GzHeaderState::Filename(crc) => {
185
11.5k
                    if self.flags & FNAME != 0 {
186
4.06k
                        let filename = self.header.filename.get_or_insert_with(Vec::new);
187
4.06k
                        read_to_nul(r, filename)?;
188
2.60k
                        if let Some(crc) = crc {
189
891
                            crc.update(filename);
190
891
                            crc.update(b"\0");
191
1.71k
                        }
192
7.49k
                    }
193
10.1k
                    self.state = GzHeaderState::Comment(crc.take());
194
                }
195
10.4k
                GzHeaderState::Comment(crc) => {
196
10.4k
                    if self.flags & FCOMMENT != 0 {
197
5.46k
                        let comment = self.header.comment.get_or_insert_with(Vec::new);
198
5.46k
                        read_to_nul(r, comment)?;
199
5.00k
                        if let Some(crc) = crc {
200
999
                            crc.update(comment);
201
999
                            crc.update(b"\0");
202
4.00k
                        }
203
4.98k
                    }
204
9.98k
                    self.state = GzHeaderState::Crc(crc.take(), 0, [0; 2]);
205
                }
206
10.2k
                GzHeaderState::Crc(crc, count, buffer) => {
207
10.2k
                    if let Some(crc) = crc {
208
1.30k
                        debug_assert!(self.flags & FHCRC != 0);
209
2.42k
                        while (*count as usize) < buffer.len() {
210
1.85k
                            *count += read_into(r, &mut buffer[*count as usize..])? as u8;
211
                        }
212
568
                        let stored_crc = parse_le_u16(&buffer);
213
568
                        let calced_crc = crc.sum() as u16;
214
568
                        if stored_crc != calced_crc {
215
568
                            return Err(corrupt());
216
0
                        }
217
8.93k
                    }
218
8.93k
                    self.state = GzHeaderState::Complete;
219
                }
220
                GzHeaderState::Complete => {
221
8.93k
                    return Ok(());
222
                }
223
            }
224
        }
225
38.5k
    }
Unexecuted instantiation: <flate2::gz::GzHeaderParser>::parse::<_>
226
227
0
    fn header(&self) -> Option<&GzHeader> {
228
0
        match self.state {
229
0
            GzHeaderState::Complete => Some(&self.header),
230
0
            _ => None,
231
        }
232
0
    }
Unexecuted instantiation: <flate2::gz::GzHeaderParser>::header
Unexecuted instantiation: <flate2::gz::GzHeaderParser>::header
233
}
234
235
impl From<GzHeaderParser> for GzHeader {
236
22.4k
    fn from(parser: GzHeaderParser) -> Self {
237
22.4k
        debug_assert!(matches!(parser.state, GzHeaderState::Complete));
238
22.4k
        parser.header
239
22.4k
    }
<flate2::gz::GzHeader as core::convert::From<flate2::gz::GzHeaderParser>>::from
Line
Count
Source
236
13.5k
    fn from(parser: GzHeaderParser) -> Self {
237
13.5k
        debug_assert!(matches!(parser.state, GzHeaderState::Complete));
238
13.5k
        parser.header
239
13.5k
    }
<flate2::gz::GzHeader as core::convert::From<flate2::gz::GzHeaderParser>>::from
Line
Count
Source
236
8.93k
    fn from(parser: GzHeaderParser) -> Self {
237
8.93k
        debug_assert!(matches!(parser.state, GzHeaderState::Complete));
238
8.93k
        parser.header
239
8.93k
    }
240
}
241
242
// Attempt to fill the `buffer` from `r`. Return the number of bytes read.
243
// Return an error if EOF is read before the buffer is full.  This differs
244
// from `read` in that Ok(0) means that more data may be available.
245
195k
fn read_into<R: Read>(r: &mut R, buffer: &mut [u8]) -> Result<usize> {
246
195k
    debug_assert!(!buffer.is_empty());
247
195k
    match r.read(buffer) {
248
0
        Ok(0) => Err(ErrorKind::UnexpectedEof.into()),
249
110k
        Ok(n) => Ok(n),
250
85.1k
        Err(ref e) if e.kind() == ErrorKind::Interrupted => Ok(0),
251
85.1k
        Err(e) => Err(e),
252
    }
253
195k
}
flate2::gz::read_into::<flate2::bufreader::BufReader<suricata::http2::decompression::HTTP2cursor>>
Line
Count
Source
245
131k
fn read_into<R: Read>(r: &mut R, buffer: &mut [u8]) -> Result<usize> {
246
131k
    debug_assert!(!buffer.is_empty());
247
131k
    match r.read(buffer) {
248
0
        Ok(0) => Err(ErrorKind::UnexpectedEof.into()),
249
73.3k
        Ok(n) => Ok(n),
250
58.0k
        Err(ref e) if e.kind() == ErrorKind::Interrupted => Ok(0),
251
58.0k
        Err(e) => Err(e),
252
    }
253
131k
}
Unexecuted instantiation: flate2::gz::read_into::<_>
flate2::gz::read_into::<flate2::bufreader::BufReader<suricata::http2::decompression::HTTP2cursor>>
Line
Count
Source
245
64.0k
fn read_into<R: Read>(r: &mut R, buffer: &mut [u8]) -> Result<usize> {
246
64.0k
    debug_assert!(!buffer.is_empty());
247
64.0k
    match r.read(buffer) {
248
0
        Ok(0) => Err(ErrorKind::UnexpectedEof.into()),
249
36.9k
        Ok(n) => Ok(n),
250
27.1k
        Err(ref e) if e.kind() == ErrorKind::Interrupted => Ok(0),
251
27.1k
        Err(e) => Err(e),
252
    }
253
64.0k
}
Unexecuted instantiation: flate2::gz::read_into::<_>
254
255
// Read `r` up to the first nul byte, pushing non-nul bytes to `buffer`.
256
25.9k
fn read_to_nul<R: Read>(r: &mut R, buffer: &mut Vec<u8>) -> Result<()> {
257
25.9k
    let mut bytes = r.bytes();
258
    loop {
259
2.30M
        match bytes.next().transpose()? {
260
2.29M
            Some(byte) if byte == 0 => {
261
20.6k
                return Ok(());
262
            }
263
2.27M
            Some(_) if buffer.len() == MAX_HEADER_BUF => {
264
20
                return Err(Error::new(
265
20
                    ErrorKind::InvalidInput,
266
20
                    "gzip header field too long",
267
20
                ));
268
            }
269
2.27M
            Some(byte) => {
270
2.27M
                buffer.push(byte);
271
2.27M
            }
272
            None => {
273
0
                return Err(ErrorKind::UnexpectedEof.into());
274
            }
275
        }
276
    }
277
25.9k
}
flate2::gz::read_to_nul::<flate2::bufreader::BufReader<suricata::http2::decompression::HTTP2cursor>>
Line
Count
Source
256
16.4k
fn read_to_nul<R: Read>(r: &mut R, buffer: &mut Vec<u8>) -> Result<()> {
257
16.4k
    let mut bytes = r.bytes();
258
    loop {
259
1.95M
        match bytes.next().transpose()? {
260
1.94M
            Some(byte) if byte == 0 => {
261
13.0k
                return Ok(());
262
            }
263
1.93M
            Some(_) if buffer.len() == MAX_HEADER_BUF => {
264
19
                return Err(Error::new(
265
19
                    ErrorKind::InvalidInput,
266
19
                    "gzip header field too long",
267
19
                ));
268
            }
269
1.93M
            Some(byte) => {
270
1.93M
                buffer.push(byte);
271
1.93M
            }
272
            None => {
273
0
                return Err(ErrorKind::UnexpectedEof.into());
274
            }
275
        }
276
    }
277
16.4k
}
Unexecuted instantiation: flate2::gz::read_to_nul::<_>
flate2::gz::read_to_nul::<flate2::bufreader::BufReader<suricata::http2::decompression::HTTP2cursor>>
Line
Count
Source
256
9.52k
fn read_to_nul<R: Read>(r: &mut R, buffer: &mut Vec<u8>) -> Result<()> {
257
9.52k
    let mut bytes = r.bytes();
258
    loop {
259
352k
        match bytes.next().transpose()? {
260
350k
            Some(byte) if byte == 0 => {
261
7.60k
                return Ok(());
262
            }
263
343k
            Some(_) if buffer.len() == MAX_HEADER_BUF => {
264
1
                return Err(Error::new(
265
1
                    ErrorKind::InvalidInput,
266
1
                    "gzip header field too long",
267
1
                ));
268
            }
269
343k
            Some(byte) => {
270
343k
                buffer.push(byte);
271
343k
            }
272
            None => {
273
0
                return Err(ErrorKind::UnexpectedEof.into());
274
            }
275
        }
276
    }
277
9.52k
}
Unexecuted instantiation: flate2::gz::read_to_nul::<_>
278
279
15.5k
fn parse_le_u16(buffer: &[u8; 2]) -> u16 {
280
15.5k
    (buffer[0] as u16) | ((buffer[1] as u16) << 8)
281
15.5k
}
flate2::gz::parse_le_u16
Line
Count
Source
279
10.4k
fn parse_le_u16(buffer: &[u8; 2]) -> u16 {
280
10.4k
    (buffer[0] as u16) | ((buffer[1] as u16) << 8)
281
10.4k
}
flate2::gz::parse_le_u16
Line
Count
Source
279
5.08k
fn parse_le_u16(buffer: &[u8; 2]) -> u16 {
280
5.08k
    (buffer[0] as u16) | ((buffer[1] as u16) << 8)
281
5.08k
}
282
283
3.86k
fn bad_header() -> Error {
284
3.86k
    Error::new(ErrorKind::InvalidInput, "invalid gzip header")
285
3.86k
}
flate2::gz::bad_header
Line
Count
Source
283
2.96k
fn bad_header() -> Error {
284
2.96k
    Error::new(ErrorKind::InvalidInput, "invalid gzip header")
285
2.96k
}
flate2::gz::bad_header
Line
Count
Source
283
906
fn bad_header() -> Error {
284
906
    Error::new(ErrorKind::InvalidInput, "invalid gzip header")
285
906
}
286
287
6.49k
fn corrupt() -> Error {
288
6.49k
    Error::new(
289
6.49k
        ErrorKind::InvalidInput,
290
        "corrupt gzip stream does not have a matching checksum",
291
    )
292
6.49k
}
flate2::gz::corrupt
Line
Count
Source
287
4.76k
fn corrupt() -> Error {
288
4.76k
    Error::new(
289
4.76k
        ErrorKind::InvalidInput,
290
        "corrupt gzip stream does not have a matching checksum",
291
    )
292
4.76k
}
flate2::gz::corrupt
Line
Count
Source
287
1.73k
fn corrupt() -> Error {
288
1.73k
    Error::new(
289
1.73k
        ErrorKind::InvalidInput,
290
        "corrupt gzip stream does not have a matching checksum",
291
    )
292
1.73k
}
293
294
/// A builder structure to create a new gzip Encoder.
295
///
296
/// This structure controls header configuration options such as the filename.
297
///
298
/// # Examples
299
///
300
/// ```
301
/// use std::io::prelude::*;
302
/// # use std::io;
303
/// use std::fs::File;
304
/// use flate2::GzBuilder;
305
/// use flate2::Compression;
306
///
307
/// // GzBuilder opens a file and writes a sample string using GzBuilder pattern
308
///
309
/// # fn sample_builder() -> Result<(), io::Error> {
310
/// let f = File::create("examples/hello_world.gz")?;
311
/// let mut gz = GzBuilder::new()
312
///                 .filename("hello_world.txt")
313
///                 .comment("test file, please delete")
314
///                 .write(f, Compression::default());
315
/// gz.write_all(b"hello world")?;
316
/// gz.finish()?;
317
/// # Ok(())
318
/// # }
319
/// ```
320
#[derive(Debug)]
321
pub struct GzBuilder {
322
    extra: Option<Vec<u8>>,
323
    filename: Option<CString>,
324
    comment: Option<CString>,
325
    operating_system: Option<u8>,
326
    mtime: u32,
327
}
328
329
impl Default for GzBuilder {
330
0
    fn default() -> Self {
331
0
        Self::new()
332
0
    }
Unexecuted instantiation: <flate2::gz::GzBuilder as core::default::Default>::default
Unexecuted instantiation: <flate2::gz::GzBuilder as core::default::Default>::default
333
}
334
335
impl GzBuilder {
336
    /// Create a new blank builder with no header by default.
337
0
    pub fn new() -> GzBuilder {
338
0
        GzBuilder {
339
0
            extra: None,
340
0
            filename: None,
341
0
            comment: None,
342
0
            operating_system: None,
343
0
            mtime: 0,
344
0
        }
345
0
    }
Unexecuted instantiation: <flate2::gz::GzBuilder>::new
Unexecuted instantiation: <flate2::gz::GzBuilder>::new
346
347
    /// Configure the `mtime` field in the gzip header.
348
0
    pub fn mtime(mut self, mtime: u32) -> GzBuilder {
349
0
        self.mtime = mtime;
350
0
        self
351
0
    }
Unexecuted instantiation: <flate2::gz::GzBuilder>::mtime
Unexecuted instantiation: <flate2::gz::GzBuilder>::mtime
352
353
    /// Configure the `operating_system` field in the gzip header.
354
0
    pub fn operating_system(mut self, os: u8) -> GzBuilder {
355
0
        self.operating_system = Some(os);
356
0
        self
357
0
    }
Unexecuted instantiation: <flate2::gz::GzBuilder>::operating_system
Unexecuted instantiation: <flate2::gz::GzBuilder>::operating_system
358
359
    /// Configure the `extra` field in the gzip header.
360
0
    pub fn extra<T: Into<Vec<u8>>>(mut self, extra: T) -> GzBuilder {
361
0
        self.extra = Some(extra.into());
362
0
        self
363
0
    }
Unexecuted instantiation: <flate2::gz::GzBuilder>::extra::<_>
Unexecuted instantiation: <flate2::gz::GzBuilder>::extra::<_>
364
365
    /// Configure the `filename` field in the gzip header.
366
    ///
367
    /// # Panics
368
    ///
369
    /// Panics if the `filename` slice contains a zero.
370
0
    pub fn filename<T: Into<Vec<u8>>>(mut self, filename: T) -> GzBuilder {
371
0
        self.filename = Some(CString::new(filename.into()).unwrap());
372
0
        self
373
0
    }
Unexecuted instantiation: <flate2::gz::GzBuilder>::filename::<_>
Unexecuted instantiation: <flate2::gz::GzBuilder>::filename::<_>
374
375
    /// Configure the `comment` field in the gzip header.
376
    ///
377
    /// # Panics
378
    ///
379
    /// Panics if the `comment` slice contains a zero.
380
0
    pub fn comment<T: Into<Vec<u8>>>(mut self, comment: T) -> GzBuilder {
381
0
        self.comment = Some(CString::new(comment.into()).unwrap());
382
0
        self
383
0
    }
Unexecuted instantiation: <flate2::gz::GzBuilder>::comment::<_>
Unexecuted instantiation: <flate2::gz::GzBuilder>::comment::<_>
384
385
    /// Consume this builder, creating a writer encoder in the process.
386
    ///
387
    /// The data written to the returned encoder will be compressed and then
388
    /// written out to the supplied parameter `w`.
389
0
    pub fn write<W: Write>(self, w: W, lvl: Compression) -> write::GzEncoder<W> {
390
0
        write::gz_encoder(self.into_header(lvl), w, lvl)
391
0
    }
Unexecuted instantiation: <flate2::gz::GzBuilder>::write::<_>
Unexecuted instantiation: <flate2::gz::GzBuilder>::write::<_>
392
393
    /// Consume this builder, creating a reader encoder in the process.
394
    ///
395
    /// Data read from the returned encoder will be the compressed version of
396
    /// the data read from the given reader.
397
0
    pub fn read<R: Read>(self, r: R, lvl: Compression) -> read::GzEncoder<R> {
398
0
        read::gz_encoder(self.buf_read(BufReader::new(r), lvl))
399
0
    }
Unexecuted instantiation: <flate2::gz::GzBuilder>::read::<_>
Unexecuted instantiation: <flate2::gz::GzBuilder>::read::<_>
400
401
    /// Consume this builder, creating a reader encoder in the process.
402
    ///
403
    /// Data read from the returned encoder will be the compressed version of
404
    /// the data read from the given reader.
405
0
    pub fn buf_read<R>(self, r: R, lvl: Compression) -> bufread::GzEncoder<R>
406
0
    where
407
0
        R: BufRead,
408
    {
409
0
        bufread::gz_encoder(self.into_header(lvl), r, lvl)
410
0
    }
Unexecuted instantiation: <flate2::gz::GzBuilder>::buf_read::<_>
Unexecuted instantiation: <flate2::gz::GzBuilder>::buf_read::<_>
411
412
0
    fn into_header(self, lvl: Compression) -> Vec<u8> {
413
        let GzBuilder {
414
0
            extra,
415
0
            filename,
416
0
            comment,
417
0
            operating_system,
418
0
            mtime,
419
0
        } = self;
420
0
        let mut flg = 0;
421
0
        let mut header = vec![0u8; 10];
422
0
        if let Some(v) = extra {
423
0
            flg |= FEXTRA;
424
0
            header.push((v.len() >> 0) as u8);
425
0
            header.push((v.len() >> 8) as u8);
426
0
            header.extend(v);
427
0
        }
428
0
        if let Some(filename) = filename {
429
0
            flg |= FNAME;
430
0
            header.extend(filename.as_bytes_with_nul().iter().copied());
431
0
        }
432
0
        if let Some(comment) = comment {
433
0
            flg |= FCOMMENT;
434
0
            header.extend(comment.as_bytes_with_nul().iter().copied());
435
0
        }
436
0
        header[0] = 0x1f;
437
0
        header[1] = 0x8b;
438
0
        header[2] = 8;
439
0
        header[3] = flg;
440
0
        header[4] = (mtime >> 0) as u8;
441
0
        header[5] = (mtime >> 8) as u8;
442
0
        header[6] = (mtime >> 16) as u8;
443
0
        header[7] = (mtime >> 24) as u8;
444
0
        header[8] = if lvl.0 >= Compression::best().0 {
445
0
            2
446
0
        } else if lvl.0 <= Compression::fast().0 {
447
0
            4
448
        } else {
449
0
            0
450
        };
451
452
        // Typically this byte indicates what OS the gz stream was created on,
453
        // but in an effort to have cross-platform reproducible streams just
454
        // default this value to 255. I'm not sure that if we "correctly" set
455
        // this it'd do anything anyway...
456
0
        header[9] = operating_system.unwrap_or(255);
457
0
        header
458
0
    }
Unexecuted instantiation: <flate2::gz::GzBuilder>::into_header
Unexecuted instantiation: <flate2::gz::GzBuilder>::into_header
459
}
460
461
#[cfg(test)]
462
mod tests {
463
    use std::io::prelude::*;
464
465
    use super::{read, write, GzBuilder, GzHeaderParser};
466
    use crate::{Compression, GzHeader};
467
    use rand::{thread_rng, Rng};
468
469
    #[test]
470
    fn roundtrip() {
471
        let mut e = write::GzEncoder::new(Vec::new(), Compression::default());
472
        e.write_all(b"foo bar baz").unwrap();
473
        let inner = e.finish().unwrap();
474
        let mut d = read::GzDecoder::new(&inner[..]);
475
        let mut s = String::new();
476
        d.read_to_string(&mut s).unwrap();
477
        assert_eq!(s, "foo bar baz");
478
    }
479
480
    #[test]
481
    fn roundtrip_zero() {
482
        let e = write::GzEncoder::new(Vec::new(), Compression::default());
483
        let inner = e.finish().unwrap();
484
        let mut d = read::GzDecoder::new(&inner[..]);
485
        let mut s = String::new();
486
        d.read_to_string(&mut s).unwrap();
487
        assert_eq!(s, "");
488
    }
489
490
    #[test]
491
    fn roundtrip_big() {
492
        let mut real = Vec::new();
493
        let mut w = write::GzEncoder::new(Vec::new(), Compression::default());
494
        let v = crate::random_bytes().take(1024).collect::<Vec<_>>();
495
        for _ in 0..200 {
496
            let to_write = &v[..thread_rng().gen_range(0..v.len())];
497
            real.extend(to_write.iter().copied());
498
            w.write_all(to_write).unwrap();
499
        }
500
        let result = w.finish().unwrap();
501
        let mut r = read::GzDecoder::new(&result[..]);
502
        let mut v = Vec::new();
503
        r.read_to_end(&mut v).unwrap();
504
        assert_eq!(v, real);
505
    }
506
507
    #[test]
508
    fn roundtrip_big2() {
509
        let v = crate::random_bytes().take(1024 * 1024).collect::<Vec<_>>();
510
        let mut r = read::GzDecoder::new(read::GzEncoder::new(&v[..], Compression::default()));
511
        let mut res = Vec::new();
512
        r.read_to_end(&mut res).unwrap();
513
        assert_eq!(res, v);
514
    }
515
516
    // A Rust implementation of CRC that closely matches the C code in RFC1952.
517
    // Only use this to create CRCs for tests.
518
    struct Rfc1952Crc {
519
        /* Table of CRCs of all 8-bit messages. */
520
        crc_table: [u32; 256],
521
    }
522
523
    impl Rfc1952Crc {
524
        fn new() -> Self {
525
            let mut crc = Rfc1952Crc {
526
                crc_table: [0; 256],
527
            };
528
            /* Make the table for a fast CRC. */
529
            for n in 0usize..256 {
530
                let mut c = n as u32;
531
                for _k in 0..8 {
532
                    if c & 1 != 0 {
533
                        c = 0xedb88320 ^ (c >> 1);
534
                    } else {
535
                        c = c >> 1;
536
                    }
537
                }
538
                crc.crc_table[n] = c;
539
            }
540
            crc
541
        }
542
543
        /*
544
         Update a running crc with the bytes buf and return
545
         the updated crc. The crc should be initialized to zero. Pre- and
546
         post-conditioning (one's complement) is performed within this
547
         function so it shouldn't be done by the caller.
548
        */
549
        fn update_crc(&self, crc: u32, buf: &[u8]) -> u32 {
550
            let mut c = crc ^ 0xffffffff;
551
552
            for b in buf {
553
                c = self.crc_table[(c as u8 ^ *b) as usize] ^ (c >> 8);
554
            }
555
            c ^ 0xffffffff
556
        }
557
558
        /* Return the CRC of the bytes buf. */
559
        fn crc(&self, buf: &[u8]) -> u32 {
560
            self.update_crc(0, buf)
561
        }
562
    }
563
564
    #[test]
565
    fn roundtrip_header() {
566
        let mut header = GzBuilder::new()
567
            .mtime(1234)
568
            .operating_system(57)
569
            .filename("filename")
570
            .comment("comment")
571
            .into_header(Compression::fast());
572
573
        // Add a CRC to the header
574
        header[3] = header[3] ^ super::FHCRC;
575
        let rfc1952_crc = Rfc1952Crc::new();
576
        let crc32 = rfc1952_crc.crc(&header);
577
        let crc16 = crc32 as u16;
578
        header.extend(&crc16.to_le_bytes());
579
580
        let mut parser = GzHeaderParser::new();
581
        parser.parse(&mut header.as_slice()).unwrap();
582
        let actual = parser.header().unwrap();
583
        assert_eq!(
584
            actual,
585
            &GzHeader {
586
                extra: None,
587
                filename: Some("filename".as_bytes().to_vec()),
588
                comment: Some("comment".as_bytes().to_vec()),
589
                operating_system: 57,
590
                mtime: 1234
591
            }
592
        )
593
    }
594
595
    #[test]
596
    fn fields() {
597
        let r = vec![0, 2, 4, 6];
598
        let e = GzBuilder::new()
599
            .filename("foo.rs")
600
            .comment("bar")
601
            .extra(vec![0, 1, 2, 3])
602
            .read(&r[..], Compression::default());
603
        let mut d = read::GzDecoder::new(e);
604
        assert_eq!(d.header().unwrap().filename(), Some(&b"foo.rs"[..]));
605
        assert_eq!(d.header().unwrap().comment(), Some(&b"bar"[..]));
606
        assert_eq!(d.header().unwrap().extra(), Some(&b"\x00\x01\x02\x03"[..]));
607
        let mut res = Vec::new();
608
        d.read_to_end(&mut res).unwrap();
609
        assert_eq!(res, vec![0, 2, 4, 6]);
610
    }
611
612
    #[test]
613
    fn keep_reading_after_end() {
614
        let mut e = write::GzEncoder::new(Vec::new(), Compression::default());
615
        e.write_all(b"foo bar baz").unwrap();
616
        let inner = e.finish().unwrap();
617
        let mut d = read::GzDecoder::new(&inner[..]);
618
        let mut s = String::new();
619
        d.read_to_string(&mut s).unwrap();
620
        assert_eq!(s, "foo bar baz");
621
        d.read_to_string(&mut s).unwrap();
622
        assert_eq!(s, "foo bar baz");
623
    }
624
625
    #[test]
626
    fn qc_reader() {
627
        ::quickcheck::quickcheck(test as fn(_) -> _);
628
629
        fn test(v: Vec<u8>) -> bool {
630
            let r = read::GzEncoder::new(&v[..], Compression::default());
631
            let mut r = read::GzDecoder::new(r);
632
            let mut v2 = Vec::new();
633
            r.read_to_end(&mut v2).unwrap();
634
            v == v2
635
        }
636
    }
637
638
    #[test]
639
    fn flush_after_write() {
640
        let mut f = write::GzEncoder::new(Vec::new(), Compression::default());
641
        write!(f, "Hello world").unwrap();
642
        f.flush().unwrap();
643
    }
644
}