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

jasonish / suricata / 23209208055

17 Mar 2026 06:06PM UTC coverage: 79.343%. First build
23209208055

push

github

jasonish
rust: cargo fmt

Format all Rust code using current stable Rust, 1.94.

3059 of 5090 new or added lines in 86 files covered. (60.1%)

266976 of 336483 relevant lines covered (79.34%)

5727482.99 hits per line

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

95.92
/rust/src/http2/parser.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::huffman;
19
use crate::common::nom7::bits;
20
use crate::detect::uint::{detect_parse_uint, DetectUintData};
21
use crate::http2::http2::{HTTP2DynTable, HTTP2_MAX_TABLESIZE};
22
use base64::{engine::general_purpose::STANDARD_NO_PAD, Engine};
23
use nom7::bits::streaming::take as take_bits;
24
use nom7::bytes::complete::tag;
25
use nom7::bytes::streaming::{take, take_while};
26
use nom7::combinator::{complete, cond, map_opt, verify};
27
use nom7::error::{make_error, ErrorKind};
28
use nom7::multi::many0;
29
use nom7::number::streaming::{be_u16, be_u24, be_u32, be_u8};
30
use nom7::sequence::tuple;
31
use nom7::{Err, IResult};
32
use std::fmt;
33
use std::rc::Rc;
34
use std::str::FromStr;
35

36
#[repr(u8)]
37
#[derive(EnumStringU8, Clone, Copy, PartialEq, Eq, FromPrimitive, Debug)]
24,687✔
38
// parse GOAWAY, not GO_AWAY
39
#[suricata(enum_string_style = "UPPERCASE")]
40
pub enum HTTP2FrameType {
41
    Data = 0,
42
    Headers = 1,
43
    Priority = 2,
44
    RstStream = 3,
45
    Settings = 4,
46
    PushPromise = 5,
47
    Ping = 6,
48
    GoAway = 7,
49
    WindowUpdate = 8,
50
    Continuation = 9,
51
}
52

53
#[derive(PartialEq, Eq, Debug)]
54
pub struct HTTP2FrameHeader {
55
    //we could add detection on (GOAWAY) additional data
56
    pub length: u32,
57
    pub ftype: u8,
58
    pub flags: u8,
59
    pub reserved: u8,
60
    pub stream_id: u32,
61
}
62

63
pub fn http2_parse_frame_header(i: &[u8]) -> IResult<&[u8], HTTP2FrameHeader> {
28,217✔
64
    let (i, length) = be_u24(i)?;
28,217✔
65
    let (i, ftype) = be_u8(i)?;
28,200✔
66
    let (i, flags) = be_u8(i)?;
28,195✔
67
    let (i, b) = be_u32(i)?;
28,181✔
68
    let (reserved, stream_id) = ((b >> 31) as u8, b & 0x7fff_ffff);
28,139✔
69
    Ok((
28,139✔
70
        i,
28,139✔
71
        HTTP2FrameHeader {
28,139✔
72
            length,
28,139✔
73
            ftype,
28,139✔
74
            flags,
28,139✔
75
            reserved,
28,139✔
76
            stream_id,
28,139✔
77
        },
28,139✔
78
    ))
28,139✔
79
}
28,217✔
80

81
#[repr(u32)]
NEW
82
#[derive(EnumStringU32, Clone, Copy, PartialEq, Eq, FromPrimitive, Debug)]
×
83
#[suricata(enum_string_style = "LOG_UPPERCASE")]
84
pub enum HTTP2ErrorCode {
85
    NoError = 0,
86
    ProtocolError = 1,
87
    InternalError = 2,
88
    FlowControlError = 3,
89
    SettingsTimeout = 4,
90
    StreamClosed = 5,
91
    FrameSizeError = 6,
92
    RefusedStream = 7,
93
    Cancel = 8,
94
    CompressionError = 9,
95
    ConnectError = 10,
96
    EnhanceYourCalm = 11,
97
    InadequateSecurity = 12,
98
    Http11Required = 13,
99
}
100

101
#[derive(Clone, Copy, Debug)]
102
pub struct HTTP2FrameGoAway {
103
    pub errorcode: u32, //HTTP2ErrorCode
104
}
105

106
pub fn http2_parse_frame_goaway(i: &[u8]) -> IResult<&[u8], HTTP2FrameGoAway> {
28✔
107
    let (i, _last_stream_id) = be_u32(i)?;
28✔
108
    let (i, errorcode) = be_u32(i)?;
28✔
109
    Ok((i, HTTP2FrameGoAway { errorcode }))
28✔
110
}
28✔
111

112
#[derive(Clone, Copy, Debug)]
113
pub struct HTTP2FrameRstStream {
114
    pub errorcode: u32, ////HTTP2ErrorCode
115
}
116

117
pub fn http2_parse_frame_rststream(i: &[u8]) -> IResult<&[u8], HTTP2FrameRstStream> {
123✔
118
    let (i, errorcode) = be_u32(i)?;
123✔
119
    Ok((i, HTTP2FrameRstStream { errorcode }))
123✔
120
}
123✔
121

122
#[derive(Clone, Copy, Debug)]
123
pub struct HTTP2FramePriority {
124
    pub exclusive: u8,
125
    pub dependency: u32,
126
    pub weight: u8,
127
}
128

129
pub fn http2_parse_frame_priority(i: &[u8]) -> IResult<&[u8], HTTP2FramePriority> {
1,902✔
130
    let (i, b) = be_u32(i)?;
1,902✔
131
    let (exclusive, dependency) = ((b >> 31) as u8, b & 0x7fff_ffff);
1,902✔
132
    let (i, weight) = be_u8(i)?;
1,902✔
133
    Ok((
1,902✔
134
        i,
1,902✔
135
        HTTP2FramePriority {
1,902✔
136
            exclusive,
1,902✔
137
            dependency,
1,902✔
138
            weight,
1,902✔
139
        },
1,902✔
140
    ))
1,902✔
141
}
1,902✔
142

143
#[derive(Clone, Copy, Debug)]
144
pub struct HTTP2FrameWindowUpdate {
145
    pub reserved: u8,
146
    pub sizeinc: u32,
147
}
148

149
pub fn http2_parse_frame_windowupdate(i: &[u8]) -> IResult<&[u8], HTTP2FrameWindowUpdate> {
1,875✔
150
    let (i, b) = be_u32(i)?;
1,875✔
151
    let (reserved, sizeinc) = ((b >> 31) as u8, b & 0x7fff_ffff);
1,875✔
152
    Ok((i, HTTP2FrameWindowUpdate { reserved, sizeinc }))
1,875✔
153
}
1,875✔
154

