Coverage Report

Created: 2026-09-06 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/rust/src/http2/parser.rs
Line
Count
Source
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 nom7::bits::streaming::take as take_bits;
23
use nom7::branch::alt;
24
use nom7::bytes::complete::tag;
25
use nom7::bytes::streaming::{is_a, is_not, take, take_while};
26
use nom7::combinator::{complete, cond, map_opt, opt, rest, 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::str::FromStr;
34
use std::rc::Rc;
35
use base64::{Engine, engine::general_purpose::STANDARD_NO_PAD};
36
37
#[repr(u8)]
38
#[derive(Clone, Copy, PartialEq, Eq, FromPrimitive, Debug)]
39
pub enum HTTP2FrameType {
40
    Data = 0,
41
    Headers = 1,
42
    Priority = 2,
43
    RstStream = 3,
44
    Settings = 4,
45
    PushPromise = 5,
46
    Ping = 6,
47
    GoAway = 7,
48
    WindowUpdate = 8,
49
    Continuation = 9,
50
}
51
52
impl fmt::Display for HTTP2FrameType {
53
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
54
0
        write!(f, "{:?}", self)
55
0
    }
56
}
57
58
impl std::str::FromStr for HTTP2FrameType {
59
    type Err = String;
60
61
133
    fn from_str(s: &str) -> Result<Self, Self::Err> {
62
133
        let su = s.to_uppercase();
63
133
        let su_slice: &str = &su;
64
133
        match su_slice {
65
133
            "DATA" => Ok(HTTP2FrameType::Data),
66
133
            "HEADERS" => Ok(HTTP2FrameType::Headers),
67
133
            "PRIORITY" => Ok(HTTP2FrameType::Priority),
68
133
            "RSTSTREAM" => Ok(HTTP2FrameType::RstStream),
69
133
            "SETTINGS" => Ok(HTTP2FrameType::Settings),
70
133
            "PUSHPROMISE" => Ok(HTTP2FrameType::PushPromise),
71
133
            "PING" => Ok(HTTP2FrameType::Ping),
72
133
            "GOAWAY" => Ok(HTTP2FrameType::GoAway),
73
50
            "WINDOWUPDATE" => Ok(HTTP2FrameType::WindowUpdate),
74
50
            "CONTINUATION" => Ok(HTTP2FrameType::Continuation),
75
50
            _ => Err(format!("'{}' is not a valid value for HTTP2FrameType", s)),
76
        }
77
133
    }
78
}
79
80
#[derive(PartialEq, Eq, Debug)]
81
pub struct HTTP2FrameHeader {
82
    //we could add detection on (GOAWAY) additional data
83
    pub length: u32,
84
    pub ftype: u8,
85
    pub flags: u8,
86
    pub reserved: u8,
87
    pub stream_id: u32,
88
}
89
90
7.44M
pub fn http2_parse_frame_header(i: &[u8]) -> IResult<&[u8], HTTP2FrameHeader> {
91
7.44M
    let (i, length) = be_u24(i)?;
92
6.88M
    let (i, ftype) = be_u8(i)?;
93
6.85M
    let (i, flags) = be_u8(i)?;
94
6.79M
    let (i, b) = be_u32(i)?;
95
6.46M
    let (reserved, stream_id) = ((b >> 31) as u8, b & 0x7fff_ffff);
96
6.46M
    Ok((
97
6.46M
        i,
98
6.46M
        HTTP2FrameHeader {
99
6.46M
            length,
100
6.46M
            ftype,
101
6.46M
            flags,
102
6.46M
            reserved,
103
6.46M
            stream_id,
104
6.46M
        },
105
6.46M
    ))
106
7.44M
}
107
108
#[repr(u32)]
109
#[derive(Clone, Copy, PartialEq, Eq, FromPrimitive, Debug)]
110
pub enum HTTP2ErrorCode {
111
    NoError = 0,
112
    ProtocolError = 1,
113
    InternalError = 2,
114
    FlowControlError = 3,
115
    SettingsTimeout = 4,
116
    StreamClosed = 5,
117
    FrameSizeError = 6,
118
    RefusedStream = 7,
119
    Cancel = 8,
120
    CompressionError = 9,
121
    ConnectError = 10,
122
    EnhanceYourCalm = 11,
123
    InadequateSecurity = 12,
124
    Http11Required = 13,
125
}
126
127
impl fmt::Display for HTTP2ErrorCode {
128
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
129
0
        write!(f, "{:?}", self)
130
0
    }
