Coverage Report

Created: 2026-09-28 07:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/rust/htp/src/connection_parser.rs
Line
Count
Source
1
use crate::{
2
    bstr::Bstr,
3
    config::Config,
4
    connection::{Connection, ConnectionFlags},
5
    decompressors::HtpContentEncoding,
6
    error::Result,
7
    hook::DataHook,
8
    log::Logger,
9
    transaction::{HtpRequestProgress, HtpResponseProgress, HtpTransferCoding, Transaction},
10
    transactions::Transactions,
11
    util::{FlagOperations, HtpFlags},
12
    HtpStatus,
13
};
14
use std::{any::Any, borrow::Cow, cell::Cell, net::IpAddr, time::SystemTime};
15
use time::OffsetDateTime;
16
17
/// Enumerates parsing state.
18
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
19
pub(crate) enum State {
20
    /// Default state.
21
    None,
22
    /// State once a transaction is processed or about to be processed.
23
    Idle,
24
    /// State for request/response line parsing.
25
    Line,
26
    /// State for header parsing.
27
    Headers,
28
    /// State for finalizing chunked body data parsing.
29
    BodyChunkedDataEnd,
30
    /// State for chunked body data.
31
    BodyChunkedData,
32
    /// Parse the chunked length state.
33
    BodyChunkedLength,
34
    /// State to determine encoding of body data.
35
    BodyDetermine,
36
    /// State for finalizing transaction side.
37
    Finalize,
38
    // Used by request_state only
39
    /// State for determining the request protocol.
40
    Protocol,
41
    /// State to determine if there is a CONNECT request.
42
    ConnectCheck,
43
    /// State to determine if inbound parsing needs to be suspended.
44
    ConnectProbeData,
45
    /// State to determine if inbound parsing can continue if it was suspended.
46
    ConnectWaitResponse,
47
    /// State to process request body data.
48
    BodyIdentity,
49
    /// State to consume remaining data in request buffer for the HTTP 0.9 case.
50
    IgnoreDataAfterHTTP09,
51
    // Used by response_state only
52
    /// State to consume response remaining body data when content-length is unknown.
53
    BodyIdentityStreamClose,
54
    /// State to consume response body data when content-length is known.
55
    BodyIdentityCLKnown,
56
}
57
58
/// Enumerates all stream states. Each connection has two streams, one
59
/// inbound and one outbound. Their states are tracked separately.
60
#[repr(C)]
61
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
62
pub enum HtpStreamState {
63
    /// Default stream state.
64
    NEW,
65
    /// State when connection is open.
66
    OPEN,
67
    /// State when connection is closed.
68
    CLOSED,
69
    /// State when stream produces a fatal error.
70
    ERROR,
71
    /// State for a tunnelled stream.
72
    TUNNEL,
73
    /// State when parsing is suspended and not consumed in order. This is to
74
    /// allow processing on another stream.
75
    DATA_OTHER,
76
    /// State when we should stop parsing the associated connection.
77
    STOP,
78
    /// State when all current data in the stream has been processed.
79
    DATA,
80
}
81
82
#[derive(Debug, Default, Clone)]
83
/// This structure is used to pass data (for example
84
/// request and response body buffers or gaps) to parsers.
85
pub(crate) struct ParserData<'a> {
86
    /// Ref to the data buffer.
87
    data: Option<Cow<'a, [u8]>>,
88
    // Length of data gap. Only set if is a gap.
89
    gap_len: Option<usize>,
90
    // Current position offset of the data to parse
91
    position: Cell<usize>,
92
    // Current callback data position
93
    callback_position: usize,
94
}
95
96
impl ParserData<'_> {
97
    /// Returns a pointer to the raw data associated with Data.
98
    /// This returns a pointer to the entire data chunk.
99
7.10M
    pub(crate) fn data_ptr(&self) -> *const u8 {
100
7.10M
        self.data()
101
7.10M
            .as_ref()
102
7.10M
            .map(|data| data.as_ptr())
103
7.10M
            .unwrap_or(std::ptr::null())
104
7.10M
    }
105
106
    /// Returns the unconsumed data
107
7.27M
    pub(crate) fn data(&self) -> Option<&[u8]> {
108
7.27M
        let data = self.data.as_ref()?;
109
7.27M
        if self.position.get() <= data.len() {
110
7.27M
            Some(&data[self.position.get()..])
111
        } else {
112
0
            None
113
        }
114
7.27M
    }
115
116
    /// Returns the length of the unconsumed data.
117
30.8M
    pub(crate) fn len(&self) -> usize {
118
30.8M
        if let Some(gap_len) = self.gap_len {
119
268
            if self.position.get() >= gap_len {
120
0
                0
121
            } else {
122
268
                gap_len - self.position.get()
123
            }
124
        } else {
125
30.8M
            self.as_slice().len()
126
        }
127
30.8M
    }
128
129
    /// Returns how much data has been consumed so far
130
13.8M
    fn consumed_len(&self) -> usize {
131
13.8M
        self.position.get()
132
13.8M
    }
133
134
    /// Return an immutable slice view of the unconsumed data.
135
48.6M
    pub(crate) fn as_slice(&self) -> &[u8] {
136
48.6M
        if let Some(data) = self.data.as_ref() {
137
47.8M
            if self.position.get() <= data.len() {
138
47.8M
                return &data[self.position.get()..];
139
0
            }
140
834k
        }
141
834k
        b""
142
48.6M
    }