155
#[derive(Clone, Copy, Debug)]
156
pub struct HTTP2FrameHeadersPriority {
157
    pub exclusive: u8,
158
    pub dependency: u32,
159
    pub weight: u8,
160
}
161

162
pub fn http2_parse_headers_priority(i: &[u8]) -> IResult<&[u8], HTTP2FrameHeadersPriority> {
2,763✔
163
    let (i, b) = be_u32(i)?;
2,763✔
164
    let (exclusive, dependency) = ((b >> 31) as u8, b & 0x7fff_ffff);
2,761✔
165
    let (i, weight) = be_u8(i)?;
2,761✔
166
    Ok((
2,760✔
167
        i,
2,760✔
168
        HTTP2FrameHeadersPriority {
2,760✔
169
            exclusive,
2,760✔
170
            dependency,
2,760✔
171
            weight,
2,760✔
172
        },
2,760✔
173
    ))
2,760✔
174
}
2,763✔
175

176
pub const HTTP2_STATIC_HEADERS_NUMBER: usize = 61;
177

178
fn http2_frame_header_static(n: u64, dyn_headers: &HTTP2DynTable) -> Option<HTTP2FrameHeaderBlock> {
67,463✔
179
    let (name, value) = match n {
67,463✔
180
        1 => (":authority", ""),
917✔
181
        2 => (":method", "GET"),
907✔
182
        3 => (":method", "POST"),
2,165✔
183
        4 => (":path", "/"),
1,906✔
184
        5 => (":path", "/index.html"),
1,960✔
185
        6 => (":scheme", "http"),
371✔
186
        7 => (":scheme", "https"),
2,629✔
187
        8 => (":status", "200"),
2,421✔
188
        9 => (":status", "204"),
60✔
189
        10 => (":status", "206"),
166✔
190
        11 => (":status", "304"),
55✔
191
        12 => (":status", "400"),
2,389✔
192
        13 => (":status", "404"),
145✔
193
        14 => (":status", "500"),
95✔
194
        15 => ("accept-charset", ""),
85✔
195
        16 => ("accept-encoding", "gzip, deflate"),
738✔
196
        17 => ("accept-language", ""),
512✔
197
        18 => ("accept-ranges", ""),
231✔
198
        19 => ("accept", ""),
751✔
199
        20 => ("access-control-allow-origin", ""),
358✔
200
        21 => ("age", ""),
56✔
201
        22 => ("allow", ""),
7✔
202
        23 => ("authorization", ""),
120✔
203
        24 => ("cache-control", ""),
1,921✔
204
        25 => ("content-disposition", ""),
135✔
205
        26 => ("content-encoding", ""),
294✔
206
        27 => ("content-language", ""),
128✔
207
        28 => ("content-length", ""),
1,141✔
208
        29 => ("content-location", ""),
25✔
209
        30 => ("content-range", ""),
192✔
210
        31 => ("content-type", ""),
1,049✔
211
        32 => ("cookie", ""),
314✔
212
        33 => ("date", ""),
1,172✔
213
        34 => ("etag", ""),
117✔
214
        35 => ("expect", ""),
177✔
215
        36 => ("expires", ""),
261✔
216
        37 => ("from", ""),
118✔
217
        38 => ("host", ""),
34✔
218
        39 => ("if-match", ""),
40✔
219
        40 => ("if-modified-since", ""),
57✔
220
        41 => ("if-none-match", ""),
311✔
221
        42 => ("if-range", ""),
64✔
222
        43 => ("if-unmodified-since", ""),
19✔
223
        44 => ("last-modified", ""),
366✔
224
        45 => ("link", ""),
61✔
225
        46 => ("location", ""),
132✔
226
        47 => ("max-forwards", ""),
79✔
227
        48 => ("proxy-authenticate", ""),
94✔
228
        49 => ("proxy-authorization", ""),
61✔
229
        50 => ("range", ""),
63✔
230
        51 => ("referer", ""),
249✔
231
        52 => ("refresh", ""),
88✔
232
        53 => ("retry-after", ""),
39✔
233
        54 => ("server", ""),
543✔
234
        55 => ("set-cookie", ""),
139✔
235
        56 => ("strict-transport-security", ""),
151✔
236
        57 => ("transfer-encoding", ""),
21✔
237
        58 => ("user-agent", ""),
673✔
238
        59 => ("vary", ""),
474✔
239
        60 => ("via", ""),
45✔
240
        61 => ("www-authenticate", ""),
67✔
241
        _ => ("", ""),
37,505✔
242
    };
243
    if !name.is_empty() {
67,463✔
244
        return Some(HTTP2FrameHeaderBlock {
29,958✔
245
            name: Rc::new(name.as_bytes().to_vec()),
29,958✔
246
            value: Rc::new(value.as_bytes().to_vec()),
29,958✔
247
            error: HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSuccess,
29,958✔
248
            sizeupdate: 0,
29,958✔
249
        });
29,958✔
250
    } else {
251
        //use dynamic table
252
        if n == 0 {
37,505✔
253
            return Some(HTTP2FrameHeaderBlock {
55✔
254
                name: Rc::new(Vec::new()),
55✔
255
                value: Rc::new(Vec::new()),
55✔
256
                error: HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeIndex0,
55✔
257
                sizeupdate: 0,
55✔
258
            });
55✔
259
        } else if dyn_headers.table.len() + HTTP2_STATIC_HEADERS_NUMBER < n as usize {
37,450✔
260
            return Some(HTTP2FrameHeaderBlock {
7,990✔
261
                name: Rc::new(Vec::new()),
7,990✔
262
                value: Rc::new(Vec::new()),
7,990✔
263
                error: HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeNotIndexed,
7,990✔
264
                sizeupdate: 0,
7,990✔
265
            });
7,990✔
266
        } else {
267
            let indyn = dyn_headers.table.len() - (n as usize - HTTP2_STATIC_HEADERS_NUMBER);
29,460✔
268
            let headcopy = HTTP2FrameHeaderBlock {
29,460✔
269
                name: dyn_headers.table[indyn].name.clone(),
29,460✔
270
                value: dyn_headers.table[indyn].value.clone(),
29,460✔
271
                error: HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSuccess,
29,460✔
272
                sizeupdate: 0,
29,460✔
273
            };
29,460✔
274
            return Some(headcopy);
29,460✔
275
        }
276
    }
277
}
67,463✔
278