131
}
132
133
impl std::str::FromStr for HTTP2ErrorCode {
134
    type Err = String;
135
136
10
    fn from_str(s: &str) -> Result<Self, Self::Err> {
137
10
        let su = s.to_uppercase();
138
10
        let su_slice: &str = &su;
139
10
        match su_slice {
140
10
            "NO_ERROR" => Ok(HTTP2ErrorCode::NoError),
141
10
            "PROTOCOL_ERROR" => Ok(HTTP2ErrorCode::ProtocolError),
142
10
            "INTERNAL_ERROR" => Ok(HTTP2ErrorCode::InternalError),
143
10
            "FLOW_CONTROL_ERROR" => Ok(HTTP2ErrorCode::FlowControlError),
144
10
            "SETTINGS_TIMEOUT" => Ok(HTTP2ErrorCode::SettingsTimeout),
145
10
            "STREAM_CLOSED" => Ok(HTTP2ErrorCode::StreamClosed),
146
10
            "FRAME_SIZE_ERROR" => Ok(HTTP2ErrorCode::FrameSizeError),
147
10
            "REFUSED_STREAM" => Ok(HTTP2ErrorCode::RefusedStream),
148
10
            "CANCEL" => Ok(HTTP2ErrorCode::Cancel),
149
10
            "COMPRESSION_ERROR" => Ok(HTTP2ErrorCode::CompressionError),
150
10
            "CONNECT_ERROR" => Ok(HTTP2ErrorCode::ConnectError),
151
10
            "ENHANCE_YOUR_CALM" => Ok(HTTP2ErrorCode::EnhanceYourCalm),
152
10
            "INADEQUATE_SECURITY" => Ok(HTTP2ErrorCode::InadequateSecurity),
153
10
            "HTTP_1_1_REQUIRED" => Ok(HTTP2ErrorCode::Http11Required),
154
10
            _ => Err(format!("'{}' is not a valid value for HTTP2ErrorCode", s)),
155
        }
156
10
    }
157
}
158
159
#[derive(Clone, Copy, Debug)]
160
pub struct HTTP2FrameGoAway {
161
    pub errorcode: u32, //HTTP2ErrorCode
162
}
163
164
2.06k
pub fn http2_parse_frame_goaway(i: &[u8]) -> IResult<&[u8], HTTP2FrameGoAway> {
165
2.06k
    let (i, _last_stream_id) = be_u32(i)?;
166
2.06k
    let (i, errorcode) = be_u32(i)?;
167
2.06k
    Ok((i, HTTP2FrameGoAway { errorcode }))
168
2.06k
}
169
170
#[derive(Clone, Copy, Debug)]
171
pub struct HTTP2FrameRstStream {
172
    pub errorcode: u32, ////HTTP2ErrorCode
173
}
174
175
5.36k
pub fn http2_parse_frame_rststream(i: &[u8]) -> IResult<&[u8], HTTP2FrameRstStream> {
176
5.36k
    let (i, errorcode) = be_u32(i)?;
177
5.36k
    Ok((i, HTTP2FrameRstStream { errorcode }))
178
5.36k
}
179
180
#[derive(Clone, Copy, Debug)]
181
pub struct HTTP2FramePriority {
182
    pub exclusive: u8,
183
    pub dependency: u32,
184
    pub weight: u8,
185
}
186
187
47.8k
pub fn http2_parse_frame_priority(i: &[u8]) -> IResult<&[u8], HTTP2FramePriority> {
188
47.8k
    let (i, b) = be_u32(i)?;
189
47.8k
    let (exclusive, dependency) = ((b >> 31) as u8, b & 0x7fff_ffff);
190
47.8k
    let (i, weight) = be_u8(i)?;
191
47.8k
    Ok((
192
47.8k
        i,
193
47.8k
        HTTP2FramePriority {
194
47.8k
            exclusive,
195
47.8k
            dependency,
196
47.8k
            weight,
197
47.8k
        },
198
47.8k
    ))
199
47.8k
}
200
201
#[derive(Clone, Copy, Debug)]
202
pub struct HTTP2FrameWindowUpdate {
203
    pub reserved: u8,
204
    pub sizeinc: u32,
205
}
206
207
1.63k
pub fn http2_parse_frame_windowupdate(i: &[u8]) -> IResult<&[u8], HTTP2FrameWindowUpdate> {
208
1.63k
    let (i, b) = be_u32(i)?;
209
1.63k
    let (reserved, sizeinc) = ((b >> 31) as u8, b & 0x7fff_ffff);
210
1.63k
    Ok((i, HTTP2FrameWindowUpdate { reserved, sizeinc }))
211
1.63k
}
212
213
#[derive(Clone, Copy, Debug)]
214
pub struct HTTP2FrameHeadersPriority {
215
    pub exclusive: u8,
216
    pub dependency: u32,
217
    pub weight: u8,
218
}
219
220
17.4k
pub fn http2_parse_headers_priority(i: &[u8]) -> IResult<&[u8], HTTP2FrameHeadersPriority> {
221
17.4k
    let (i, b) = be_u32(i)?;
222
15.9k
    let (exclusive, dependency) = ((b >> 31) as u8, b & 0x7fff_ffff);
223
15.9k
    let (i, weight) = be_u8(i)?;
224
14.9k
    Ok((
225
14.9k
        i,
226
14.9k
        HTTP2FrameHeadersPriority {
227
14.9k
            exclusive,
228
14.9k
            dependency,
229
14.9k
            weight,
230
14.9k
        },
231
14.9k
    ))
232
17.4k
}
233
234
pub const HTTP2_STATIC_HEADERS_NUMBER: usize = 61;
235
236
15.1M
fn http2_frame_header_static(n: u64, dyn_headers: &HTTP2DynTable) -> Option<HTTP2FrameHeaderBlock> {
237
15.1M
    let (name, value) = match n {
238
330k
        1 => (":authority", ""),
239
13.1k
        2 => (":method", "GET"),
240
21.0k
        3 => (":method", "POST"),
241
217k
        4 => (":path", "/"),
242
81.7k
        5 => (":path", "/index.html"),
243
101k
        6 => (":scheme", "http"),
244
14.0k
        7 => (":scheme", "https"),
245
16.5k
        8 => (":status", "200"),
246
436k
        9 => (":status", "204"),
247
19.3k
        10 => (":status", "206"),
248
26.9k
        11 => (":status", "304"),
249
26.1k
        12 => (":status", "400"),
250
28.1k
        13 => (":status", "404"),
251
76.4k
        14 => (":status", "500"),
252
16.1k
        15 => ("accept-charset", ""),
253
15.1k
        16 => ("accept-encoding", "gzip, deflate"),
254
12.6k
        17 => ("accept-language", ""),
255
11.5k
        18 => ("accept-ranges", ""),
256
16.7k
        19 => ("accept", ""),
257
47.1k
        20 => ("access-control-allow-origin", ""),
258
6.23k
        21 => ("age", ""),
259
11.9k
        22 => ("allow", ""),
260
103k
        23 => ("authorization", ""),
261
19.8k
        24 => ("cache-control", ""),
262
8.23k
        25 => ("content-disposition", ""),
263
23.6k
        26 => ("content-encoding", ""),
264
50.3k
        27 => ("content-language", ""),
265
6.07k
        28 => ("content-length", ""),
266
13.1k
        29 => ("content-location", ""),
267
362k
        30 => ("content-range", ""),
268
12.8k
        31 => ("content-type", ""),
269
247k
        32 => ("cookie", ""),
270
11.9k
        33 => ("date", ""),
271
5.45k
        34 => ("etag", ""),
272
9.18k
        35 => ("expect", ""),
273
12.8k
        36 => ("expires", ""),
274
255k
        37 => ("from", ""),
275
40.0k
        38 => ("host", ""),
276
17.5k
        39 => ("if-match", ""),
277
42.9k
        40 => ("if-modified-since", ""),
278
167k
        41 => ("if-none-match", ""),
279
32.9k
        42 => ("if-range", ""),
280
5.04k
        43 => ("if-unmodified-since", ""),
281
105k
        44 => ("last-modified", ""),
282
2.33k
        45 => ("link", ""),
283
23.9k
        46 => ("location", ""),
284
122k
        47 => ("max-forwards", ""),
285
25.8k
        48 => ("proxy-authenticate", ""),
286
86.4k
        49 => ("proxy-authorization", ""),
287
6.39k
        50 => ("range", ""),
288
25.7k
        51 => ("referer", ""),
289
11.7k
        52 => ("refresh", ""),
290
111k
        53 => ("retry-after", ""),
291
245k
        54 => ("server", ""),
292
9.10k
        55 => ("set-cookie", ""),
293
52.2k
        56 => ("strict-transport-security", ""),
294
4.56k
        57 => ("transfer-encoding", ""),
295
91.5k
        58 => ("user-agent", ""),
296
35.1k
        59 => ("vary", ""),
297
2.30k
        60 => ("via", ""),
298
19.6k
        61 => ("www-authenticate", ""),
299
11.1M
        _ => ("", ""),
300
    };
301
15.1M
    if !name.is_empty() {
302
3.97M
        return Some(HTTP2FrameHeaderBlock {
303
3.97M
            name: Rc::new(name.as_bytes().to_vec()),
304
3.97M
            value: Rc::new(value.as_bytes().to_vec()),
305
3.97M
            error: HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSuccess,
306
3.97M
            sizeupdate: 0,
307
3.97M
        });
308
    } else {
309
        //use dynamic table
310
11.1M
        if n == 0 {
311
6.50M
            return Some(HTTP2FrameHeaderBlock {
312
6.50M
                name: Rc::new(Vec::new()),
313
6.50M
                value: Rc::new(Vec::new()),
314
6.50M
                error: HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeIndex0,
315
6.50M
                sizeupdate: 0,
316
6.50M
            });
317
4.68M
        } else if dyn_headers.table.len() + HTTP2_STATIC_HEADERS_NUMBER < n as usize {
318
4.02M
            return Some(HTTP2FrameHeaderBlock {
319
4.02M
                name: Rc::new(Vec::new()),
320
4.02M
                value: Rc::new(Vec::new()),
321
4.02M
                error: HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeNotIndexed,
322
4.02M
                sizeupdate: 0,
323
4.02M
            });
324
        } else {
325
657k
            let indyn = dyn_headers.table.len() - (n as usize - HTTP2_STATIC_HEADERS_NUMBER);
326
657k
            let headcopy = HTTP2FrameHeaderBlock {
327
657k
                name: dyn_headers.table[indyn].name.clone(),
328
657k
                value: dyn_headers.table[indyn].value.clone(),
329
657k
                error: HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSuccess,
330
657k
                sizeupdate: 0,
331
657k
            };
332
657k
            return Some(headcopy);
333
        }
334
    }
335
15.1M
}
336
337
#[repr(u8)]
338
#[derive(Copy, Clone, PartialOrd, PartialEq, Eq, Debug)]
339
pub enum HTTP2HeaderDecodeStatus {
340
    HTTP2HeaderDecodeSuccess = 0,
341
    HTTP2HeaderDecodeSizeUpdate = 1,
342
    HTTP2HeaderDecodeError = 0x80,
343
    HTTP2HeaderDecodeNotIndexed = 0x81,
344
    HTTP2HeaderDecodeIntegerOverflow = 0x82,
345
    HTTP2HeaderDecodeIndex0 = 0x83,
346
}
347
348
impl fmt::Display for HTTP2HeaderDecodeStatus {
349
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
350
0
        write!(f, "{:?}", self)
351
0
    }