143
144
    /// Determines if this chunk is a gap or not
145
20.0M
    pub(crate) fn is_gap(&self) -> bool {
146
20.0M
        self.gap_len.is_some()
147
20.0M
    }
148
149
    /// Determine whether there is no more data to consume.
150
4.51M
    pub(crate) fn is_empty(&self) -> bool {
151
4.51M
        self.len() == 0
152
4.51M
    }
153
154
    /// Set the position offset into the data for parsing
155
13.8M
    fn set_position(&self, position: usize) {
156
13.8M
        self.position.set(position);
157
13.8M
    }
158
159
    /// Advances the internal position where we are parsing
160
13.8M
    pub(crate) fn consume(&self, consumed: usize) {
161
13.8M
        self.set_position(self.position.get() + consumed);
162
13.8M
    }
163
164
    /// Decrements the internal position where we are parsing
165
20.4k
    fn unconsume(&self, unconsume: usize) {
166
20.4k
        if unconsume < self.position.get() {
167
17.3k
            self.set_position(self.position.get() - unconsume);
168
17.3k
        } else {
169
3.07k
            self.set_position(0);
170
3.07k
        }
171
20.4k
    }
172
173
    /// Make an owned version of this data.
174
    #[cfg(test)]
175
    pub(crate) fn into_owned(self) -> ParserData<'static> {
176
        ParserData {
177
            data: self.data.map(|d| Cow::Owned(d.into_owned())),
178
            gap_len: self.gap_len,
179
            position: self.position,
180
            callback_position: self.callback_position,
181
        }
182
    }
183
184
    /// Callback data is raw data buffer content that is passed to the
185
    /// application via the header and trailer data hooks.
186
    ///
187
    /// This function will return any data that has been consumed but not
188
    /// yet returned from this function.
189
2.19M
    pub(crate) fn callback_data(&mut self) -> &[u8] {
190
2.19M
        if let Some(data) = self.data.as_ref() {
191
2.17M
            if self.position.get() <= data.len() && self.callback_position <= self.position.get() {
192
2.17M
                let d = &data[self.callback_position..self.position.get()];
193
2.17M
                self.callback_position = self.position.get();
194
2.17M
                return d;
195
0
            }
196
23.2k
        }
197
23.2k
        b""
198
2.19M
    }
199
200
    /// Sets the callback start location to the current parsing location
201
451k
    pub(crate) fn reset_callback_start(&mut self) {
202
451k
        self.callback_position = self.position.get();
203
451k
    }
204
}
205
206
impl<'a> From<Option<&'a [u8]>> for ParserData<'a> {
207
5.76M
    fn from(data: Option<&'a [u8]>) -> Self {
208
5.76M
        ParserData {
209
5.76M
            data: data.map(Cow::Borrowed),
210
5.76M
            gap_len: None,
211
5.76M
            position: Cell::new(0),
212
5.76M
            callback_position: 0,
213
5.76M
        }
214
5.76M
    }
215
}
216
217
impl<'a> From<&'a [u8]> for ParserData<'a> {
218
3.94M
    fn from(data: &'a [u8]) -> Self {
219
3.94M
        ParserData {
220
3.94M
            data: Some(Cow::Borrowed(data)),
221
3.94M
            gap_len: None,
222
3.94M
            position: Cell::new(0),
223
3.94M
            callback_position: 0,
224
3.94M
        }
225
3.94M
    }
226
}
227
228
impl From<Vec<u8>> for ParserData<'static> {
229
0
    fn from(data: Vec<u8>) -> Self {
230
0
        ParserData {
231
0
            data: Some(Cow::Owned(data)),
232
0
            gap_len: None,
233
0
            position: Cell::new(0),
234
0
            callback_position: 0,
235
0
        }
236
0
    }
237
}
238
239
impl<'a> From<&'a Vec<u8>> for ParserData<'a> {
240
0
    fn from(data: &'a Vec<u8>) -> Self {
241
0
        ParserData {
242
0
            data: Some(Cow::Borrowed(data.as_slice())),
243
0
            gap_len: None,
244
0
            position: Cell::new(0),
245
0
            callback_position: 0,
246
0
        }
247
0
    }
248
}
249
250
impl From<usize> for ParserData<'_> {
251
105
    fn from(gap_len: usize) -> Self {
252
105
        ParserData {
253
105
            data: None,
254
105
            gap_len: Some(gap_len),
255
105
            position: Cell::new(0),
256
105
            callback_position: 0,
257
105
        }
258
105
    }
259
}
260
261
impl From<(*const u8, usize)> for ParserData<'_> {
262
1.74M
    fn from((data, len): (*const u8, usize)) -> Self {
263
1.74M
        if data.is_null() {
264
105
            if len > 0 {
265
105
                ParserData::from(len)
266
            } else {
267
0
                ParserData::from(b"".as_ref())
268
            }
269
        } else {
270
1.74M
            unsafe { ParserData::from(std::slice::from_raw_parts(data, len)) }
271
        }
272
1.74M
    }