279
#[repr(u8)]
280
#[derive(Copy, Clone, PartialOrd, PartialEq, Eq, Debug)]
281
pub enum HTTP2HeaderDecodeStatus {
282
    HTTP2HeaderDecodeSuccess = 0,
283
    HTTP2HeaderDecodeSizeUpdate = 1,
284
    HTTP2HeaderDecodeError = 0x80,
285
    HTTP2HeaderDecodeNotIndexed = 0x81,
286
    HTTP2HeaderDecodeIntegerOverflow = 0x82,
287
    HTTP2HeaderDecodeIndex0 = 0x83,
288
}
289

290
impl fmt::Display for HTTP2HeaderDecodeStatus {
291
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6,038✔
292
        write!(f, "{:?}", self)
6,038✔
293
    }
6,038✔
294
}
295

296
#[derive(Clone, Debug)]
297
pub struct HTTP2FrameHeaderBlock {
298
    // Use Rc reference counted so that indexed headers do not get copied.
299
    // Otherwise, this leads to quadratic complexity in memory occupation.
300
    pub name: Rc<Vec<u8>>,
301
    pub value: Rc<Vec<u8>>,
302
    pub error: HTTP2HeaderDecodeStatus,
303
    pub sizeupdate: u64,
304
}
305

306
fn http2_parse_headers_block_indexed<'a>(
48,056✔
307
    input: &'a [u8], dyn_headers: &HTTP2DynTable,
48,056✔
308
) -> IResult<&'a [u8], HTTP2FrameHeaderBlock> {
48,056✔
309
    fn parser(input: &[u8]) -> IResult<&[u8], (u8, u8)> {
48,056✔
310
        bits(complete(tuple((
48,056✔
311
            verify(take_bits(1u8), |&x| x == 1),
48,056✔
312
            take_bits(7u8),
48,056✔
313
        ))))(input)
48,056✔
314
    }
48,056✔
315
    let (i2, indexed) = parser(input)?;
48,056✔
316
    let (i3, indexreal) = http2_parse_var_uint(i2, indexed.1 as u64, 0x7F)?;
48,056✔
317
    match http2_frame_header_static(indexreal, dyn_headers) {
48,055✔
318
        Some(h) => Ok((i3, h)),
48,055✔
319
        _ => Err(Err::Error(make_error(i3, ErrorKind::MapOpt))),
×
320
    }
321
}
48,056✔
322

323
fn http2_parse_headers_block_string(input: &[u8]) -> IResult<&[u8], Vec<u8>> {
34,086✔
324
    fn parser(input: &[u8]) -> IResult<&[u8], (u8, u8)> {
34,086✔
325
        bits(tuple((take_bits(1u8), take_bits(7u8))))(input)
34,086✔
326
    }
34,086✔
327
    let (i1, huffslen) = parser(input)?;
34,086✔
328
    let (i2, stringlen) = http2_parse_var_uint(i1, huffslen.1 as u64, 0x7F)?;
34,069✔
329
    let (i3, data) = take(stringlen as usize)(i2)?;
34,068✔
330
    if huffslen.0 == 0 {
33,734✔
331
        return Ok((i3, data.to_vec()));
12,011✔
332
    } else {
333
        let (_, val) = bits(many0(huffman::http2_decode_huffman))(data)?;
21,723✔
334
        return Ok((i3, val));
21,723✔
335
    }
336
}
34,086✔
337

338
fn http2_parse_headers_block_literal_common<'a>(
26,762✔
339
    input: &'a [u8], index: u64, dyn_headers: &HTTP2DynTable,
26,762✔
340
) -> IResult<&'a [u8], HTTP2FrameHeaderBlock> {
26,762✔
341
    let (i3, name, error) = if index == 0 {
26,762✔
342
        match http2_parse_headers_block_string(input) {
7,354✔
343
            Ok((r, n)) => Ok((
7,322✔
344
                r,
7,322✔
345
                Rc::new(n),
7,322✔
346
                HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSuccess,
7,322✔
347
            )),
7,322✔
348
            Err(e) => Err(e),
32✔
349
        }
350
    } else {
351
        match http2_frame_header_static(index, dyn_headers) {
19,408✔
352
            Some(x) => Ok((
19,408✔
353
                input,
19,408✔
354
                x.name,
19,408✔
355
                HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSuccess,
19,408✔
356
            )),
19,408✔
357
            None => Ok((
×
358
                input,
×
359
                Rc::new(Vec::new()),
×
360
                HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeNotIndexed,
×
361
            )),
×
362
        }
363
    }?;
32✔
364
    let (i4, value) = http2_parse_headers_block_string(i3)?;
26,730✔
365
    return Ok((
26,410✔
366
        i4,
26,410✔
367
        HTTP2FrameHeaderBlock {
26,410✔
368
            name,
26,410✔
369
            value: Rc::new(value),
26,410✔
370
            error,
26,410✔
371
            sizeupdate: 0,
26,410✔
372
        },
26,410✔
373
    ));
26,410✔
374
}
26,762✔
375

376
fn http2_parse_headers_block_literal_incindex<'a>(
18,242✔
377
    input: &'a [u8], dyn_headers: &mut HTTP2DynTable,
18,242✔
378
) -> IResult<&'a [u8], HTTP2FrameHeaderBlock> {
18,242✔
379
    fn parser(input: &[u8]) -> IResult<&[u8], (u8, u8)> {
18,242✔
380
        bits(complete(tuple((
18,242✔
381
            verify(take_bits(2u8), |&x| x == 1),
18,242✔
382
            take_bits(6u8),
18,242✔
383
        ))))(input)
18,242✔
384
    }
18,242✔
385
    let (i2, indexed) = parser(input)?;
18,242✔
386
    let (i3, indexreal) = http2_parse_var_uint(i2, indexed.1 as u64, 0x3F)?;
18,242✔
387
    let r = http2_parse_headers_block_literal_common(i3, indexreal, dyn_headers);