352
}
353
354
#[derive(Clone, Debug)]
355
pub struct HTTP2FrameHeaderBlock {
356
    // Use Rc reference counted so that indexed headers do not get copied.
357
    // Otherwise, this leads to quadratic complexity in memory occupation.
358
    pub name: Rc<Vec<u8>>,
359
    pub value: Rc<Vec<u8>>,
360
    pub error: HTTP2HeaderDecodeStatus,
361
    pub sizeupdate: u64,
362
}
363
364
12.8M
fn http2_parse_headers_block_indexed<'a>(
365
12.8M
    input: &'a [u8], dyn_headers: &HTTP2DynTable,
366
12.8M
) -> IResult<&'a [u8], HTTP2FrameHeaderBlock> {
367
12.8M
    fn parser(input: &[u8]) -> IResult<&[u8], (u8, u8)> {
368
12.8M
        bits(complete(tuple((
369
12.8M
            verify(take_bits(1u8), |&x| x == 1),
370
12.8M
            take_bits(7u8),
371
12.8M
        ))))(input)
372
12.8M
    }
373
12.8M
    let (i2, indexed) = parser(input)?;
374
12.8M
    let (i3, indexreal) = http2_parse_var_uint(i2, indexed.1 as u64, 0x7F)?;
375
12.8M
    match http2_frame_header_static(indexreal, dyn_headers) {
376
12.8M
        Some(h) => Ok((i3, h)),
377
0
        _ => Err(Err::Error(make_error(i3, ErrorKind::MapOpt))),
378
    }
379
12.8M
}
380
381
18.7M
fn http2_parse_headers_block_string(input: &[u8]) -> IResult<&[u8], Vec<u8>> {
382
18.7M
    fn parser(input: &[u8]) -> IResult<&[u8], (u8, u8)> {
383
18.7M
        bits(tuple((take_bits(1u8), take_bits(7u8))))(input)
384
18.7M
    }
385
18.7M
    let (i1, huffslen) = parser(input)?;
386
18.5M
    let (i2, stringlen) = http2_parse_var_uint(i1, huffslen.1 as u64, 0x7F)?;
387
18.5M
    let (i3, data) = take(stringlen as usize)(i2)?;
388
18.2M
    if huffslen.0 == 0 {
389
17.6M
        return Ok((i3, data.to_vec()));
390
    } else {
391
573k
        let (_, val) = bits(many0(huffman::http2_decode_huffman))(data)?;
392
573k
        return Ok((i3, val));
393
    }
394
18.7M
}
395
396
10.5M
fn http2_parse_headers_block_literal_common<'a>(
397
10.5M
    input: &'a [u8], index: u64, dyn_headers: &HTTP2DynTable,