273
}
274
275
/// Stores information about the parsing process and associated transactions.
276
pub struct ConnectionParser {
277
    // General fields
278
    /// The logger structure associated with this parser
279
    pub(crate) logger: Logger,
280
    /// A reference to the current parser configuration structure.
281
    pub(crate) cfg: &'static Config,
282
    /// The connection structure associated with this parser.
283
    pub(crate) conn: Connection,
284
    /// Opaque user data associated with this parser.
285
    pub(crate) user_data: Option<Box<dyn Any>>,
286
    // Request parser fields
287
    /// Parser inbound status. Starts as OK, but may turn into ERROR.
288
    pub(crate) request_status: HtpStreamState,
289
    /// Parser outbound status. Starts as OK, but may turn into ERROR.
290
    pub(crate) response_status: HtpStreamState,
291
    /// When true, this field indicates that there is unprocessed inbound data, and
292
    /// that the response parsing code should stop at the end of the current request
293
    /// in order to allow more requests to be produced.
294
    pub(crate) response_data_other_at_tx_end: bool,
295
    /// The time when the last request data chunk was received.
296
    pub(crate) request_timestamp: OffsetDateTime,
297
    /// How many bytes from the last input chunk have we consumed
298
    /// This is mostly used from callbacks, where the caller
299
    /// wants to know how far into the last chunk the parser is.
300
    pub(crate) request_bytes_consumed: usize,
301
    /// How many data chunks does the inbound connection stream consist of?
302
    pub(crate) request_chunk_count: usize,
303
    /// The index of the first chunk used in the current request.
304
    pub(crate) request_chunk_request_index: usize,
305
    /// Used to buffer a line of inbound data when buffering cannot be avoided.
306
    pub(crate) request_buf: Bstr,
307
    /// Stores the current value of a folded request header. Such headers span
308
    /// multiple lines, and are processed only when all data is available.
309
    pub(crate) request_header: Option<Bstr>,
310
    /// The request body length declared in a valid request header. The key here
311
    /// is "valid". This field will not be populated if the request contains both
312
    /// a Transfer-Encoding header and a Content-Length header.
313
    pub(crate) request_content_length: Option<u64>,
314
    /// Holds the remaining request body length that we expect to read. This
315
    /// field will be available only when the length of a request body is known
316
    /// in advance, i.e. when request headers contain a Content-Length header.
317
    pub(crate) request_body_data_left: Option<u64>,
318
    /// Holds the amount of data that needs to be read from the
319
    /// current data chunk. Only used with chunked request bodies.
320
    pub(crate) request_chunked_length: Option<u64>,
321
    /// Current request parser state.
322
    pub(crate) request_state: State,
323
    /// Previous request parser state. Used to detect state changes.
324
    pub(crate) request_state_previous: State,
325
    /// The hook that should be receiving raw connection data.
326
    pub(crate) request_data_receiver_hook: Option<DataHook>,
327
328
    // Response parser fields
329
    /// The time when the last response data chunk was received.
330
    pub(crate) response_timestamp: OffsetDateTime,
331
    /// How many bytes from the last input chunk have we consumed
332
    /// This is mostly used from callbacks, where the caller
333
    /// wants to know how far into the last chunk the parser is.
334
    pub(crate) response_bytes_consumed: usize,
335
    /// Used to buffer a line of outbound data when buffering cannot be avoided.
336
    pub(crate) response_buf: Bstr,
337
    /// Stores the current value of a folded response header. Such headers span
338
    /// multiple lines, and are processed only when all data is available.
339
    pub(crate) response_header: Option<Bstr>,
340
    /// The length of the current response body as presented in the
341
    /// Content-Length response header.
342
    pub(crate) response_content_length: Option<u64>,
343
    /// The remaining length of the current response body, if known. Set to None otherwise.
344
    pub(crate) response_body_data_left: Option<u64>,
345
    /// Holds the amount of data that needs to be read from the
346
    /// current response data chunk. Only used with chunked response bodies.
347
    pub(crate) response_chunked_length: Option<u64>,
348
    /// Current response parser state.
349
    pub(crate) response_state: State,
350
    /// Previous response parser state.
351
    pub(crate) response_state_previous: State,
352
    /// The hook that should be receiving raw connection data.
353
    pub(crate) response_data_receiver_hook: Option<DataHook>,
354
355
    /// Number of compression bombs seen.
356
    pub(crate) bombs: u8,
357
358
    /// Transactions processed by this parser
359
    transactions: Transactions,
360
}
361
362
impl std::fmt::Debug for ConnectionParser {
363
0
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
364
0
        f.debug_struct("ConnectionParser")
365
0
            .field("request_status", &self.request_status)
366
0
            .field("response_status", &self.response_status)
367
0
            .field("request_index", &self.request_index())
368
0
            .field("response_index", &self.response_index())
369
0
            .finish()
370
0
    }