18,241✔
388
    match r {
18,241✔
389
        Ok((r, head)) => {
18,032✔
390
            let headcopy = HTTP2FrameHeaderBlock {
18,032✔
391
                name: head.name.clone(),
18,032✔
392
                value: head.value.clone(),
18,032✔
393
                error: head.error,
18,032✔
394
                sizeupdate: 0,
18,032✔
395
            };
18,032✔
396
            if head.error == HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSuccess {
18,032✔
397
                dyn_headers.current_size += 32 + headcopy.name.len() + headcopy.value.len();
18,032✔
398
                //in case of overflow, best effort is to keep first headers
18,032✔
399
                if dyn_headers.overflow > 0 {
18,032✔
400
                    if dyn_headers.overflow == 1 {
103✔
401
                        if dyn_headers.current_size <= (unsafe { HTTP2_MAX_TABLESIZE } as usize) {
103✔
402
                            //overflow had not yet happened
103✔
403
                            dyn_headers.table.push(headcopy);
103✔
404
                        } else if dyn_headers.current_size > dyn_headers.max_size {
103✔
405
                            //overflow happens, we cannot replace evicted headers
×
406
                            dyn_headers.overflow = 2;
×
407
                        }
×
408
                    }
×
409
                } else {
17,929✔
410
                    dyn_headers.table.push(headcopy);
17,929✔
411
                }
17,929✔
412
                let mut toremove = 0;
18,032✔
413
                while dyn_headers.current_size > dyn_headers.max_size
18,365✔
414
                    && toremove < dyn_headers.table.len()
333✔
415
                {
333✔
416
                    dyn_headers.current_size -= 32
333✔
417
                        + dyn_headers.table[toremove].name.len()
333✔
418
                        + dyn_headers.table[toremove].value.len();
333✔
419
                    toremove += 1;
333✔
420
                }
333✔
421
                dyn_headers.table.drain(0..toremove);
18,032✔
422
            }
×
423
            return Ok((r, head));
18,032✔
424
        }
425
        Err(e) => {
209✔
426
            return Err(e);
209✔
427
        }
428
    }
429
}
18,242✔
430

431
fn http2_parse_headers_block_literal_noindex<'a>(
8,138✔
432
    input: &'a [u8], dyn_headers: &HTTP2DynTable,
8,138✔
433
) -> IResult<&'a [u8], HTTP2FrameHeaderBlock> {
8,138✔
434
    fn parser(input: &[u8]) -> IResult<&[u8], (u8, u8)> {
8,138✔
435
        bits(complete(tuple((
8,138✔
436
            verify(take_bits(4u8), |&x| x == 0),
8,138✔
437
            take_bits(4u8),
8,138✔
438
        ))))(input)
8,138✔
439
    }
8,138✔
440
    let (i2, indexed) = parser(input)?;
8,138✔
441
    let (i3, indexreal) = http2_parse_var_uint(i2, indexed.1 as u64, 0xF)?;
8,138✔
442
    let r = http2_parse_headers_block_literal_common(i3, indexreal, dyn_headers);
8,137✔
443
    return r;
8,137✔
444
}
8,138✔
445

446
fn http2_parse_headers_block_literal_neverindex<'a>(
386✔
447
    input: &'a [u8], dyn_headers: &HTTP2DynTable,
386✔
448
) -> IResult<&'a [u8], HTTP2FrameHeaderBlock> {
386✔
449
    fn parser(input: &[u8]) -> IResult<&[u8], (u8, u8)> {
386✔
450
        bits(complete(tuple((
386✔
451
            verify(take_bits(4u8), |&x| x == 1),
386✔
452
            take_bits(4u8),
386✔
453
        ))))(input)
386✔
454
    }
386✔
455
    let (i2, indexed) = parser(input)?;
386✔
456
    let (i3, indexreal) = http2_parse_var_uint(i2, indexed.1 as u64, 0xF)?;
386✔
457
    let r = http2_parse_headers_block_literal_common(i3, indexreal, dyn_headers);
384✔
458
    return r;
384✔
459
}
386✔
460

461
fn http2_parse_var_uint(input: &[u8], value: u64, max: u64) -> IResult<&[u8], u64> {
111,018✔
462
    if value < max {
111,018✔
463
        return Ok((input, value));
106,562✔
464
    }
4,456✔
465
    let (i2, varia) = take_while(|ch| (ch & 0x80) != 0)(input)?;
5,697✔
466
    let (i3, finalv) = be_u8(i2)?;
4,448✔
467
    if varia.len() > 9 || (varia.len() == 9 && finalv > 1) {
4,448✔
468
        // this will overflow u64
469
        return Ok((i3, 0));
5✔
470
    }
4,443✔
471
    let mut varval = max;
4,443✔
472
    for (i, e) in varia.iter().enumerate() {
4,443✔
473
        varval += ((e & 0x7F) as u64) << (7 * i);
830✔
474
    }
830✔
475
    match varval.checked_add((finalv as u64) << (7 * varia.len())) {
4,443✔
476
        None => {
477
            return Err(Err::Error(make_error(i3, ErrorKind::LengthValue)));
×
478
        }
479
        Some(x) => {
4,443✔
480
            return Ok((i3, x));
4,443✔
481
        }
482
    }
483
}
111,018✔
484

485
fn http2_parse_headers_block_dynamic_size<'a>(
2,127✔
486
    input: &'a [u8], dyn_headers: &mut HTTP2DynTable,
2,127✔
487
) -> IResult<&'a [u8], HTTP2FrameHeaderBlock> {
2,127✔
488
    fn parser(input: &[u8]) -> IResult<&[u8], (u8, u8)> {
2,127✔
489
        bits(complete(tuple((
2,127✔
490
            verify(take_bits(3u8), |&x| x == 1),
2,127✔
491
            take_bits(5u8),
2,127✔
492
        ))))(input)
2,127✔
493
    }
2,127✔
494
    let (i2, maxsize) = parser(input)?;
2,127✔
495
    let (i3, maxsize2) = http2_parse_var_uint(i2, maxsize.1 as u64, 0x1F)?;
2,127✔
496
    if (maxsize2 as usize) < dyn_headers.max_size {
2,125✔
497
        //dyn_headers.max_size is updated later with all headers
498
        //may evict entries
499
        let mut toremove = 0;
2,056✔
500
        while dyn_headers.current_size > (maxsize2 as usize) && toremove < dyn_headers.table.len() {
5,171✔
501
            // we check dyn_headers.table as we may be in best effort
3,115✔
502
            // because the previous maxsize was too big for us to retain all the headers
3,115✔
503
            dyn_headers.current_size -= 32
3,115✔
504
                + dyn_headers.table[toremove].name.len()
3,115✔
505
                + dyn_headers.table[toremove].value.len();
3,115✔
506
            toremove += 1;
3,115✔
507
        }
3,115✔
508
        dyn_headers.table.drain(0..toremove);
2,056✔
509
    }