398
10.5M
) -> IResult<&'a [u8], HTTP2FrameHeaderBlock> {
399
10.5M
    let (i3, name, error) = if index == 0 {
400
8.29M
        match http2_parse_headers_block_string(input) {
401
8.10M
            Ok((r, n)) => Ok((r, Rc::new(n), HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSuccess)),
402
190k
            Err(e) => Err(e),
403
        }
404
    } else {
405
2.30M
        match http2_frame_header_static(index, dyn_headers) {
406
2.30M
            Some(x) => Ok((
407
2.30M
                input,
408
2.30M
                x.name,
409
2.30M
                HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSuccess,
410
2.30M
            )),
411
0
            None => Ok((
412
0
                input,
413
0
                Rc::new(Vec::new()),
414
0
                HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeNotIndexed,
415
0
            )),
416
        }
417
190k
    }?;
418
10.4M
    let (i4, value) = http2_parse_headers_block_string(i3)?;
419
10.1M
    return Ok((
420
10.1M
        i4,
421
10.1M
        HTTP2FrameHeaderBlock {
422
10.1M
            name,
423
10.1M
            value: Rc::new(value),
424
10.1M
            error,
425
10.1M
            sizeupdate: 0,
426
10.1M
        },
427
10.1M
    ));
428
10.5M
}
429
430
1.23M
fn http2_parse_headers_block_literal_incindex<'a>(
431
1.23M
    input: &'a [u8], dyn_headers: &mut HTTP2DynTable,
432
1.23M
) -> IResult<&'a [u8], HTTP2FrameHeaderBlock> {
433
1.23M
    fn parser(input: &[u8]) -> IResult<&[u8], (u8, u8)> {
434
1.23M
        bits(complete(tuple((
435
1.23M
            verify(take_bits(2u8), |&x| x == 1),
436
1.23M
            take_bits(6u8),
437
1.23M
        ))))(input)
438
1.23M
    }
439
1.23M
    let (i2, indexed) = parser(input)?;
440
1.23M
    let (i3, indexreal) = http2_parse_var_uint(i2, indexed.1 as u64, 0x3F)?;
441
1.23M
    let r = http2_parse_headers_block_literal_common(i3, indexreal, dyn_headers);
442
1.23M
    match r {
443
1.05M
        Ok((r, head)) => {
444
1.05M
            let headcopy = HTTP2FrameHeaderBlock {
445
1.05M
                name: head.name.clone(),
446
1.05M
                value: head.value.clone(),
447
1.05M
                error: head.error,
448
1.05M
                sizeupdate: 0,
449
1.05M
            };
450
1.05M
            if head.error == HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSuccess {
451
1.05M
                dyn_headers.current_size += 32 + headcopy.name.len() + headcopy.value.len();
452
                //in case of overflow, best effort is to keep first headers
453
1.05M
                if dyn_headers.overflow > 0 {
454
424k
                    if dyn_headers.overflow == 1 {
455
383k
                        if dyn_headers.current_size <= (unsafe { HTTP2_MAX_TABLESIZE } as usize) {
456
231k
                            //overflow had not yet happened
457
231k
                            dyn_headers.table.push(headcopy);
458
231k
                        } else if dyn_headers.current_size > dyn_headers.max_size {
459
67
                            //overflow happens, we cannot replace evicted headers
460
67
                            dyn_headers.overflow = 2;
461
151k
                        }
462
40.9k
                    }
463
633k
                } else {
464
633k
                    dyn_headers.table.push(headcopy);
465
633k
                }
466
1.05M
                let mut toremove = 0;
467
1.39M
                while dyn_headers.current_size > dyn_headers.max_size
468
361k
                    && toremove < dyn_headers.table.len()
469
335k
                {
470
335k
                    dyn_headers.current_size -= 32
471
335k
                        + dyn_headers.table[toremove].name.len()
472
335k
                        + dyn_headers.table[toremove].value.len();
473
335k
                    toremove += 1;
474
335k
                }
475
1.05M
                dyn_headers.table.drain(0..toremove);
476
0
            }
477
1.05M
            return Ok((r, head));
478
        }
479
176k
        Err(e) => {
480
176k
            return Err(e);
481
        }
482
    }
483
1.23M
}
484
485
9.11M
fn http2_parse_headers_block_literal_noindex<'a>(
486
9.11M
    input: &'a [u8], dyn_headers: &HTTP2DynTable,
487
9.11M
) -> IResult<&'a [u8], HTTP2FrameHeaderBlock> {
488
9.11M
    fn parser(input: &[u8]) -> IResult<&[u8], (u8, u8)> {
489
9.11M
        bits(complete(tuple((
490
9.11M
            verify(take_bits(4u8), |&x| x == 0),
491
9.11M
            take_bits(4u8),
492
9.11M
        ))))(input)
493
9.11M
    }
494
9.11M
    let (i2, indexed) = parser(input)?;
495
9.11M
    let (i3, indexreal) = http2_parse_var_uint(i2, indexed.1 as u64, 0xF)?;
496
9.11M
    let r = http2_parse_headers_block_literal_common(i3, indexreal, dyn_headers);
497
9.11M
    return r;
498
9.11M
}
499
500
247k
fn http2_parse_headers_block_literal_neverindex<'a>(
501
247k
    input: &'a [u8], dyn_headers: &HTTP2DynTable,
502
247k
) -> IResult<&'a [u8], HTTP2FrameHeaderBlock> {
503
247k
    fn parser(input: &[u8]) -> IResult<&[u8], (u8, u8)> {
504
247k
        bits(complete(tuple((
505
247k
            verify(take_bits(4u8), |&x| x == 1),
506
247k
            take_bits(4u8),
507
247k
        ))))(input)
508
247k
    }
509
247k
    let (i2, indexed) = parser(input)?;
510
247k
    let (i3, indexreal) = http2_parse_var_uint(i2, indexed.1 as u64, 0xF)?;
511
246k
    let r = http2_parse_headers_block_literal_common(i3, indexreal, dyn_headers);
512
246k
    return r;
513
247k
}
514
515
44.3M
fn http2_parse_var_uint(input: &[u8], value: u64, max: u64) -> IResult<&[u8], u64> {
516
44.3M
    if value < max {
517
43.6M
        return Ok((input, value));
518
748k
    }
519
6.52M
    let (i2, varia) = take_while(|ch| (ch & 0x80) != 0)(input)?;
520
709k
    let (i3, finalv) = be_u8(i2)?;
521
709k
    if varia.len() > 9 || (varia.len() == 9 && finalv > 1) {
522
        // this will overflow u64
523
54.4k
        return Ok((i3, 0));
524
655k
    }
525
655k
    let mut varval = max;
526
711k
    for (i, e) in varia.iter().enumerate() {
527
711k
        varval += ((e & 0x7F) as u64) << (7 * i);
528
711k
    }
529
655k
    match varval.checked_add((finalv as u64) << (7 * varia.len())) {
530
        None => {
531
4.01k
            return Err(Err::Error(make_error(i3, ErrorKind::LengthValue)));
532
        }
533
651k
        Some(x) => {
534
651k
            return Ok((i3, x));
535
        }
536
    }
537
44.3M
}
538
539
2.29M
fn http2_parse_headers_block_dynamic_size<'a>(
540
2.29M
    input: &'a [u8], dyn_headers: &mut HTTP2DynTable,