371
}
372
373
impl ConnectionParser {
374
    /// Creates a new ConnectionParser with a preconfigured `Config` struct.
375
14.8k
    pub(crate) fn new(cfg: &'static Config) -> Self {
376
14.8k
        let conn = Connection::default();
377
14.8k
        let logger = Logger::new(conn.get_sender());
378
14.8k
        Self {
379
14.8k
            logger: logger.clone(),
380
14.8k
            cfg,
381
14.8k
            conn,
382
14.8k
            user_data: None,
383
14.8k
            request_status: HtpStreamState::NEW,
384
14.8k
            response_status: HtpStreamState::NEW,
385
14.8k
            response_data_other_at_tx_end: false,
386
14.8k
            request_timestamp: OffsetDateTime::from(SystemTime::now()),
387
14.8k
            request_bytes_consumed: 0,
388
14.8k
            request_chunk_count: 0,
389
14.8k
            request_chunk_request_index: 0,
390
14.8k
            request_buf: Bstr::new(),
391
14.8k
            request_header: None,
392
14.8k
            request_content_length: None,
393
14.8k
            request_body_data_left: None,
394
14.8k
            request_chunked_length: None,
395
14.8k
            request_state: State::Idle,
396
14.8k
            request_state_previous: State::None,
397
14.8k
            request_data_receiver_hook: None,
398
14.8k
            response_timestamp: OffsetDateTime::from(SystemTime::now()),
399
14.8k
            response_bytes_consumed: 0,
400
14.8k
            response_buf: Bstr::new(),
401
14.8k
            response_header: None,
402
14.8k
            response_content_length: None,
403
14.8k
            response_body_data_left: None,
404
14.8k
            response_chunked_length: None,
405
14.8k
            response_state: State::Idle,
406
14.8k
            response_state_previous: State::None,
407
14.8k
            response_data_receiver_hook: None,
408
14.8k
            bombs: 0,
409
14.8k
            transactions: Transactions::new(cfg, &logger),
410
14.8k
        }
411
14.8k
    }
412
413
    /// Get the current request transaction
414
2.40M
    pub(crate) fn request(&mut self) -> Option<&Transaction> {
415
2.40M
        self.transactions.request()
416
2.40M
    }
417
418
    /// Get the current request transaction
419
25.9M
    pub(crate) fn request_mut(&mut self) -> Option<&mut Transaction> {
420
25.9M
        self.transactions.request_mut()
421
25.9M
    }
422
423
    /// Get the current response transaction
424
2.31M
    pub(crate) fn response(&mut self) -> Option<&Transaction> {
425
2.31M
        self.transactions.response()
426
2.31M
    }
427
428
    /// Get the current response transaction
429
12.2M
    pub(crate) fn response_mut(&mut self) -> Option<&mut Transaction> {
430
12.2M
        self.transactions.response_mut()
431
12.2M
    }
432
433
    /// Advance to the next request
434
    /// Returns the next request transaction id
435
776k
    pub(crate) fn request_next(&mut self) -> usize {
436
        // Detect pipelining.
437
776k
        if self.transactions.request_index() > self.transactions.response_index() {
438
403k
            self.conn.flags.set(ConnectionFlags::PIPELINED)
439
372k
        }
440
776k
        self.transactions.request_next()
441
776k
    }
442
443
    /// Advance to the next response
444
    /// Returns the next response transaction id
445
379k
    pub(crate) fn response_next(&mut self) -> usize {
446
379k
        self.transactions.response_next()
447
379k
    }
448
449
    /// Get the index of the request transaction
450
1.74M
    pub(crate) fn request_index(&self) -> usize {
451
1.74M
        self.transactions.request_index()
452
1.74M
    }
453
454
    /// Get the index of the response transaction
455
868k
    pub(crate) fn response_index(&self) -> usize {
456
868k
        self.transactions.response_index()
457
868k
    }
458
459
    /// Get the number of transactions processed up to now
460
76.0M
    pub(crate) fn tx_size(&self) -> usize {
461
76.0M
        self.transactions.size()
462
76.0M
    }
463
464
    /// Get a specific transaction
465
6.35M
    pub(crate) fn tx(&self, index: usize) -> Option<&Transaction> {
466
6.35M
        self.transactions.get(index)
467
6.35M
    }
468
469
    /// Get a specific transaction by its index
470
132M
    pub(crate) fn tx_index(&mut self, index: usize) -> Option<&mut Transaction> {
471
132M
        self.transactions.get_index(index)
472
132M
    }
473
474
    /// Get a specific transaction
475
2.07M
    pub(crate) fn tx_mut(&mut self, index: usize) -> Option<&mut Transaction> {
476
2.07M
        self.transactions.get_mut(index)
477
2.07M
    }
478
479
    /// Handle the current state to be processed.
480
8.16M
    pub(crate) fn handle_request_state(&mut self, data: &mut ParserData) -> Result<()> {
481
8.16M
        match self.request_state {
482
0
            State::None => Err(HtpStatus::ERROR),
483
466k
            State::Idle => self.request_idle(data),
484
189k
            State::IgnoreDataAfterHTTP09 => self.request_ignore_data_after_http_0_9(data),
485
1.33M
            State::Line => self.request_line(data),
486
434k
            State::Protocol => self.request_protocol(data),
487
839k
            State::Headers => self.request_headers(data),
488
10.4k
            State::ConnectWaitResponse => self.request_connect_wait_response(),
489
422k
            State::ConnectCheck => self.request_connect_check(),
490
1.53k
            State::ConnectProbeData => self.request_connect_probe_data(data),
491
418k
            State::BodyDetermine => self.request_body_determine(),
492
0
            State::BodyChunkedData => self.request_body_chunked_data(data),
493
0
            State::BodyChunkedLength => self.request_body_chunked_length(data),
494
0
            State::BodyChunkedDataEnd => self.request_body_chunked_data_end(data),
495
0
            State::BodyIdentity => self.request_body_identity(data),
496
4.04M
            State::Finalize => self.request_finalize(data),
497
            // These are only used by response_state
498
0
            _ => Err(HtpStatus::ERROR),
499
        }
500
8.16M
    }
501
502
    /// Handle the current state to be processed.
503
5.15M
    pub(crate) fn handle_response_state(&mut self, data: &mut ParserData) -> Result<()> {
504
5.15M
        match self.response_state {
505
0
            State::None => Err(HtpStatus::ERROR),
506
754k
            State::Idle => self.response_idle(data),
507
3.13M
            State::Line => self.response_line(data),
508
102k
            State::Headers => self.response_headers(data),
509
18.4k
            State::BodyDetermine => self.response_body_determine(data),
510
0
            State::BodyChunkedData => self.response_body_chunked_data(data),
511
0
            State::BodyChunkedLength => self.response_body_chunked_length(data),
512
0
            State::BodyChunkedDataEnd => self.response_body_chunked_data_end(data),
513
967k
            State::Finalize => self.response_finalize(data),
514
172k
            State::BodyIdentityStreamClose => self.response_body_identity_stream_close(data),
515
16
            State::BodyIdentityCLKnown => self.response_body_identity_cl_known(data),
516
            // These are only used by request_state
517
0
            _ => Err(HtpStatus::ERROR),
518
        }
519
5.15M
    }
520
521
    /// Closes the connection associated with the supplied parser.
522
9.57k
    pub(crate) fn request_close(&mut self, timestamp: Option<OffsetDateTime>) {
523
        // Update internal flags
524
9.57k
        if self.request_status != HtpStreamState::ERROR {
525
9.47k
            self.request_status = HtpStreamState::CLOSED
526
95
        }
527
        // Call the parsers one last time, which will allow them
528
        // to process the events that depend on stream closure
529
9.57k
        self.request_data(ParserData::default(), timestamp);
530
9.57k
    }
531
532
    /// Closes the connection associated with the supplied parser.
533
3.64k
    pub(crate) fn close(&mut self, timestamp: Option<OffsetDateTime>) {
534
        // Close the underlying connection.
535
3.64k
        self.conn.close(timestamp);
536
        // Update internal flags
537
3.64k
        if self.request_status != HtpStreamState::ERROR {
538
3.63k
            self.request_status = HtpStreamState::CLOSED
539
14
        }
540
3.64k
        if self.response_status != HtpStreamState::ERROR {
541
3.61k
            self.response_status = HtpStreamState::CLOSED
542
28
        }
543
        // Call the parsers one last time, which will allow them
544
        // to process the events that depend on stream closure
545
3.64k
        self.request_data(ParserData::default(), timestamp);
546
3.64k
        self.response_data(ParserData::default(), timestamp);
547
3.64k
    }
548
549
    /// This function is most likely not used and/or not needed.
550
435k
    pub(crate) fn request_reset(&mut self) {
551
435k
        self.request_content_length = None;
552
435k
        self.request_body_data_left = None;
553
435k
        self.request_chunk_request_index = self.request_chunk_count;
554
435k
    }
555
556
    /// Returns the number of bytes consumed from the current data chunks so far.
557
866k
    pub(crate) fn request_data_consumed(&self) -> usize {
558
866k
        self.request_bytes_consumed
559
866k
    }
560
561
    /// Consume the given number of bytes from the ParserData and update
562
    /// the internal counter for how many bytes consumed so far.
563
9.86M
    pub(crate) fn request_data_consume(&mut self, input: &ParserData, consumed: usize) {
564
9.86M
        input.consume(consumed);
565
9.86M
        self.request_bytes_consumed = input.consumed_len();
566
9.86M
    }
567
568
    /// Unconsume the given number of bytes from the ParserData and update the
569
    /// the internal counter for how many bytes are consumed.
570
    /// If the requested number of bytes is larger than the number of bytes
571
    /// already consumed then the parser will be unwound to the beginning.
572
12.8k
    pub(crate) fn request_data_unconsume(&mut self, input: &mut ParserData, unconsume: usize) {
573
12.8k
        input.unconsume(unconsume);
574
12.8k
        self.request_bytes_consumed = input.consumed_len();
575
12.8k
    }
576
577
    /// Consume the given number of bytes from the ParserData and update
578
    /// the internal counter for how many bytes consumed so far.
579
4.00M
    pub(crate) fn response_data_consume(&mut self, input: &ParserData, consumed: usize) {
580
4.00M
        input.consume(consumed);
581
4.00M
        self.response_bytes_consumed = input.consumed_len();
582
4.00M
    }
583
584
    /// Unconsume the given number of bytes from the ParserData and update the
585
    /// the internal counter for how many bytes are consumed.
586
    /// If the requested number of bytes is larger than the number of bytes
587
    /// already consumed then the parser will be unwound to the beginning.
588
7.56k
    pub(crate) fn response_data_unconsume(&mut self, input: &mut ParserData, unconsume: usize) {
589
7.56k
        input.unconsume(unconsume);
590
7.56k
        self.response_bytes_consumed = input.consumed_len();
591
7.56k
    }
592
593
    /// Returns the number of bytes consumed from the most recent outbound data chunk. Normally, an invocation
594
    /// of response_data() will consume all data from the supplied buffer, but there are circumstances
595
    /// where only partial consumption is possible. In such cases DATA_OTHER will be returned.
596
    /// Consumed bytes are no longer necessary, but the remainder of the buffer will be saved
597
    /// for later.
598
763k
    pub(crate) fn response_data_consumed(&self) -> usize {
599
763k
        self.response_bytes_consumed
600
763k
    }
601
602
    /// Opens connection.
603
14.8k
    pub(crate) fn open(
604
14.8k
        &mut self, client_addr: Option<IpAddr>, client_port: Option<u16>,
605
14.8k
        server_addr: Option<IpAddr>, server_port: Option<u16>, timestamp: Option<OffsetDateTime>,
606
14.8k
    ) {
607
        // Check connection parser state first.
608
14.8k
        if self.request_status != HtpStreamState::NEW || self.response_status != HtpStreamState::NEW
609
        {
610
0
            htp_error!(
611
0
                self.logger,
612
0
                HtpLogCode::CONNECTION_ALREADY_OPEN,
613
0
                "Connection is already open"
614
0
            );
615
0
            return;
616
14.8k
        }
617
14.8k
        self.conn.open(
618
14.8k
            client_addr,
619
14.8k
            client_port,
620
14.8k
            server_addr,
621
14.8k
            server_port,
622
14.8k
            timestamp,
623
        );
624
14.8k
        self.request_status = HtpStreamState::OPEN;
625
14.8k
        self.response_status = HtpStreamState::OPEN;
626
14.8k
    }
627
628
    /// Set the user data.
629
14.8k
    pub(crate) fn set_user_data(&mut self, data: Box<dyn Any + 'static>) {
630
14.8k
        self.user_data = Some(data);
631
14.8k
    }
632
633
    /// Get a reference to the user data.
634
8.24M
    pub(crate) fn user_data<T: 'static>(&self) -> Option<&T> {
635
8.24M
        self.user_data
636
8.24M
            .as_ref()
637
8.24M
            .and_then(|ud| ud.downcast_ref::<T>())
638
8.24M
    }