69✔
510
    return Ok((
2,125✔
511
        i3,
2,125✔
512
        HTTP2FrameHeaderBlock {
2,125✔
513
            name: Rc::new(Vec::new()),
2,125✔
514
            value: Rc::new(Vec::new()),
2,125✔
515
            error: HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSizeUpdate,
2,125✔
516
            sizeupdate: maxsize2,
2,125✔
517
        },
2,125✔
518
    ));
2,125✔
519
}
2,127✔
520

521
fn http2_parse_headers_block<'a>(
76,949✔
522
    input: &'a [u8], dyn_headers: &mut HTTP2DynTable,
76,949✔
523
) -> IResult<&'a [u8], HTTP2FrameHeaderBlock> {
76,949✔
524
    //caller guarantees o have at least one byte
76,949✔
525
    if input[0] & 0x80 != 0 {
76,949✔
526
        return http2_parse_headers_block_indexed(input, dyn_headers);
48,056✔
527
    } else if input[0] & 0x40 != 0 {
28,893✔
528
        return http2_parse_headers_block_literal_incindex(input, dyn_headers);
18,242✔
529
    } else if input[0] & 0x20 != 0 {
10,651✔
530
        return http2_parse_headers_block_dynamic_size(input, dyn_headers);
2,127✔
531
    } else if input[0] & 0x10 != 0 {
8,524✔
532
        return http2_parse_headers_block_literal_neverindex(input, dyn_headers);
386✔
533
    } else {
534
        return http2_parse_headers_block_literal_noindex(input, dyn_headers);
8,138✔
535
    }
536
}
76,949✔
537

538
#[derive(Clone, Debug)]
539
pub struct HTTP2FrameHeaders {
540
    pub padlength: Option<u8>,
541
    pub priority: Option<HTTP2FrameHeadersPriority>,
542
    pub blocks: Vec<HTTP2FrameHeaderBlock>,
543
}
544

545
//end stream
546
pub const HTTP2_FLAG_HEADER_EOS: u8 = 0x1;
547
pub const HTTP2_FLAG_HEADER_END_HEADERS: u8 = 0x4;
548
pub const HTTP2_FLAG_HEADER_PADDED: u8 = 0x8;
549
const HTTP2_FLAG_HEADER_PRIORITY: u8 = 0x20;
550

551
fn http2_parse_headers_blocks<'a>(
5,316✔
552
    input: &'a [u8], dyn_headers: &mut HTTP2DynTable,
5,316✔
553
) -> IResult<&'a [u8], Vec<HTTP2FrameHeaderBlock>> {
5,316✔
554
    let mut blocks = Vec::new();
5,316✔
555
    let mut i3 = input;
5,316✔
556
    while !i3.is_empty() {
81,900✔
557
        match http2_parse_headers_block(i3, dyn_headers) {
76,943✔
558
            Ok((rem, b)) => {
76,584✔
559
                blocks.push(b);
76,584✔
560
                debug_validate_bug_on!(i3.len() == rem.len());
76,584✔
561
                if i3.len() == rem.len() {
76,584✔
562
                    //infinite loop
563
                    return Err(Err::Error(make_error(input, ErrorKind::Eof)));
×
564
                }
76,584✔
565
                i3 = rem;
76,584✔
566
            }
567
            Err(Err::Error(ref err)) => {
×
568
                // if we error from http2_parse_var_uint, we keep the first parsed headers
×
569
                if err.code == ErrorKind::LengthValue {
×
570
                    blocks.push(HTTP2FrameHeaderBlock {
×
571
                        name: Rc::new(Vec::new()),
×
572
                        value: Rc::new(Vec::new()),
×
573
                        error: HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeIntegerOverflow,
×
574
                        sizeupdate: 0,
×
575
                    });
×
576
                    break;
×
577
                }
×
578
            }
579
            Err(x) => {
359✔
580
                return Err(x);
359✔
581
            }
582
        }
583
    }
584
    return Ok((i3, blocks));
4,957✔
585
}
5,316✔
586

587
pub fn http2_parse_frame_headers<'a>(
5,285✔
588
    input: &'a [u8], flags: u8, dyn_headers: &mut HTTP2DynTable,
5,285✔
589
) -> IResult<&'a [u8], HTTP2FrameHeaders> {
5,285✔
590
    let (i2, padlength) = cond(flags & HTTP2_FLAG_HEADER_PADDED != 0, be_u8)(input)?;
5,285✔
591
    let (i3, priority) = cond(
5,284✔
592
        flags & HTTP2_FLAG_HEADER_PRIORITY != 0,
5,284✔
593
        http2_parse_headers_priority,
5,284✔
594
    )(i2)?;
5,284✔
595
    let (i3, blocks) = http2_parse_headers_blocks(i3, dyn_headers)?;
5,281✔
596
    return Ok((
4,937✔
597
        i3,
4,937✔
598
        HTTP2FrameHeaders {
4,937✔
599
            padlength,
4,937✔
600
            priority,
4,937✔
601
            blocks,
4,937✔
602
        },
4,937✔
603
    ));
4,937✔
604
}
5,285✔
605

606
#[derive(Clone, Debug)]
607
pub struct HTTP2FramePushPromise {
608
    pub padlength: Option<u8>,
609
    pub reserved: u8,
610
    pub stream_id: u32,
611
    pub blocks: Vec<HTTP2FrameHeaderBlock>,
612
}
613

614
pub fn http2_parse_frame_push_promise<'a>(
34✔
615
    input: &'a [u8], flags: u8, dyn_headers: &mut HTTP2DynTable,
34✔
616
) -> IResult<&'a [u8], HTTP2FramePushPromise> {
34✔
617
    let (i2, padlength) = cond(flags & HTTP2_FLAG_HEADER_PADDED != 0, be_u8)(input)?;
34✔
618
    let (i3, stream_id) = bits(tuple((take_bits(1u8), take_bits(31u32))))(i2)?;
34✔
619
    let (i3, blocks) = http2_parse_headers_blocks(i3, dyn_headers)?;
18✔
620
    return Ok((
4✔
621
        i3,
4✔
622
        HTTP2FramePushPromise {
4✔
623
            padlength,
4✔
624
            reserved: stream_id.0,
4✔
625
            stream_id: stream_id.1,
4✔
626
            blocks,
4✔
627
        },
4✔
628
    ));
4✔
629
}
34✔
630