541
2.29M
) -> IResult<&'a [u8], HTTP2FrameHeaderBlock> {
542
2.29M
    fn parser(input: &[u8]) -> IResult<&[u8], (u8, u8)> {
543
2.29M
        bits(complete(tuple((
544
2.29M
            verify(take_bits(3u8), |&x| x == 1),
545
2.29M
            take_bits(5u8),
546
2.29M
        ))))(input)
547
2.29M
    }
548
2.29M
    let (i2, maxsize) = parser(input)?;
549
2.29M
    let (i3, maxsize2) = http2_parse_var_uint(i2, maxsize.1 as u64, 0x1F)?;
550
2.28M
    if (maxsize2 as usize) < dyn_headers.max_size {
551
        //dyn_headers.max_size is updated later with all headers
552
        //may evict entries
553
1.99M
        let mut toremove = 0;
554
2.38M
        while dyn_headers.current_size > (maxsize2 as usize) && toremove < dyn_headers.table.len() {
555
392k
            // we check dyn_headers.table as we may be in best effort
556
392k
            // because the previous maxsize was too big for us to retain all the headers
557
392k
            dyn_headers.current_size -= 32
558
392k
                + dyn_headers.table[toremove].name.len()
559
392k
                + dyn_headers.table[toremove].value.len();
560
392k
            toremove += 1;
561
392k
        }
562
1.99M
        dyn_headers.table.drain(0..toremove);
563
292k
    }
564
2.28M
    return Ok((
565
2.28M
        i3,
566
2.28M
        HTTP2FrameHeaderBlock {
567
2.28M
            name: Rc::new(Vec::new()),
568
2.28M
            value: Rc::new(Vec::new()),
569
2.28M
            error: HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSizeUpdate,
570
2.28M
            sizeupdate: maxsize2,
571
2.28M
        },
572
2.28M
    ));
573
2.29M
}
574
575
25.7M
fn http2_parse_headers_block<'a>(
576
25.7M
    input: &'a [u8], dyn_headers: &mut HTTP2DynTable,
577
25.7M
) -> IResult<&'a [u8], HTTP2FrameHeaderBlock> {
578
    //caller guarantees o have at least one byte
579
25.7M
    if input[0] & 0x80 != 0 {
580
12.8M
        return http2_parse_headers_block_indexed(input, dyn_headers);
581
12.8M
    } else if input[0] & 0x40 != 0 {
582
1.23M
        return http2_parse_headers_block_literal_incindex(input, dyn_headers);
583
11.6M
    } else if input[0] & 0x20 != 0 {
584
2.29M
        return http2_parse_headers_block_dynamic_size(input, dyn_headers);
585
9.36M
    } else if input[0] & 0x10 != 0 {
586
247k
        return http2_parse_headers_block_literal_neverindex(input, dyn_headers);
587
    } else {
588
9.11M
        return http2_parse_headers_block_literal_noindex(input, dyn_headers);
589
    }
590
25.7M
}
591
592
#[derive(Clone, Debug)]
593
pub struct HTTP2FrameHeaders {
594
    pub padlength: Option<u8>,
595
    pub priority: Option<HTTP2FrameHeadersPriority>,
596
    pub blocks: Vec<HTTP2FrameHeaderBlock>,
597
}
598
599
//end stream
600
pub const HTTP2_FLAG_HEADER_EOS: u8 = 0x1;
601
pub const HTTP2_FLAG_HEADER_END_HEADERS: u8 = 0x4;
602
pub const HTTP2_FLAG_HEADER_PADDED: u8 = 0x8;
603
const HTTP2_FLAG_HEADER_PRIORITY: u8 = 0x20;
604
605
1.07M
fn http2_parse_headers_blocks<'a>(
606
1.07M
    input: &'a [u8], dyn_headers: &mut HTTP2DynTable,
607
1.07M
) -> IResult<&'a [u8], Vec<HTTP2FrameHeaderBlock>> {
608
1.07M
    let mut blocks = Vec::new();
609
1.07M
    let mut i3 = input;
610
26.3M
    while !i3.is_empty() {
611
25.7M
        match http2_parse_headers_block(i3, dyn_headers) {
612
25.2M
            Ok((rem, b)) => {
613
25.2M
                blocks.push(b);
614
25.2M
                debug_validate_bug_on!(i3.len() == rem.len());
615
25.2M
                if i3.len() == rem.len() {
616
                    //infinite loop
617
0
                    return Err(Err::Error(make_error(input, ErrorKind::Eof)));
618
25.2M
                }
619
25.2M
                i3 = rem;
620
            }
621
4.01k
            Err(Err::Error(ref err)) => {
622
                // if we error from http2_parse_var_uint, we keep the first parsed headers
623
4.01k
                if err.code == ErrorKind::LengthValue {
624
4.01k
                    blocks.push(HTTP2FrameHeaderBlock {
625
4.01k
                        name: Rc::new(Vec::new()),
626
4.01k
                        value: Rc::new(Vec::new()),
627
4.01k
                        error: HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeIntegerOverflow,
628
4.01k
                        sizeupdate: 0,
629
4.01k
                    });
630
4.01k
                    break;
631
0
                }
632
            }
633
509k
            Err(x) => {
634
509k
                return Err(x);
635
            }
636
        }
637
    }
638
562k
    return Ok((i3, blocks));
639
1.07M
}
640
641
80.9k
pub fn http2_parse_frame_headers<'a>(
642
80.9k
    input: &'a [u8], flags: u8, dyn_headers: &mut HTTP2DynTable,
643
80.9k
) -> IResult<&'a [u8], HTTP2FrameHeaders> {
644
80.9k
    let (i2, padlength) = cond(flags & HTTP2_FLAG_HEADER_PADDED != 0, be_u8)(input)?;