639
640
    /// Initialize request parsing, change state to LINE,
641
    /// and invoke all registered callbacks.
642
    ///
643
    /// Returns HtpStatus::OK on success; HtpStatus::ERROR on error, HtpStatus::STOP if one of the
644
    /// callbacks does not want to follow the transaction any more.
645
435k
    pub(crate) fn state_request_start(&mut self) -> Result<()> {
646
        // Change state into request line parsing.
647
435k
        self.request_state = State::Line;
648
435k
        let req = self.request_mut();
649
435k
        if req.is_none() {
650
125
            return Err(HtpStatus::ERROR);
651
435k
        }
652
435k
        req.unwrap().request_progress = HtpRequestProgress::LINE;
653
        // Run hook REQUEST_START.
654
435k
        self.cfg
655
435k
            .hook_request_start
656
435k
            .clone()
657
435k
            .run_all(self, self.request_index())?;
658
435k
        Ok(())
659
435k
    }
660
661
    /// Change transaction state to HEADERS and invoke all
662
    /// registered callbacks.
663
    ///
664
    /// Returns HtpStatus::OK on success; HtpStatus::ERROR on error, HtpStatus::STOP if one of the
665
    /// callbacks does not want to follow the transaction any more.
666
430k
    pub(crate) fn state_request_headers(&mut self, input: &mut ParserData) -> Result<()> {
667
        // Finalize sending raw header data
668
430k
        self.request_receiver_finalize_clear(input)?;
669
        // If we're in HTP_REQ_HEADERS that means that this is the
670
        // first time we're processing headers in a request. Otherwise,
671
        // we're dealing with trailing headers.
672
430k
        let req = self.request();
673
430k
        if req.is_none() {
674
0
            return Err(HtpStatus::ERROR);
675
430k
        }
676
430k
        let request_progress = req.unwrap().request_progress;
677
430k
        if request_progress > HtpRequestProgress::HEADERS {
678
            // Request trailers.
679
            // Run hook HTP_REQUEST_TRAILER.
680
8.17k
            self.cfg
681
8.17k
                .hook_request_trailer
682
8.17k
                .clone()
683
8.17k
                .run_all(self, self.request_index())?;
684
            // Completed parsing this request; finalize it now.
685
8.17k
            self.request_state = State::Finalize;
686
422k
        } else if request_progress >= HtpRequestProgress::LINE {
687
            // Request headers.
688
            // Did this request arrive in multiple data chunks?
689
422k
            let req = self.transactions.request_mut().unwrap();
690
422k
            if self.request_chunk_count != self.request_chunk_request_index {
691
43.1k
                req.flags.set(HtpFlags::MULTI_PACKET_HEAD)
692
379k
            }
693
422k
            req.process_request_headers()?;
694
            // Run hook REQUEST_HEADERS.
695
            #[cfg(test)]
696
            self.cfg
697
                .hook_request_headers
698
                .clone()
699
                .run_all(self, self.request_index())?;
700
422k
            self.request_initialize_decompressors()?;
701
702
            // We still proceed if the request is invalid.
703
422k
            self.request_state = State::ConnectCheck;
704
        } else {
705
29
            htp_warn!(
706
29
                self.logger,
707
29
                HtpLogCode::RESPONSE_BODY_INTERNAL_ERROR,
708
29
                format!(
709
29
                    "[Internal Error] Invalid tx progress: {:?}",
710
29
                    request_progress
711
29
                )
712
29
            );
713
29
            return Err(HtpStatus::ERROR);
714
        }
715
430k
        Ok(())
716
430k
    }