631
#[derive(Clone, Debug)]
632
pub struct HTTP2FrameContinuation {
633
    pub blocks: Vec<HTTP2FrameHeaderBlock>,
634
}
635

636
pub fn http2_parse_frame_continuation<'a>(
17✔
637
    input: &'a [u8], dyn_headers: &mut HTTP2DynTable,
17✔
638
) -> IResult<&'a [u8], HTTP2FrameContinuation> {
17✔
639
    let (i3, blocks) = http2_parse_headers_blocks(input, dyn_headers)?;
17✔
640
    return Ok((i3, HTTP2FrameContinuation { blocks }));
16✔
641
}
17✔
642

643
#[repr(u16)]
644
#[derive(Clone, Copy, PartialEq, Eq, FromPrimitive, Debug)]
6,967✔
645
pub enum HTTP2SettingsId {
646
    HeaderTableSize = 1,
647
    EnablePush = 2,
648
    MaxConcurrentStreams = 3,
649
    InitialWindowSize = 4,
650
    MaxFrameSize = 5,
651
    MaxHeaderListSize = 6,
652
    EnableConnectProtocol = 8, // rfc8441
653
    NoRfc7540Priorities = 9,   // rfc9218
654
}
655

656
impl fmt::Display for HTTP2SettingsId {
657
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1,332✔
658
        write!(f, "{:?}", self)
1,332✔
659
    }
1,332✔
660
}
661

662
impl std::str::FromStr for HTTP2SettingsId {
663
    type Err = String;
664

665
    fn from_str(s: &str) -> Result<Self, Self::Err> {
14,561✔
666
        let su = s.to_uppercase();
14,561✔
667
        let su_slice: &str = &su;
14,561✔
668
        match su_slice {
14,561✔
669
            "SETTINGS_HEADER_TABLE_SIZE" => Ok(HTTP2SettingsId::HeaderTableSize),
14,561✔
670
            "SETTINGS_ENABLE_PUSH" => Ok(HTTP2SettingsId::EnablePush),
6,211✔
671
            "SETTINGS_MAX_CONCURRENT_STREAMS" => Ok(HTTP2SettingsId::MaxConcurrentStreams),
6,209✔
672
            "SETTINGS_INITIAL_WINDOW_SIZE" => Ok(HTTP2SettingsId::InitialWindowSize),
6,201✔
673
            "SETTINGS_MAX_FRAME_SIZE" => Ok(HTTP2SettingsId::MaxFrameSize),
6,201✔
674
            "SETTINGS_MAX_HEADER_LIST_SIZE" => Ok(HTTP2SettingsId::MaxHeaderListSize),
6,112✔
675
            "SETTINGS_ENABLE_CONNECT_PROTOCOL" => Ok(HTTP2SettingsId::EnableConnectProtocol),
6,111✔
676
            "SETTINGS_NO_RFC7540_PRIORITIES" => Ok(HTTP2SettingsId::NoRfc7540Priorities),
6,111✔
677
            _ => Err(format!("'{}' is not a valid value for HTTP2SettingsId", s)),
6,111✔
678
        }
679
    }
14,561✔
680
}
681

682
pub struct DetectHTTP2settingsSigCtx {
683
    pub id: HTTP2SettingsId,                //identifier
684
    pub value: Option<DetectUintData<u32>>, //optional value
685
}
686

687
pub fn http2_parse_settingsctx(i: &str) -> nom8::IResult<&str, DetectHTTP2settingsSigCtx> {
14,561✔
688
    use nom8::branch::alt as alt8;
689
    use nom8::bytes::complete::{is_a as is_a8, is_not as is_not8};
690
    use nom8::combinator::{
691
        complete as complete8, map_opt as map_opt8, opt as opt8, rest as rest8,
692
    };
693
    use nom8::Parser;
694

695
    let (i, _) = opt8(is_a8(" ")).parse(i)?;
14,561✔
696
    let (i, id) = map_opt8(alt8((complete8(is_not8(" <>=")), rest8)), |s: &str| {
14,561✔
697
        HTTP2SettingsId::from_str(s).ok()
14,561✔
698
    })
14,561✔
699
    .parse(i)?;
14,561✔
700
    let (i, value) = opt8(complete8(detect_parse_uint)).parse(i)?;
8,450✔
701
    Ok((i, DetectHTTP2settingsSigCtx { id, value }))
8,450✔
702
}
14,561✔
703

704
#[derive(Clone, Copy, Debug)]
705
pub struct HTTP2FrameSettings {
706
    pub id: HTTP2SettingsId,
707
    pub value: u32,
708
}
709

710
fn http2_parse_frame_setting(i: &[u8]) -> IResult<&[u8], HTTP2FrameSettings> {
9,046✔
711
    let (i, id) = map_opt(be_u16, num::FromPrimitive::from_u16)(i)?;
9,046✔
712
    let (i, value) = be_u32(i)?;
6,891✔
713
    Ok((i, HTTP2FrameSettings { id, value }))
6,890✔
714
}
9,046✔
715

716
pub fn http2_parse_frame_settings(i: &[u8]) -> IResult<&[u8], Vec<HTTP2FrameSettings>> {
2,156✔
717
    many0(complete(http2_parse_frame_setting))(i)
2,156✔
718
}
2,156✔
719

720
pub fn doh_extract_request(i: &[u8]) -> IResult<&[u8], Vec<u8>> {
1,861✔
721
    let (i, _) = tag("/dns-query?dns=")(i)?;
1,861✔
722
    match STANDARD_NO_PAD.decode(i) {
262✔
723
        Ok(dec) => {
175✔
724
            // i is unused
175✔
725
            return Ok((i, dec));
175✔
726
        }
727
        _ => {
728
            return Err(Err::Error(make_error(i, ErrorKind::MapOpt)));
87✔
729
        }
730
    }
731
}
1,861✔
732