645
80.0k
    let (i3, priority) = cond(
646
80.0k
        flags & HTTP2_FLAG_HEADER_PRIORITY != 0,
647
80.0k
        http2_parse_headers_priority,
648
80.0k
    )(i2)?;
649
77.6k
    let (i3, blocks) = http2_parse_headers_blocks(i3, dyn_headers)?;
650
27.0k
    return Ok((
651
27.0k
        i3,
652
27.0k
        HTTP2FrameHeaders {
653
27.0k
            padlength,
654
27.0k
            priority,
655
27.0k
            blocks,
656
27.0k
        },
657
27.0k
    ));
658
80.9k
}
659
660
#[derive(Clone, Debug)]
661
pub struct HTTP2FramePushPromise {
662
    pub padlength: Option<u8>,
663
    pub reserved: u8,
664
    pub stream_id: u32,
665
    pub blocks: Vec<HTTP2FrameHeaderBlock>,
666
}
667
668
34.4k
pub fn http2_parse_frame_push_promise<'a>(
669
34.4k
    input: &'a [u8], flags: u8, dyn_headers: &mut HTTP2DynTable,
670
34.4k
) -> IResult<&'a [u8], HTTP2FramePushPromise> {
671
34.4k
    let (i2, padlength) = cond(flags & HTTP2_FLAG_HEADER_PADDED != 0, be_u8)(input)?;
672
31.9k
    let (i3, stream_id) = bits(tuple((take_bits(1u8), take_bits(31u32))))(i2)?;
673
30.2k
    let (i3, blocks) = http2_parse_headers_blocks(i3, dyn_headers)?;
674
21.6k
    return Ok((
675
21.6k
        i3,
676
21.6k
        HTTP2FramePushPromise {
677
21.6k
            padlength,
678
21.6k
            reserved: stream_id.0,
679
21.6k
            stream_id: stream_id.1,
680
21.6k
            blocks,
681
21.6k
        },
682
21.6k
    ));
683
34.4k
}
684
685
#[derive(Clone, Debug)]
686
pub struct HTTP2FrameContinuation {
687
    pub blocks: Vec<HTTP2FrameHeaderBlock>,
688
}
689
690
964k
pub fn http2_parse_frame_continuation<'a>(
691
964k
    input: &'a [u8], dyn_headers: &mut HTTP2DynTable,
692
964k
) -> IResult<&'a [u8], HTTP2FrameContinuation> {
693
964k
    let (i3, blocks) = http2_parse_headers_blocks(input, dyn_headers)?;
694
513k
    return Ok((i3, HTTP2FrameContinuation { blocks }));
695
964k
}
696
697
#[repr(u16)]
698
#[derive(Clone, Copy, PartialEq, Eq, FromPrimitive, Debug)]
699
pub enum HTTP2SettingsId {
700
    HeaderTableSize = 1,
701
    EnablePush = 2,
702
    MaxConcurrentStreams = 3,
703
    InitialWindowSize = 4,
704
    MaxFrameSize = 5,
705
    MaxHeaderListSize = 6,
706
    EnableConnectProtocol = 8, // rfc8441
707
    NoRfc7540Priorities = 9, // rfc9218
708
}
709
710
impl fmt::Display for HTTP2SettingsId {
711
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
712
0
        write!(f, "{:?}", self)
713
0
    }
714
}
715
716
impl std::str::FromStr for HTTP2SettingsId {
717
    type Err = String;
718
719
1.03k
    fn from_str(s: &str) -> Result<Self, Self::Err> {
720
1.03k
        let su = s.to_uppercase();
721
1.03k
        let su_slice: &str = &su;
722
1.03k
        match su_slice {
723
1.03k
            "SETTINGS_HEADER_TABLE_SIZE" => Ok(HTTP2SettingsId::HeaderTableSize),
724
217
            "SETTINGS_ENABLE_PUSH" => Ok(HTTP2SettingsId::EnablePush),
725
217
            "SETTINGS_MAX_CONCURRENT_STREAMS" => Ok(HTTP2SettingsId::MaxConcurrentStreams),
726
217
            "SETTINGS_INITIAL_WINDOW_SIZE" => Ok(HTTP2SettingsId::InitialWindowSize),
727
217
            "SETTINGS_MAX_FRAME_SIZE" => Ok(HTTP2SettingsId::MaxFrameSize),
728
215
            "SETTINGS_MAX_HEADER_LIST_SIZE" => Ok(HTTP2SettingsId::MaxHeaderListSize),
729
215
            "SETTINGS_ENABLE_CONNECT_PROTOCOL" => Ok(HTTP2SettingsId::EnableConnectProtocol),
730
215
            "SETTINGS_NO_RFC7540_PRIORITIES" => Ok(HTTP2SettingsId::NoRfc7540Priorities),
731
215
            _ => Err(format!("'{}' is not a valid value for HTTP2SettingsId", s)),
732
        }
733
1.03k
    }
734
}
735
736
pub struct DetectHTTP2settingsSigCtx {
737
    pub id: HTTP2SettingsId,                //identifier
738
    pub value: Option<DetectUintData<u32>>, //optional value
739
}
740
741
1.03k
pub fn http2_parse_settingsctx(i: &str) -> IResult<&str, DetectHTTP2settingsSigCtx> {
742
1.03k
    let (i, _) = opt(is_a(" "))(i)?;
743
1.03k
    let (i, id) = map_opt(alt((complete(is_not(" <>=")), rest)), |s: &str| {
744
1.03k
        HTTP2SettingsId::from_str(s).ok()
745
1.03k
    })(i)?;
746
824
    let (i, value) = opt(complete(detect_parse_uint))(i)?;
747
824
    Ok((i, DetectHTTP2settingsSigCtx { id, value }))
748
1.03k
}
749
750
#[derive(Clone, Copy, Debug)]
751
pub struct HTTP2FrameSettings {
752
    pub id: HTTP2SettingsId,
753
    pub value: u32,
754
}
755
756
106k
fn http2_parse_frame_setting(i: &[u8]) -> IResult<&[u8], HTTP2FrameSettings> {
757
106k
    let (i, id) = map_opt(be_u16, num::FromPrimitive::from_u16)(i)?;
758
69.2k
    let (i, value) = be_u32(i)?;
759
29.4k
    Ok((i, HTTP2FrameSettings { id, value }))
760
106k
}
761
762
77.0k
pub fn http2_parse_frame_settings(i: &[u8]) -> IResult<&[u8], Vec<HTTP2FrameSettings>> {
763
77.0k
    many0(complete(http2_parse_frame_setting))(i)
764
77.0k
}
765
766
0
pub fn doh_extract_request(i: &[u8]) -> IResult<&[u8], Vec<u8>> {
767
0
    let (i, _) = tag("/dns-query?dns=")(i)?;
768
0
    match STANDARD_NO_PAD.decode(i) {
769
0
        Ok(dec) => {
770
            // i is unused
771
0
            return Ok((i, dec));
772
        }
773
        _ => {
774
0
            return Err(Err::Error(make_error(i, ErrorKind::MapOpt)));
775
        }
776
    }
777
0
}
778
779
#[cfg(test)]
780
mod tests {
781
782
    use super::*;
783
    use crate::detect::uint::DetectUintMode;
784
785
    #[test]
786
    fn test_http2_parse_header() {
787
        let buf0: &[u8] = &[0x82];
788
        let mut dynh = HTTP2DynTable::new();
789
        let r0 = http2_parse_headers_block(buf0, &mut dynh);
790
        match r0 {
791
            Ok((remainder, hd)) => {
792
                // Check the first message.
793
                assert_eq!(hd.name, ":method".as_bytes().to_vec().into());
794
                assert_eq!(hd.value, "GET".as_bytes().to_vec().into());
795
                // And we should have no bytes left.
796
                assert_eq!(remainder.len(), 0);
797
            }
798
            Err(Err::Incomplete(_)) => {
799
                panic!("Result should not have been incomplete.");
800
            }
801
            Err(Err::Error(err)) | Err(Err::Failure(err)) => {
802
                panic!("Result should not be an error: {:?}.", err);
803
            }
804
        }
805
        let buf1: &[u8] = &[0x53, 0x03, 0x2A, 0x2F, 0x2A];
806
        let r1 = http2_parse_headers_block(buf1, &mut dynh);
807
        match r1 {
808
            Ok((remainder, hd)) => {
809
                // Check the first message.
810
                assert_eq!(hd.name, "accept".as_bytes().to_vec().into());
811
                assert_eq!(hd.value, "*/*".as_bytes().to_vec().into());
812
                // And we should have no bytes left.
813
                assert_eq!(remainder.len(), 0);
814
                assert_eq!(dynh.table.len(), 1);
815
            }
816
            Err(Err::Incomplete(_)) => {
817
                panic!("Result should not have been incomplete.");
818
            }
819
            Err(Err::Error(err)) | Err(Err::Failure(err)) => {
820
                panic!("Result should not be an error: {:?}.", err);
821
            }
822
        }
823
        let buf: &[u8] = &[
824
            0x41, 0x8a, 0xa0, 0xe4, 0x1d, 0x13, 0x9d, 0x09, 0xb8, 0xc8, 0x00, 0x0f,
825
        ];
826
        let result = http2_parse_headers_block(buf, &mut dynh);
827
        match result {
828
            Ok((remainder, hd)) => {
829
                // Check the first message.
830
                assert_eq!(hd.name, ":authority".as_bytes().to_vec().into());
831
                assert_eq!(hd.value, "localhost:3000".as_bytes().to_vec().into());
832
                // And we should have no bytes left.
833
                assert_eq!(remainder.len(), 0);
834
                assert_eq!(dynh.table.len(), 2);
835
            }
836
            Err(Err::Incomplete(_)) => {
837
                panic!("Result should not have been incomplete.");
838
            }
839
            Err(Err::Error(err)) | Err(Err::Failure(err)) => {
840
                panic!("Result should not be an error: {:?}.", err);
841
            }
842
        }
843
        let buf3: &[u8] = &[0xbe];
844
        let r3 = http2_parse_headers_block(buf3, &mut dynh);
845
        match r3 {
846
            Ok((remainder, hd)) => {
847
                // same as before
848
                assert_eq!(hd.name, ":authority".as_bytes().to_vec().into());
849
                assert_eq!(hd.value, "localhost:3000".as_bytes().to_vec().into());
850
                // And we should have no bytes left.
851
                assert_eq!(remainder.len(), 0);
852
                assert_eq!(dynh.table.len(), 2);
853
            }
854
            Err(Err::Incomplete(_)) => {
855
                panic!("Result should not have been incomplete.");
856
            }
857
            Err(Err::Error(err)) | Err(Err::Failure(err)) => {
858
                panic!("Result should not be an error: {:?}.", err);
859
            }
860
        }
861
        let buf4: &[u8] = &[0x80];
862
        let r4 = http2_parse_headers_block(buf4, &mut dynh);
863
        match r4 {
864
            Ok((remainder, hd)) => {
865
                assert_eq!(hd.error, HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeIndex0);
866
                assert_eq!(remainder.len(), 0);
867
                assert_eq!(dynh.table.len(), 2);
868
            }
869
            Err(Err::Incomplete(_)) => {
870
                panic!("Result should not have been incomplete.");
871
            }
872
            Err(Err::Error(err)) | Err(Err::Failure(err)) => {
873
                panic!("Result should not be an error: {:?}.", err);
874
            }
875
        }
876
        let buf2: &[u8] = &[
877
            0x04, 0x94, 0x62, 0x43, 0x91, 0x8a, 0x47, 0x55, 0xa3, 0xa1, 0x89, 0xd3, 0x4d, 0x0c,
878
            0x1a, 0xa9, 0x0b, 0xe5, 0x79, 0xd3, 0x4d, 0x1f,
879
        ];
880
        let r2 = http2_parse_headers_block(buf2, &mut dynh);
881
        match r2 {
882
            Ok((remainder, hd)) => {
883
                // Check the first message.
884
                assert_eq!(hd.name, ":path".as_bytes().to_vec().into());
885
                assert_eq!(hd.value, "/doc/manual/html/index.html".as_bytes().to_vec().into());
886
                // And we should have no bytes left.
887
                assert_eq!(remainder.len(), 0);
888
                assert_eq!(dynh.table.len(), 2);
889
            }
890
            Err(Err::Incomplete(_)) => {
891
                panic!("Result should not have been incomplete.");
892
            }
893
            Err(Err::Error(err)) | Err(Err::Failure(err)) => {
894
                panic!("Result should not be an error: {:?}.", err);
895
            }
896
        }
897
    }
898
899
    /// Simple test of some valid data.
900
    #[test]
901
    fn test_http2_parse_settingsctx() {
902
        let s = "SETTINGS_ENABLE_PUSH";
903
        let r = http2_parse_settingsctx(s);
904
        match r {
905
            Ok((rem, ctx)) => {
906
                assert_eq!(ctx.id, HTTP2SettingsId::EnablePush);
907
                assert!(ctx.value.is_none());
908
                assert_eq!(rem.len(), 0);
909
            }
910
            Err(e) => {
911
                panic!("Result should not be an error {:?}.", e);
912
            }
913
        }
914
915
        //spaces in the end
916
        let s1 = "SETTINGS_ENABLE_PUSH ";
917
        let r1 = http2_parse_settingsctx(s1);
918
        match r1 {
919
            Ok((rem, ctx)) => {
920
                assert_eq!(ctx.id, HTTP2SettingsId::EnablePush);
921
                if ctx.value.is_some() {
922
                    panic!("Unexpected value");
923
                }
924
                assert_eq!(rem.len(), 1);
925
            }
926
            Err(e) => {
927
                panic!("Result should not be an error {:?}.", e);
928
            }
929
        }
930
931
        let s2 = "SETTINGS_MAX_CONCURRENT_STREAMS  42";
932
        let r2 = http2_parse_settingsctx(s2);
933
        match r2 {
934
            Ok((rem, ctx)) => {
935
                assert_eq!(ctx.id, HTTP2SettingsId::MaxConcurrentStreams);
936
                match ctx.value {
937
                    Some(ctxval) => {
938
                        assert_eq!(ctxval.arg1, 42);
939
                    }
940
                    None => {
941
                        panic!("No value");
942
                    }
943
                }
944
                assert_eq!(rem.len(), 0);
945
            }
946
            Err(e) => {
947
                panic!("Result should not be an error {:?}.", e);
948
            }
949
        }
950
951
        let s3 = "SETTINGS_MAX_CONCURRENT_STREAMS 42-68";
952
        let r3 = http2_parse_settingsctx(s3);
953
        match r3 {
954
            Ok((rem, ctx)) => {
955
                assert_eq!(ctx.id, HTTP2SettingsId::MaxConcurrentStreams);
956
                match ctx.value {
957
                    Some(ctxval) => {
958
                        assert_eq!(ctxval.arg1, 42);
959
                        assert_eq!(ctxval.mode, DetectUintMode::DetectUintModeRange);
960
                        assert_eq!(ctxval.arg2, 68);
961
                    }
962
                    None => {
963
                        panic!("No value");
964
                    }
965
                }
966
                assert_eq!(rem.len(), 0);
967
            }
968
            Err(e) => {
969
                panic!("Result should not be an error {:?}.", e);
970
            }
971
        }
972
973
        let s4 = "SETTINGS_MAX_CONCURRENT_STREAMS<54";
974
        let r4 = http2_parse_settingsctx(s4);
975
        match r4 {
976
            Ok((rem, ctx)) => {
977
                assert_eq!(ctx.id, HTTP2SettingsId::MaxConcurrentStreams);
978
                match ctx.value {
979
                    Some(ctxval) => {
980
                        assert_eq!(ctxval.arg1, 54);
981
                        assert_eq!(ctxval.mode, DetectUintMode::DetectUintModeLt);
982
                    }
983
                    None => {
984
                        panic!("No value");
985
                    }
986
                }
987
                assert_eq!(rem.len(), 0);
988
            }
989
            Err(e) => {
990
                panic!("Result should not be an error {:?}.", e);
991
            }
992
        }
993
994
        let s5 = "SETTINGS_MAX_CONCURRENT_STREAMS > 76";
995
        let r5 = http2_parse_settingsctx(s5);
996
        match r5 {
997
            Ok((rem, ctx)) => {
998
                assert_eq!(ctx.id, HTTP2SettingsId::MaxConcurrentStreams);
999
                match ctx.value {
1000
                    Some(ctxval) => {
1001
                        assert_eq!(ctxval.arg1, 76);
1002
                        assert_eq!(ctxval.mode, DetectUintMode::DetectUintModeGt);
1003
                    }
1004
                    None => {
1005
                        panic!("No value");
1006
                    }
1007
                }
1008
                assert_eq!(rem.len(), 0);
1009
            }
1010
            Err(e) => {
1011
                panic!("Result should not be an error {:?}.", e);
1012
            }
1013
        }
1014
    }
1015
1016
    #[test]
1017
    fn test_http2_parse_headers_block_string() {
1018
        let buf: &[u8] = &[0x01, 0xFF];
1019
        let r = http2_parse_headers_block_string(buf);
1020
        match r {
1021
            Ok((remainder, _)) => {
1022
                assert_eq!(remainder.len(), 0);
1023
            }
1024
            Err(Err::Error(err)) | Err(Err::Failure(err)) => {
1025
                panic!("Result should not be an error: {:?}.", err);
1026
            }
1027
            _ => {
1028
                panic!("Result should have been ok");
1029
            }
1030
        }
1031
        let buf2: &[u8] = &[0x83, 0xFF, 0xFF, 0xEA];
1032
        let r2 = http2_parse_headers_block_string(buf2);
1033
        match r2 {
1034
            Ok((remainder, _)) => {
1035
                assert_eq!(remainder.len(), 0);
1036
            }
1037
            _ => {
1038
                panic!("Result should have been ok");
1039
            }
1040
        }
1041
    }
1042
1043
    #[test]
1044
    fn test_http2_parse_frame_header() {
1045
        let buf: &[u8] = &[
1046
            0x00, 0x00, 0x06, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1047
            0x64,
1048
        ];
1049
        let result = http2_parse_frame_header(buf);
1050
        match result {
1051
            Ok((remainder, frame)) => {
1052
                // Check the first message.
1053
                assert_eq!(frame.length, 6);
1054
                assert_eq!(frame.ftype, HTTP2FrameType::Settings as u8);
1055
                assert_eq!(frame.flags, 0);
1056
                assert_eq!(frame.reserved, 0);
1057
                assert_eq!(frame.stream_id, 0);
1058
1059
                // And we should have 6 bytes left.
1060
                assert_eq!(remainder.len(), 6);
1061
            }
1062
            Err(Err::Incomplete(_)) => {
1063
                panic!("Result should not have been incomplete.");
1064
            }
1065
            Err(Err::Error(err)) | Err(Err::Failure(err)) => {
1066
                panic!("Result should not be an error: {:?}.", err);
1067
            }
1068
        }
1069
    }
1070
}