717
718
    /// Change transaction state to PROTOCOL and invoke all
719
    /// registered callbacks.
720
    ///
721
    /// Returns HtpStatus::OK on success; HtpStatus::ERROR on error, HtpStatus::STOP if one of the
722
    /// callbacks does not want to follow the transaction any more.
723
434k
    pub(crate) fn state_request_line(&mut self) -> Result<()> {
724
434k
        let req = self.request_mut();
725
434k
        if req.is_none() {
726
0
            return Err(HtpStatus::ERROR);
727
434k
        }
728
434k
        req.unwrap().parse_request_line()?;
729
        // Run hook REQUEST_LINE.
730
434k
        self.cfg
731
434k
            .hook_request_line
732
434k
            .clone()
733
434k
            .run_all(self, self.request_index())?;
734
434k
        let logger = self.logger.clone();
735
434k
        let req = self.request_mut().unwrap();
736
434k
        if let Some(parsed_uri) = req.parsed_uri.as_mut() {
737
434k
            let (partial_normalized_uri, complete_normalized_uri) =
738
434k
                parsed_uri.generate_normalized_uri(Some(logger));
739
434k
            req.partial_normalized_uri = partial_normalized_uri;
740
434k
            req.complete_normalized_uri = complete_normalized_uri;
741
434k
        }
742
        // Move on to the next phase.
743
434k
        self.request_state = State::Protocol;
744
434k
        Ok(())
745
434k
    }
746
747
    /// Advance state after processing request headers.
748
    ///
749
    /// Returns HtpStatus::OK on success; HtpStatus::ERROR on error, HtpStatus::STOP
750
    /// if one of the callbacks does not want to follow the transaction any more.
751
433k
    pub(crate) fn state_request_complete(&mut self, input: &mut ParserData) -> Result<()> {
752
433k
        let req = self.request_mut();
753
433k
        if req.is_none() {
754
0
            return Err(HtpStatus::ERROR);
755
433k
        }
756
433k
        let req = req.unwrap();
757
433k
        if req.request_progress != HtpRequestProgress::COMPLETE {
758
            // Finalize request body.
759
431k
            if req.request_has_body() {
760
0
                self.request_body_data(None)?;
761
431k
            }
762
431k
            self.request_mut().unwrap().request_progress = HtpRequestProgress::COMPLETE;
763
            // Run hook REQUEST_COMPLETE.
764
431k
            self.cfg
765
431k
                .hook_request_complete
766
431k
                .clone()
767
431k
                .run_all(self, self.request_index())?;
768
769
            // Clear request data
770
431k
            self.request_receiver_finalize_clear(input)?;
771
2.37k
        }
772
        // Determine what happens next, and remove this transaction from the parser.
773
433k
        self.request_state = if self.request().unwrap().is_protocol_0_9 {
774
3.70k
            State::IgnoreDataAfterHTTP09
775
        } else {
776
430k
            State::Idle
777
        };
778
        // Check if the entire transaction is complete.
779
433k
        self.finalize(self.request_index())?;
780
433k
        self.request_next();
781
433k
        Ok(())
782
433k
    }
783
784
    /// Determine if the transaction is complete and run any hooks.
785
813k
    fn finalize(&mut self, _tx_index: usize) -> Result<()> {
786
        #[cfg(test)]
787
        if let Some(tx) = self.tx(_tx_index) {
788
            if !tx.is_complete() {
789
                return Ok(());
790
            }
791
            // Disconnect transaction from the parser.
792
            // Run hook TRANSACTION_COMPLETE.
793
            self.cfg
794
                .hook_transaction_complete
795
                .clone()
796
                .run_all(self, _tx_index)?;
797
        }
798
813k
        Ok(())
799
813k
    }
800
801
    /// Advance state to LINE, or BODY if http version is 0.9.
802
    ///
803
    /// Returns HtpStatus::OK on success; HtpStatus::ERROR on error, HtpStatus::STOP
804
    /// if one of the callbacks does not want to follow the transaction any more.
805
382k
    pub(crate) fn state_response_start(&mut self) -> Result<()> {
806
        // Change state into response line parsing, except if we're following
807
        // a HTTP/0.9 request (no status line or response headers).
808
382k
        let tx = self.response_mut();
809
382k
        if tx.is_none() {
810
0
            return Err(HtpStatus::ERROR);
811
382k
        }
812
382k
        let tx = tx.unwrap();
813
814
382k
        if tx.is_protocol_0_9 {
815
103
            tx.response_transfer_coding = HtpTransferCoding::Identity;
816
103
            tx.response_content_encoding_processing = HtpContentEncoding::None;
817
103
            tx.response_progress = HtpResponseProgress::BODY;
818
103
            self.response_state = State::BodyIdentityStreamClose;
819
103
            self.response_body_data_left = None
820
        } else {
821
382k
            tx.response_progress = HtpResponseProgress::LINE;
822
382k
            self.response_state = State::Line
823
        }
824
        // Run hook RESPONSE_START.
825
382k
        self.cfg
826
382k
            .hook_response_start
827
382k
            .clone()
828
382k
            .run_all(self, self.response_index())?;
829
        // If at this point we have no method and no uri and our status
830
        // is still REQ_LINE, we likely have timed out request
831
        // or a overly long request
832
382k
        let tx = self.response_mut().unwrap();
833
382k
        if tx.request_method.is_none()
834
346k
            && tx.request_uri.is_none()
835
3.48k
            && self.request_state == State::Line
836
3.48k
        {
837
3.48k
            htp_warn!(
838
3.48k
                self.logger,
839
3.48k
                HtpLogCode::REQUEST_LINE_INCOMPLETE,
840
3.48k
                "Request line incomplete"
841
3.48k
            );
842
379k
        }
843
382k
        Ok(())
844
382k
    }
845
846
    /// Advance state after processing response headers.
847
    ///
848
    /// Returns HtpStatus::OK on success; HtpStatus::ERROR on error, HtpStatus::STOP
849
    /// if one of the callbacks does not want to follow the transaction any more.
850
16.6k
    pub(crate) fn state_response_headers(&mut self, input: &mut ParserData) -> Result<()> {
851
        // Finalize sending raw header data.
852
16.6k
        self.response_receiver_finalize_clear(input)?;
853
        // Run hook RESPONSE_HEADERS.
854
        #[cfg(test)]
855
        self.cfg
856
            .hook_response_headers
857
            .clone()
858
            .run_all(self, self.response_index())?;
859
16.6k
        self.response_initialize_decompressors()
860
16.6k
    }
861
862
    /// Change transaction state to RESPONSE_LINE and invoke registered callbacks.
863
    ///
864
    /// Returns HtpStatus::OK on success; HtpStatus::ERROR on error, HtpStatus::STOP
865
    /// if one of the callbacks does not want to follow the transaction any more.
866
19.9k
    pub(crate) fn state_response_line(&mut self) -> Result<()> {
867
        // Is the response line valid?
868
19.9k
        let tx = self.response_mut();
869
19.9k
        if tx.is_none() {
870
0
            return Err(HtpStatus::ERROR);
871
19.9k
        }
872
19.9k
        let tx = tx.unwrap();
873
874
19.9k
        tx.validate_response_line();
875
        #[cfg(test)]
876
        let index = tx.index;
877
        // Run hook HTP_RESPONSE_LINE
878
        #[cfg(test)]
879
        return self.cfg.hook_response_line.clone().run_all(self, index);
880
        #[cfg(not(test))]
881
19.9k
        return Ok(());
882
19.9k
    }
883
884
    /// Change transaction state to COMPLETE and invoke registered callbacks.
885
    ///
886
    /// Returns HtpStatus::OK on success; HtpStatus::ERROR on error, HtpStatus::STOP
887
    /// if one of the callbacks does not want to follow the transaction any more.
888
381k
    pub(crate) fn state_response_complete(&mut self, input: &mut ParserData) -> Result<()> {
889
381k
        let response_index = self.response_index();
890
381k
        let tx = self.response_mut();
891
381k
        if tx.is_none() {
892
0
            return Err(HtpStatus::ERROR);
893
381k
        }
894
381k
        let tx = tx.unwrap();
895
381k
        if tx.response_progress != HtpResponseProgress::COMPLETE {
896
380k
            tx.response_progress = HtpResponseProgress::COMPLETE;
897
            // Run the last RESPONSE_BODY_DATA HOOK, but only if there was a response body present.
898
380k
            if tx.response_transfer_coding != HtpTransferCoding::NoBody {
899
366k
                let _ = self.response_body_data(None);
900
366k
            }
901
            // Run hook RESPONSE_COMPLETE.
902
380k
            self.cfg
903
380k
                .hook_response_complete
904
380k
                .clone()
905
380k
                .run_all(self, response_index)?;
906
907
            // Clear the data receivers hook if any
908
380k
            self.response_receiver_finalize_clear(input)?;
909
694
        }
910
        // Check if we want to signal the caller to send request data
911
381k
        self.request_parser_check_waiting()?;
912
        // Otherwise finalize the transaction
913
379k
        self.finalize(response_index)?;
914
379k
        self.response_next();
915
379k
        self.response_state = State::Idle;
916
379k
        Ok(())
917
381k
    }
918
919
    /// Check if we had previously signalled the caller to give us response
920
    /// data, and now we are ready to receive it
921
381k
    fn request_parser_check_waiting(&mut self) -> Result<()> {
922
        // Check if the inbound parser is waiting on us. If it is, that means that
923
        // there might be request data that the inbound parser hasn't consumed yet.
924
        // If we don't stop parsing we might encounter a response without a request,
925
        // which is why we want to return straight away before processing any data.
926
        //
927
        // This situation will occur any time the parser needs to see the server
928
        // respond to a particular situation before it can decide how to proceed. For
929
        // example, when a CONNECT is sent, different paths are used when it is accepted
930
        // and when it is not accepted.
931
        //
932
        // It is not enough to check only in_status here. Because of pipelining, it's possible
933
        // that many inbound transactions have been processed, and that the parser is
934
        // waiting on a response that we have not seen yet.
935
381k
        if self.response_status == HtpStreamState::DATA_OTHER
936
5
            && self.response_index() == self.request_index()
937
        {
938
5
            return Err(HtpStatus::DATA_OTHER);
939
381k
        }
940
941
        // Do we have a signal to yield to inbound processing at
942
        // the end of the next transaction?
943
381k
        if self.response_data_other_at_tx_end {
944
            // We do. Let's yield then.
945
2.05k
            self.response_data_other_at_tx_end = false;
946
2.05k
            if self.response_index() == self.request_index() {
947
1.72k
                return Err(HtpStatus::DATA_OTHER);
948
331
            }
949
379k
        }
950
379k
        Ok(())
951
381k
    }
952
953
    /// Remove the given transaction from the parser
954
354k
    pub(crate) fn remove_tx(&mut self, tx_id: usize) {
955
354k
        self.transactions.remove(tx_id);
956
354k
    }
957
}