733
#[cfg(test)]
734
mod tests {
735

736
    use super::*;
737
    use crate::detect::uint::DetectUintMode;
738

739
    #[test]
740
    fn test_http2_parse_header() {
1✔
741
        let buf0: &[u8] = &[0x82];
1✔
742
        let mut dynh = HTTP2DynTable::new();
1✔
743
        let r0 = http2_parse_headers_block(buf0, &mut dynh);
1✔
744
        match r0 {
745
            Ok((remainder, hd)) => {
1✔
746
                // Check the first message.
1✔
747
                assert_eq!(hd.name, ":method".as_bytes().to_vec().into());
1✔
748
                assert_eq!(hd.value, "GET".as_bytes().to_vec().into());
1✔
749
                // And we should have no bytes left.
750
                assert_eq!(remainder.len(), 0);
1✔
751
            }
752
            Err(Err::Incomplete(_)) => {
753
                panic!("Result should not have been incomplete.");
754
            }
755
            Err(Err::Error(err)) | Err(Err::Failure(err)) => {
756
                panic!("Result should not be an error: {:?}.", err);
757
            }
758
        }
759
        let buf1: &[u8] = &[0x53, 0x03, 0x2A, 0x2F, 0x2A];
1✔
760
        let r1 = http2_parse_headers_block(buf1, &mut dynh);
1✔
761
        match r1 {
762
            Ok((remainder, hd)) => {
1✔
763
                // Check the first message.
1✔
764
                assert_eq!(hd.name, "accept".as_bytes().to_vec().into());
1✔
765
                assert_eq!(hd.value, "*/*".as_bytes().to_vec().into());
1✔
766
                // And we should have no bytes left.
767
                assert_eq!(remainder.len(), 0);
1✔
768
                assert_eq!(dynh.table.len(), 1);
1✔
769
            }
770
            Err(Err::Incomplete(_)) => {
771
                panic!("Result should not have been incomplete.");
772
            }
773
            Err(Err::Error(err)) | Err(Err::Failure(err)) => {
774
                panic!("Result should not be an error: {:?}.", err);
775
            }
776
        }
777
        let buf: &[u8] = &[
1✔
778
            0x41, 0x8a, 0xa0, 0xe4, 0x1d, 0x13, 0x9d, 0x09, 0xb8, 0xc8, 0x00, 0x0f,
1✔
779
        ];
1✔
780
        let result = http2_parse_headers_block(buf, &mut dynh);
1✔
781
        match result {
782
            Ok((remainder, hd)) => {
1✔
783
                // Check the first message.
1✔
784
                assert_eq!(hd.name, ":authority".as_bytes().to_vec().into());
1✔
785
                assert_eq!(hd.value, "localhost:3000".as_bytes().to_vec().into());
1✔
786
                // And we should have no bytes left.
787
                assert_eq!(remainder.len(), 0);
1✔
788
                assert_eq!(dynh.table.len(), 2);
1✔
789
            }
790
            Err(Err::Incomplete(_)) => {
791
                panic!("Result should not have been incomplete.");
792
            }
793
            Err(Err::Error(err)) | Err(Err::Failure(err)) => {
794
                panic!("Result should not be an error: {:?}.", err);
795
            }
796
        }
797
        let buf3: &[u8] = &[0xbe];
1✔
798
        let r3 = http2_parse_headers_block(buf3, &mut dynh);
1✔
799
        match r3 {
800
            Ok((remainder, hd)) => {
1✔
801
                // same as before
1✔
802
                assert_eq!(hd.name, ":authority".as_bytes().to_vec().into());
1✔
803
                assert_eq!(hd.value, "localhost:3000".as_bytes().to_vec().into());
1✔
804
                // And we should have no bytes left.
805
                assert_eq!(remainder.len(), 0);
1✔
806
                assert_eq!(dynh.table.len(), 2);
1✔
807
            }
808
            Err(Err::Incomplete(_)) => {
809
                panic!("Result should not have been incomplete.");
810
            }
811
            Err(Err::Error(err)) | Err(Err::Failure(err)) => {
812
                panic!("Result should not be an error: {:?}.", err);
813
            }
814
        }
815
        let buf4: &[u8] = &[0x80];
1✔
816
        let r4 = http2_parse_headers_block(buf4, &mut dynh);
1✔
817
        match r4 {
818
            Ok((remainder, hd)) => {
1✔
819
                assert_eq!(hd.error, HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeIndex0);
1✔
820
                assert_eq!(remainder.len(), 0);
1✔
821
                assert_eq!(dynh.table.len(), 2);
1✔
822
            }
823
            Err(Err::Incomplete(_)) => {
824
                panic!("Result should not have been incomplete.");
825
            }
826
            Err(Err::Error(err)) | Err(Err::Failure(err)) => {
827
                panic!("Result should not be an error: {:?}.", err);
828
            }
829
        }
830
        let buf2: &[u8] = &[
1✔
831
            0x04, 0x94, 0x62, 0x43, 0x91, 0x8a, 0x47, 0x55, 0xa3, 0xa1, 0x89, 0xd3, 0x4d, 0x0c,
1✔
832
            0x1a, 0xa9, 0x0b, 0xe5, 0x79, 0xd3, 0x4d, 0x1f,
1✔
833
        ];
1✔
834
        let r2 = http2_parse_headers_block(buf2, &mut dynh);
1✔
835
        match r2 {
836
            Ok((remainder, hd)) => {
1✔
837
                // Check the first message.
1✔
838
                assert_eq!(hd.name, ":path".as_bytes().to_vec().into());
1✔
839
                assert_eq!(
1✔
840
                    hd.value,
1✔
841
                    "/doc/manual/html/index.html".as_bytes().to_vec().into()
1✔
842
                );
1✔
843
                // And we should have no bytes left.
844
                assert_eq!(remainder.len(), 0);
1✔
845
                assert_eq!(dynh.table.len(), 2);
1✔
846
            }
847
            Err(Err::Incomplete(_)) => {
848
                panic!("Result should not have been incomplete.");
849
            }
850
            Err(Err::Error(err)) | Err(Err::Failure(err)) => {
851
                panic!("Result should not be an error: {:?}.", err);
852
            }
853
        }
854
    }
1✔
855

856
    /// Simple test of some valid data.
857
    #[test]
858
    fn test_http2_parse_settingsctx() {
1✔
859
        let s = "SETTINGS_ENABLE_PUSH";
1✔
860
        let r = http2_parse_settingsctx(s);
1✔
861
        match r {
1✔
862
            Ok((rem, ctx)) => {
1✔
863
                assert_eq!(ctx.id, HTTP2SettingsId::EnablePush);
1✔
864
                assert!(ctx.value.is_none());
1✔
865
                assert_eq!(rem.len(), 0);
1✔
866
            }
867
            Err(e) => {
868
                panic!("Result should not be an error {:?}.", e);
869
            }
870
        }
871

872
        //spaces in the end
873
        let s1 = "SETTINGS_ENABLE_PUSH ";
1✔
874
        let r1 = http2_parse_settingsctx(s1);
1✔
875
        match r1 {
1✔
876
            Ok((rem, ctx)) => {
1✔
877
                assert_eq!(ctx.id, HTTP2SettingsId::EnablePush);
1✔
878
                if ctx.value.is_some() {
1✔
879
                    panic!("Unexpected value");
880
                }
1✔
881
                assert_eq!(rem.len(), 1);
1✔
882
            }
883
            Err(e) => {
884
                panic!("Result should not be an error {:?}.", e);
885
            }
886
        }
887

888
        let s2 = "SETTINGS_MAX_CONCURRENT_STREAMS  42";
1✔
889
        let r2 = http2_parse_settingsctx(s2);
1✔
890
        match r2 {
1✔
891
            Ok((rem, ctx)) => {
1✔
892
                assert_eq!(ctx.id, HTTP2SettingsId::MaxConcurrentStreams);
1✔
893
                match ctx.value {
1✔
894
                    Some(ctxval) => {
1✔
895
                        assert_eq!(ctxval.arg1, 42);
1✔
896
                    }
897
                    None => {
898
                        panic!("No value");
899
                    }
900
                }
901
                assert_eq!(rem.len(), 0);
1✔
902
            }
903
            Err(e) => {
904
                panic!("Result should not be an error {:?}.", e);
905
            }
906
        }
907

908
        let s3 = "SETTINGS_MAX_CONCURRENT_STREAMS 42-68";
1✔
909
        let r3 = http2_parse_settingsctx(s3);
1✔
910
        match r3 {
1✔
911
            Ok((rem, ctx)) => {
1✔
912
                assert_eq!(ctx.id, HTTP2SettingsId::MaxConcurrentStreams);
1✔
913
                match ctx.value {
1✔
914
                    Some(ctxval) => {
1✔
915
                        assert_eq!(ctxval.arg1, 42);
1✔
916
                        assert_eq!(ctxval.mode, DetectUintMode::DetectUintModeRange);
1✔
917
                        assert_eq!(ctxval.arg2, 68);
1✔
918
                    }
919
                    None => {
920
                        panic!("No value");
921
                    }
922
                }
923
                assert_eq!(rem.len(), 0);
1✔
924
            }
925
            Err(e) => {
926
                panic!("Result should not be an error {:?}.", e);
927
            }
928
        }
929

930
        let s4 = "SETTINGS_MAX_CONCURRENT_STREAMS<54";
1✔
931
        let r4 = http2_parse_settingsctx(s4);
1✔
932
        match r4 {
1✔
933
            Ok((rem, ctx)) => {
1✔
934
                assert_eq!(ctx.id, HTTP2SettingsId::MaxConcurrentStreams);
1✔
935
                match ctx.value {
1✔
936
                    Some(ctxval) => {
1✔
937
                        assert_eq!(ctxval.arg1, 54);
1✔
938
                        assert_eq!(ctxval.mode, DetectUintMode::DetectUintModeLt);
1✔
939
                    }
940
                    None => {
941
                        panic!("No value");
942
                    }
943
                }
944
                assert_eq!(rem.len(), 0);
1✔
945
            }
946
            Err(e) => {
947
                panic!("Result should not be an error {:?}.", e);
948
            }
949
        }
950

951
        let s5 = "SETTINGS_MAX_CONCURRENT_STREAMS > 76";
1✔
952
        let r5 = http2_parse_settingsctx(s5);
1✔
953
        match r5 {
1✔
954
            Ok((rem, ctx)) => {
1✔
955
                assert_eq!(ctx.id, HTTP2SettingsId::MaxConcurrentStreams);
1✔
956
                match ctx.value {
1✔
957
                    Some(ctxval) => {
1✔
958
                        assert_eq!(ctxval.arg1, 76);
1✔
959
                        assert_eq!(ctxval.mode, DetectUintMode::DetectUintModeGt);
1✔
960
                    }
961
                    None => {
962
                        panic!("No value");
963
                    }
964
                }
965
                assert_eq!(rem.len(), 0);
1✔
966
            }
967
            Err(e) => {
968
                panic!("Result should not be an error {:?}.", e);
969
            }
970
        }
971
    }
1✔
972

973
    #[test]
974
    fn test_http2_parse_headers_block_string() {
1✔
975
        let buf: &[u8] = &[0x01, 0xFF];
1✔
976
        let r = http2_parse_headers_block_string(buf);
1✔
977
        match r {
978
            Ok((remainder, _)) => {
1✔
979
                assert_eq!(remainder.len(), 0);
1✔
980
            }
981
            Err(Err::Error(err)) | Err(Err::Failure(err)) => {
982
                panic!("Result should not be an error: {:?}.", err);
983
            }
984
            _ => {
985
                panic!("Result should have been ok");
986
            }
987
        }
988
        let buf2: &[u8] = &[0x83, 0xFF, 0xFF, 0xEA];
1✔
989
        let r2 = http2_parse_headers_block_string(buf2);
1✔
990
        match r2 {
1✔
991
            Ok((remainder, _)) => {
1✔
992
                assert_eq!(remainder.len(), 0);
1✔
993
            }
994
            _ => {
995
                panic!("Result should have been ok");
996
            }
997
        }
998
    }
1✔
999

1000
    #[test]
1001
    fn test_http2_parse_frame_header() {
1✔
1002
        let buf: &[u8] = &[
1✔
1003
            0x00, 0x00, 0x06, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1✔
1004
            0x64,
1✔
1005
        ];
1✔
1006
        let result = http2_parse_frame_header(buf);
1✔
1007
        match result {
1008
            Ok((remainder, frame)) => {
1✔
1009
                // Check the first message.
1✔
1010
                assert_eq!(frame.length, 6);
1✔
1011
                assert_eq!(frame.ftype, HTTP2FrameType::Settings as u8);
1✔
1012
                assert_eq!(frame.flags, 0);
1✔
1013
                assert_eq!(frame.reserved, 0);
1✔
1014
                assert_eq!(frame.stream_id, 0);
1✔
1015

1016
                // And we should have 6 bytes left.
1017
                assert_eq!(remainder.len(), 6);
1✔
1018
            }
1019
            Err(Err::Incomplete(_)) => {
1020
                panic!("Result should not have been incomplete.");
1021
            }
1022
            Err(Err::Error(err)) | Err(Err::Failure(err)) => {
1023
                panic!("Result should not be an error: {:?}.", err);
1024
            }
1025
        }
1026
    }
1✔
1027
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc