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/response.rs
Line
Count
Source
1
use crate::{
2
    bstr::Bstr,
3
    connection_parser::{ConnectionParser, HtpStreamState, ParserData, State},
4
    decompressors::{Decompressor, HtpContentEncoding},
5
    error::Result,
6
    headers::HeaderFlags,
7
    hook::DataHook,
8
    parsers::{parse_chunked_length, parse_content_length, parse_protocol, parse_status},
9
    request::HtpMethod,
10
    transaction::{
11
        Data, Header, HtpProtocol, HtpRequestProgress, HtpResponseNumber, HtpResponseProgress,
12
        HtpTransferCoding,
13
    },
14
    uri::Uri,
15
    util::{
16
        chomp, is_chunked_ctl_line, is_line_ignorable, is_space, is_valid_chunked_length_data,
17
        take_ascii_whitespace, take_is_space, take_is_space_or_null, take_not_is_space,
18
        take_till_eol, take_till_lf, treat_response_line_as_body, FlagOperations, HtpFlags,
19
    },
20
    HtpStatus,
21
};
22
use nom::{bytes::streaming::take_till as streaming_take_till, error::ErrorKind, sequence::tuple};
23
use std::{
24
    cmp::{min, Ordering},
25
    mem::take,
26
};
27
use time::OffsetDateTime;
28
29
impl ConnectionParser {
30
    /// Sends outstanding connection data to the currently active data receiver hook.
31
954k
    fn response_receiver_send_data(&mut self, data: &mut ParserData) -> Result<()> {
32
954k
        let data = ParserData::from(data.callback_data());
33
954k
        let resp = self.response_mut();
34
954k
        if resp.is_none() {
35
13
            return Err(HtpStatus::ERROR);
36
954k
        }
37
954k
        let mut tx_data = Data::new(resp.unwrap(), &data);
38
954k
        if let Some(hook) = &self.response_data_receiver_hook {
39
105k
            hook.run_all(self, &mut tx_data)?;
40
        } else {
41
848k
            return Ok(());
42
        };
43
105k
        Ok(())
44
954k
    }
45
46
    /// Finalizes an existing data receiver hook by sending any outstanding data to it. The
47
    /// hook is then removed so that it receives no more data.
48
398k
    pub(crate) fn response_receiver_finalize_clear(
49
398k
        &mut self, input: &mut ParserData,
50
398k
    ) -> Result<()> {
51
398k
        if self.response_data_receiver_hook.is_none() {
52
379k
            return Ok(());
53
18.5k
        }
54
18.5k
        let rc = self.response_receiver_send_data(input);
55
18.5k
        self.response_data_receiver_hook = None;
56
18.5k
        rc
57
398k
    }
58
59
    /// Configures the data receiver hook.
60
19.9k
    fn response_receiver_set(&mut self, data_receiver_hook: Option<DataHook>) -> Result<()> {
61
19.9k
        self.response_data_receiver_hook = data_receiver_hook;
62
19.9k
        Ok(())
63
19.9k
    }
64
65
    /// Handles response parser state changes. At the moment, this function is used only
66
    /// to configure data receivers, which are sent raw connection data.
67
4.21M
    fn response_handle_state_change(&mut self, input: &mut ParserData) -> Result<()> {
68
4.21M
        if self.response_state_previous == self.response_state {
69
3.03M
            return Ok(());
70
1.18M
        }
71
72
1.18M
        if self.response_state == State::Headers {
73
19.9k
            let resp = self.response_mut();
74
19.9k
            if resp.is_none() {
75
0
                return Err(HtpStatus::ERROR);
76
19.9k
            }
77
19.9k
            let resp = resp.unwrap();
78
19.9k
            let header_fn = Some(resp.cfg.hook_response_header_data.clone());
79
19.9k
            let trailer_fn = Some(resp.cfg.hook_response_trailer_data.clone());
80
19.9k
            input.reset_callback_start();
81
82
19.9k
            match resp.response_progress {
83
19.9k
                HtpResponseProgress::HEADERS => self.response_receiver_set(header_fn),
84
0
                HtpResponseProgress::TRAILER => self.response_receiver_set(trailer_fn),
85
0
                _ => Ok(()),
86
0
            }?;
87
1.16M
        }
88
        // Same comment as in request_handle_state_change(). Below is a copy.
89
        // Initially, I had the finalization of raw data sending here, but that
90
        // caused the last REQUEST_HEADER_DATA hook to be invoked after the
91
        // REQUEST_HEADERS hook -- which I thought made no sense. For that reason,
92
        // the finalization is now initiated from the request header processing code,
93
        // which is less elegant but provides a better user experience. Having some
94
        // (or all) hooks to be invoked on state change might work better.
95
1.18M
        self.response_state_previous = self.response_state;
96
1.18M
        Ok(())
97
4.21M
    }
98
99
    /// The maximum amount accepted for buffering is controlled
100
    /// by htp_config_t::field_limit.
101
3.28M
    fn check_response_buffer_limit(&mut self, len: usize) -> Result<()> {
102
3.28M
        if len == 0 {
103
10.7k
            return Ok(());
104
3.27M
        }
105
        // Check the hard (buffering) limit.
106
3.27M
        let mut newlen: usize = self.response_buf.len().wrapping_add(len);
107
        // When calculating the size of the buffer, take into account the
108
        // space we're using for the response header buffer.
109
3.27M
        if let Some(response_header) = &self.response_header {
110
81.9k
            newlen = newlen.wrapping_add(response_header.len());
111
3.19M
        }
112
3.27M
        let field_limit = self.cfg.field_limit;
113
3.27M
        if newlen > field_limit {
114
77
            htp_error!(
115
77
                self.logger,
116
77
                HtpLogCode::RESPONSE_FIELD_TOO_LONG,
117
77
                format!(
118
77
                    "Response the buffer limit: size {} limit {}.",
119
77
                    newlen, field_limit
120
77
                )
121
77
            );
122
77
            return Err(HtpStatus::ERROR);
123
3.27M
        }
124
3.27M
        Ok(())
125
3.28M
    }
126
127
    /// Consumes bytes until the end of the current line.
128
    ///
129
    /// Returns HtpStatus::OK on state change, HtpStatus::Error on error, or HtpStatus::DATA
130
    /// when more data is needed.
131
0
    pub(crate) fn response_body_chunked_data_end(&mut self, input: &ParserData) -> Result<()> {
132
        // TODO We shouldn't really see anything apart from CR and LF,
133
        //      so we should warn about anything else.
134
0
        let resp = self.response_mut();
135
0
        if resp.is_none() {
136
0
            return Err(HtpStatus::ERROR);
137
0
        }
138
0
        let resp = resp.unwrap();
139
140
0
        if let Ok((_, line)) = take_till_lf(input.as_slice()) {
141
0
            let len = line.len();
142
0
            self.response_data_consume(input, len);
143
0
            let resp = self.response_mut().unwrap();
144
0
            resp.response_message_len = resp.response_message_len.wrapping_add(len as u64);
145
0
            self.response_state = State::BodyChunkedLength;
146
0
            Ok(())
147
        } else {
148
            // Advance to end. Dont need to buffer
149
0
            resp.response_message_len = resp.response_message_len.wrapping_add(input.len() as u64);
150
0
            self.response_data_consume(input, input.len());
151
0
            Err(HtpStatus::DATA_BUFFER)
152
        }
153
0
    }
154
155
    /// Processes a chunk of data.
156
    ///
157
    /// Returns HtpStatus::OK on state change, HtpStatus::Error on error, or
158
    /// HtpStatus::DATA when more data is needed.
159
0
    pub(crate) fn response_body_chunked_data(&mut self, input: &ParserData) -> Result<()> {
160
0
        if self.response_status == HtpStreamState::CLOSED {
161
0
            self.response_state = State::Finalize;
162
            // Sends close signal to decompressors
163
0
            return self.response_body_data(input.data());
164
0
        }
165
0
        let bytes_to_consume = min(
166
0
            input.len(),
167
0
            self.response_chunked_length.unwrap_or(0) as usize,
168
        );
169
0
        if bytes_to_consume == 0 {
170
0
            return Err(HtpStatus::DATA);
171
0
        }
172
        // Consume the data.
173
0
        self.response_body_data(Some(&input.as_slice()[0..bytes_to_consume]))?;
174
        // Adjust the counters.
175
0
        self.response_data_consume(input, bytes_to_consume);
176
0
        if let Some(len) = &mut self.response_chunked_length {
177
0
            *len -= bytes_to_consume as u64;
178
            // Have we seen the entire chunk?
179
0
            if *len == 0 {
180
0
                self.response_state = State::BodyChunkedDataEnd;
181
0
                return Ok(());
182
0
            }
183
0
        }
184
185
0
        Err(HtpStatus::DATA)
186
0
    }
187
188
    /// Extracts chunk length.
189
    ///
190
    /// Returns Ok(()) on success, Err(HTP_ERROR) on error, or Err(HTP_DATA) when more data is needed.
191
0
    pub(crate) fn response_body_chunked_length(&mut self, input: &mut ParserData) -> Result<()> {
192
0
        let mut data = input.as_slice();
193
        loop {
194
0
            let buf_empty = self.response_buf.is_empty();
195
0
            let resp = self.response_mut();
196
0
            if resp.is_none() {
197
0
                return Err(HtpStatus::ERROR);
198
0
            }
199
0
            let resp = resp.unwrap();
200
201
0
            match take_till_lf(data) {
202
0
                Ok((remaining, line)) => {
203
0
                    self.response_data_consume(input, line.len());
204
0
                    if !buf_empty {
205
0
                        self.check_response_buffer_limit(line.len())?;
206
0
                    }
207
0
                    let mut data2 = take(&mut self.response_buf);
208
0
                    data2.add(line);
209
0
                    if is_chunked_ctl_line(&data2) {
210
0
                        let resp = self.response_mut().unwrap();
211
0
                        resp.response_message_len =
212
0
                            (resp.response_message_len).wrapping_add(data2.len() as u64);
213
                        //Empty chunk len. Try to continue parsing.
214
0
                        data = remaining;
215
0
                        continue;
216
0
                    }
217
0
                    let resp = self.response_mut().unwrap();
218
0
                    resp.response_message_len =
219
0
                        (resp.response_message_len).wrapping_add(data2.len() as u64);
220
221
0
                    match parse_chunked_length(&data2) {
222
0
                        Ok((len, ext)) => {
223
0
                            self.response_chunked_length = len;
224
0
                            if ext {
225
0
                                let mut flags = 0; // unused but needed by macro
226
0
                                htp_warn_once!(
227
0
                                    self.logger,
228
0
                                    HtpLogCode::RESPONSE_CHUNK_EXTENSION,
229
0
                                    "Response chunk extension",
230
0
                                    self.response_mut().unwrap().flags,
231
0
                                    flags,
232
                                    HtpFlags::FIELD_RESP_CHUNK_EXTENSION
233
                                );
234
0
                            }
235
                            // Handle chunk length
236
0
                            if let Some(len) = len {
237
0
                                match len.cmp(&0) {
238
                                    Ordering::Equal => {
239
                                        // End of data
240
0
                                        self.response_state = State::Headers;
241
0
                                        self.response_mut().unwrap().response_progress =
242
0
                                            HtpResponseProgress::TRAILER
243
                                    }
244
                                    Ordering::Greater => {
245
                                        // More data available.
246
0
                                        self.response_state = State::BodyChunkedData
247
                                    }
248
0
                                    _ => {}
249
                                }
250
                            } else {
251
0
                                return Ok(()); // empty chunk length line, lets try to continue
252
                            }
253
                        }
254
0
                        Err(_) => {
255
0
                            // unconsume so response_body_identity_stream_close doesn't miss the first bytes
256
0
                            self.response_data_unconsume(input, line.len());
257
0
                            self.response_state = State::BodyIdentityStreamClose;
258
0
                            self.response_mut().unwrap().response_transfer_coding =
259
0
                                HtpTransferCoding::Identity;
260
0
                            htp_error!(
261
0
                                self.logger,
262
0
                                HtpLogCode::INVALID_RESPONSE_CHUNK_LEN,
263
0
                                "Response chunk encoding: Invalid chunk length"
264
0
                            );
265
0
                        }
266
                    }
267
268
0
                    return Ok(());
269
                }
270
                _ => {
271
                    // Check if the data we have seen so far is invalid
272
0
                    if buf_empty && !is_valid_chunked_length_data(data) {
273
                        // Contains leading junk non hex_ascii data
274
0
                        resp.response_transfer_coding = HtpTransferCoding::Identity;
275
0
                        self.response_state = State::BodyIdentityStreamClose;
276
0
                        htp_error!(
277
0
                            self.logger,
278
0
                            HtpLogCode::INVALID_RESPONSE_CHUNK_LEN,
279
0
                            "Response chunk encoding: Invalid chunk length"
280
0
                        );
281
0
                        return Ok(());
282
                    } else {
283
0
                        return self.handle_response_absent_lf(input);
284
                    }
285
                }
286
            }
287
        }
288
0
    }
289
290
    /// Processes an identity response body of known length.
291
    ///
292
    /// Returns HtpStatus::OK on state change, HtpStatus::ERROR on error, or
293
    /// HtpStatus::DATA when more data is needed.
294
16
    pub(crate) fn response_body_identity_cl_known(&mut self, data: &mut ParserData) -> Result<()> {
295
16
        if self.response_status == HtpStreamState::CLOSED {
296
0
            self.response_state = State::Finalize;
297
            // Sends close signal to decompressors
298
0
            return self.response_body_data(data.data());
299
16
        }
300
16
        let left = self.response_body_data_left.ok_or(HtpStatus::ERROR)?;
301
16
        let bytes_to_consume = std::cmp::min(data.len() as u64, left);
302
16
        if bytes_to_consume == 0 {
303
8
            return Err(HtpStatus::DATA);
304
8
        }
305
8
        if data.is_gap() {
306
0
            let resp = self.response_mut();
307
0
            if resp.is_none() {
308
0
                return Err(HtpStatus::ERROR);
309
0
            }
310
0
            let resp = resp.unwrap();
311
312
0
            if resp.response_content_encoding_processing == HtpContentEncoding::None {
313
0
                resp.response_message_len =
314
0
                    resp.response_message_len.wrapping_add(bytes_to_consume);
315
                // Create a new gap of the appropriate length
316
0
                let parser_data = ParserData::from(bytes_to_consume as usize);
317
                // Send the gap to the data hooks
318
0
                let mut tx_data = Data::new(resp, &parser_data);
319
0
                self.response_run_hook_body_data(&mut tx_data)?;
320
            } else {
321
                // end decompression on gap
322
0
                self.response_body_data(None)?;
323
            }
324
        } else {
325
            // Consume the data.
326
8
            self.response_body_data(Some(&data.as_slice()[0..bytes_to_consume as usize]))?;
327
        }
328
        // Adjust the counters.
329
8
        self.response_data_consume(data, bytes_to_consume as usize);
330
8
        self.response_body_data_left = Some(left - bytes_to_consume);
331
        // Have we seen the entire response body?
332
8
        if self.response_body_data_left > Some(0) {
333
0
            return Err(HtpStatus::DATA);
334
8
        }
335
        // End of response body.
336
8
        self.response_state = State::Finalize;
337
        // Sends close signal to decompressors, outputting any partially decompressed data
338
8
        self.response_body_data(None)
339
16
    }
340
341
    /// Processes identity response body of unknown length. In this case, we assume the
342
    /// response body consumes all data until the end of the stream.
343
    ///
344
    /// Returns HtpStatus::OK on state change, HtpStatus::ERROR on error, or HtpStatus::DATA
345
    /// when more data is needed.
346
172k
    pub(crate) fn response_body_identity_stream_close(&mut self, data: &ParserData) -> Result<()> {
347
172k
        if !data.is_empty() {
348
            // Consume all data from the input buffer.
349
170k
            self.response_body_data(data.data())?;
350
            // Adjust the counters.
351
170k
            self.response_data_consume(data, data.len());
352
1.55k
        }
353
        // Have we seen the entire response body?
354
172k
        if self.response_status == HtpStreamState::CLOSED {
355
825
            self.response_state = State::Finalize;
356
825
            return Ok(());
357
171k
        }
358
359
171k
        Err(HtpStatus::DATA)
360
172k
    }
361
362
    /// Determines presence (and encoding) of a response body.
363
18.4k
    pub(crate) fn response_body_determine(&mut self, input: &mut ParserData) -> Result<()> {
364
        // If the request uses the CONNECT method, then not only are we
365
        // to assume there's no body, but we need to ignore all
366
        // subsequent data in the stream.
367
18.4k
        let response_tx = self.response_mut();
368
18.4k
        if response_tx.is_none() {
369
0
            return Err(HtpStatus::ERROR);
370
18.4k
        }
371
18.4k
        let response_tx = response_tx.unwrap();
372
373
18.4k
        if response_tx.request_method_number == HtpMethod::CONNECT {
374
2.40k
            if response_tx.response_status_number.in_range(200, 299) {
375
                // This is a successful CONNECT stream, which means
376
                // we need to switch into tunneling mode: on the
377
                // request side we'll now probe the tunnel data to see
378
                // if we need to parse or ignore it. So on the response
379
                // side we wrap up the tx and wait.
380
342
                self.response_state = State::Finalize;
381
                // we may have response headers
382
342
                return self.state_response_headers(input);
383
2.06k
            } else if response_tx.response_status_number.eq_num(407) {
384
                // proxy telling us to auth
385
1
                if self.request_status != HtpStreamState::ERROR {
386
1
                    self.request_status = HtpStreamState::DATA
387
0
                }
388
            } else {
389
                // This is a failed CONNECT stream, which means that
390
                // we can unblock request parsing
391
2.06k
                if self.request_status != HtpStreamState::ERROR {
392
2.06k
                    self.request_status = HtpStreamState::DATA
393
0
                }
394
                // We are going to continue processing this transaction,
395
                // adding a note for ourselves to stop at the end (because
396
                // we don't want to see the beginning of a new transaction).
397
2.06k
                self.response_data_other_at_tx_end = true
398
            }
399
16.0k
        }
400
18.1k
        let response_tx = self.response_mut().unwrap();
401
18.1k
        let cl_opt = response_tx
402
18.1k
            .response_headers
403
18.1k
            .get_nocase_nozero("content-length")
404
18.1k
            .cloned();
405
18.1k
        let te_opt = response_tx
406
18.1k
            .response_headers
407
18.1k
            .get_nocase_nozero("transfer-encoding")
408
18.1k
            .cloned();
409
        // Check for "101 Switching Protocol" response.
410
        // If it's seen, it means that traffic after empty line following headers
411
        // is no longer HTTP. We can treat it similarly to CONNECT.
412
        // Unlike CONNECT, however, upgrades from HTTP to HTTP seem
413
        // rather unlikely, so don't try to probe tunnel for nested HTTP,
414
        // and switch to tunnel mode right away.
415
18.1k
        if response_tx.response_status_number.eq_num(101) {
416
40
            if response_tx
417
40
                .response_headers
418
40
                .get_nocase_nozero("upgrade")
419
40
                .map(|upgrade| upgrade.value.index_of_nocase_nozero("h2c").is_some())
420
40
                .unwrap_or(false)
421
0
            {
422
0
                response_tx.is_http_2_upgrade = true;
423
40
            }
424
40
            if te_opt.is_none() && cl_opt.is_none() {
425
40
                self.response_state = State::Finalize;
426
40
                if self.request_status != HtpStreamState::ERROR {
427
40
                    self.request_status = HtpStreamState::TUNNEL
428
0
                }
429
40
                self.response_status = HtpStreamState::TUNNEL;
430
                // we may have response headers
431
40
                return self.state_response_headers(input);
432
0
            } else {
433
0
                htp_warn!(
434
0
                    self.logger,
435
0
                    HtpLogCode::SWITCHING_PROTO_WITH_CONTENT_LENGTH,
436
0
                    "Switching Protocol with Content-Length"
437
0
                );
438
0
            }
439
        }
440
        // Check for an interim "100 Continue" response. Ignore it if found, and revert back to RES_LINE.
441
18.1k
        else if response_tx.response_status_number.eq_num(100) && te_opt.is_none() {
442
1.81k
            match cl_opt
443
1.81k
                .as_ref()
444
1.81k
                .and_then(|cl| parse_content_length(cl.value.as_slice(), Some(&mut self.logger)))
445
            {
446
                // 100 Continue with a Content-Length > 0 isn't treated as a 100 Continue,
447
                // so we do nothing here.
448
0
                Some(x) if x > 0 => (),
449
                // Otherwise we treat it as a continue and prep for the next response
450
                _ => {
451
1.81k
                    let response_tx = self.response_mut().unwrap();
452
1.81k
                    if response_tx.seen_100continue {
453
936
                        let mut flags = 0; // unused but needed by macro
454
936
                        htp_warn_once!(
455
324
                            self.logger,
456
324
                            HtpLogCode::CONTINUE_ALREADY_SEEN,
457
324
                            "Already seen 100-Continue.",
458
936
                            self.response_mut().unwrap().flags,
459
936
                            flags,
460
                            HtpFlags::FIELD_100_CONTINUE
461
                        );
462
883
                    }
463
                    // Expecting to see another response line next.
464
1.81k
                    self.response_state = State::Line;
465
1.81k
                    let response_tx = self.response_mut().unwrap();
466
                    // Ignore any response headers seen so far.
467
1.81k
                    response_tx.response_headers.elements.clear();
468
1.81k
                    response_tx.response_progress = HtpResponseProgress::LINE;
469
1.81k
                    response_tx.seen_100continue = true;
470
1.81k
                    return Ok(());
471
                }
472
            }
473
        }
474
        // A request can indicate it waits for headers validation
475
        // before sending its body cf
476
        // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expect
477
16.2k
        else if response_tx.response_status_number.in_range(400, 499)
478
23
            && self.request_content_length > Some(0)
479
0
            && self.request_body_data_left == self.request_content_length
480
        {
481
0
            let response_tx = self.response_mut().unwrap();
482
0
            if let Some(expect) = response_tx.request_headers.get_nocase("expect") {
483
0
                if expect.value.eq_slice("100-continue") {
484
0
                    self.request_state = State::Finalize;
485
0
                }
486
0
            }
487
16.2k
        }
488
489
        // 1. Any response message which MUST NOT include a message-body
490
        //  (such as the 1xx, 204, and 304 responses and any response to a HEAD
491
        //  request) is always terminated by the first empty line after the
492
        //  header fields, regardless of the entity-header fields present in the
493
        //  message.
494
16.2k
        let response_tx = self.response_mut().unwrap();
495
16.2k
        if response_tx.request_method_number == HtpMethod::HEAD {
496
            // There's no response body whatsoever
497
644
            response_tx.response_transfer_coding = HtpTransferCoding::NoBody;
498
644
            self.response_state = State::Finalize
499
15.6k
        } else if response_tx.response_status_number.in_range(100, 199)
500
4.06k
            || response_tx.response_status_number.eq_num(204)
501
3.97k
            || response_tx.response_status_number.eq_num(304)
502
        {
503
            // There should be no response body
504
            // but browsers interpret content sent by the server as such
505
13.7k
            if te_opt.is_none() && cl_opt.is_none() {
506
13.7k
                response_tx.response_transfer_coding = HtpTransferCoding::NoBody;
507
13.7k
                self.response_state = State::Finalize
508
0
            } else {
509
0
                htp_warn!(
510
0
                    self.logger,
511
0
                    HtpLogCode::RESPONSE_BODY_UNEXPECTED,
512
0
                    "Unexpected Response body"
513
0
                );
514
0
            }
515
1.94k
        }
516
        // Hack condition to check that we do not assume "no body"
517
16.2k
        let mut multipart_byteranges = false;
518
16.2k
        if self.response_state != State::Finalize {
519
            // We have a response body
520
1.94k
            let response_tx = self.response_mut().unwrap();
521
1.94k
            let response_content_type = if let Some(ct) = response_tx
522
1.94k
                .response_headers
523
1.94k
                .get_nocase_nozero("content-type")
524
            {
525
                // TODO Some platforms may do things differently here.
526
533
                let response_content_type = if let Ok((_, ct)) =
527
224k
                    streaming_take_till::<_, _, (&[u8], ErrorKind)>(|c| c == b';' || is_space(c))(
528
533
                        &ct.value,
529
                    ) {
530
133
                    ct
531
                } else {
532
400
                    &ct.value
533
                };
534
535
533
                let mut response_content_type = Bstr::from(response_content_type);
536
533
                response_content_type.make_ascii_lowercase();
537
533
                if response_content_type
538
533
                    .index_of_nocase("multipart/byteranges")
539
533
                    .is_some()
540
0
                {
541
0
                    multipart_byteranges = true;
542
533
                }
543
533
                Some(response_content_type)
544
            } else {
545
1.41k
                None
546
            };
547
548
1.94k
            if response_content_type.is_some() {
549
533
                response_tx.response_content_type = response_content_type;
550
1.41k
            }
551
            // 2. If a Transfer-Encoding header field (section 14.40) is present and
552
            //   indicates that the "chunked" transfer coding has been applied, then
553
            //   the length is defined by the chunked encoding (section 3.6).
554
0
            if let Some(te) =
555
1.94k
                te_opt.and_then(|te| te.value.index_of_nocase_nozero("chunked").and(Some(te)))
556
            {
557
0
                if !te.value.cmp_nocase("chunked") {
558
0
                    htp_warn!(
559
0
                        self.logger,
560
0
                        HtpLogCode::RESPONSE_ABNORMAL_TRANSFER_ENCODING,
561
0
                        "Transfer-encoding has abnormal chunked value"
562
0
                    );
563
0
                }
564
                // 3. If a Content-Length header field (section 14.14) is present, its
565
                // spec says chunked is HTTP/1.1 only, but some browsers accept it
566
                // with 1.0 as well
567
0
                let response_tx = self.response_mut().unwrap();
568
0
                if response_tx.response_protocol_number < HtpProtocol::V1_1 {
569
0
                    htp_warn!(
570
0
                        self.logger,
571
0
                        HtpLogCode::RESPONSE_CHUNKED_OLD_PROTO,
572
0
                        "Chunked transfer-encoding on HTTP/0.9 or HTTP/1.0"
573
0
                    );
574
0
                }
575
                // If the T-E header is present we are going to use it.
576
0
                let response_tx = self.response_mut().unwrap();
577
0
                response_tx.response_transfer_coding = HtpTransferCoding::Chunked;
578
                // We are still going to check for the presence of C-L
579
0
                if cl_opt.is_some() {
580
                    // This is a violation of the RFC
581
0
                    response_tx.flags.set(HtpFlags::REQUEST_SMUGGLING)
582
0
                }
583
0
                response_tx.response_progress = HtpResponseProgress::BODY;
584
0
                self.response_state = State::BodyChunkedLength
585
1.94k
            } else if let Some(cl) = cl_opt {
586
                //   value in bytes represents the length of the message-body.
587
                // We know the exact length
588
8
                response_tx.response_transfer_coding = HtpTransferCoding::Identity;
589
                // Check for multiple C-L headers
590
8
                if cl.flags.is_set(HtpFlags::FIELD_REPEATED) {
591
0
                    response_tx.flags.set(HtpFlags::REQUEST_SMUGGLING)
592
8
                }
593
                // Get body length
594
8
                let response_content_length =
595
8
                    parse_content_length((*cl.value).as_slice(), Some(&mut self.logger));
596
8
                self.response_mut().unwrap().response_content_length = response_content_length;
597
8
                self.response_content_length = response_content_length;
598
8
                self.response_body_data_left = response_content_length;
599
8
                if let Some(len) = response_content_length {
600
8
                    if len != 0 {
601
8
                        self.response_state = State::BodyIdentityCLKnown;
602
8
                        self.response_mut().unwrap().response_progress = HtpResponseProgress::BODY
603
                    } else {
604
0
                        self.response_state = State::Finalize
605
                    }
606
                } else {
607
0
                    htp_error!(
608
0
                        self.logger,
609
0
                        HtpLogCode::INVALID_CONTENT_LENGTH_FIELD_IN_RESPONSE,
610
0
                        "Invalid C-L field in response"
611
0
                    );
612
0
                    return Err(HtpStatus::ERROR);
613
                }
614
            } else {
615
                // 4. If the message uses the media type "multipart/byteranges", which is
616
                //   self-delimiting, then that defines the length. This media type MUST
617
                //   NOT be used unless the sender knows that the recipient can parse it;
618
                //   the presence in a request of a Range header with multiple byte-range
619
                //   specifiers implies that the client can parse multipart/byteranges
620
                //   responses.
621
                // TODO Handle multipart/byteranges
622
1.93k
                if multipart_byteranges {
623
0
                    htp_error!(
624
0
                        self.logger,
625
0
                        HtpLogCode::RESPONSE_MULTIPART_BYTERANGES,
626
0
                        "C-T multipart/byteranges in responses not supported"
627
0
                    );
628
0
                    return Err(HtpStatus::ERROR);
629
1.93k
                }
630
                // 5. By the server closing the connection. (Closing the connection
631
                //   cannot be used to indicate the end of a request body, since that
632
                //   would leave no possibility for the server to send back a response.)
633
1.93k
                response_tx.response_transfer_coding = HtpTransferCoding::Identity;
634
1.93k
                response_tx.response_progress = HtpResponseProgress::BODY;
635
1.93k
                self.response_state = State::BodyIdentityStreamClose;
636
1.93k
                self.response_body_data_left = None
637
            }
638
14.3k
        }
639
        // NOTE We do not need to check for short-style HTTP/0.9 requests here because
640
        //      that is done earlier, before response line parsing begins
641
16.2k
        self.state_response_headers(input)
642
18.4k
    }
643
644
    /// Parses response line.
645
    ///
646
    /// Returns HtpStatus::OK on state change, HtpStatus::ERROR on error, or HtpStatus::DATA
647
    /// when more data is needed.
648
3.13M
    pub(crate) fn response_line(&mut self, input: &ParserData) -> Result<()> {
649
3.13M
        match take_till_eol(input.as_slice()) {
650
2.83M
            Ok((_, (line, _))) => {
651
                // We have a line ending, so consume the input
652
                // and grab any buffered data.
653
2.83M
                let mut data = take(&mut self.response_buf);
654
2.83M
                data.add(line);
655
2.83M
                self.response_data_consume(input, line.len());
656
2.83M
                self.response_line_complete(data.as_slice(), input)
657
            }
658
            _ => {
659
307k
                if self.response_status == HtpStreamState::CLOSED {
660
1.63k
                    let mut data = take(&mut self.response_buf);
661
1.63k
                    data.add(input.as_slice());
662
1.63k
                    self.response_data_consume(input, input.len());
663
1.63k
                    self.response_line_complete(data.as_slice(), input)
664
                } else {
665
306k
                    self.handle_response_absent_lf(input)
666
                }
667
            }
668
        }
669
3.13M
    }
670
671
    /// Parse the complete response line.
672
    ///
673
    /// Returns OK on state change, ERROR on error, or HtpStatus::DATA_BUFFER
674
    /// when more data is needed.
675
2.83M
    fn response_line_complete(&mut self, line: &[u8], input: &ParserData) -> Result<()> {
676
2.83M
        self.check_response_buffer_limit(line.len())?;
677
2.83M
        if line.is_empty() {
678
73
            return Err(HtpStatus::DATA);
679
2.83M
        }
680
2.83M
        let response_tx = self.response_mut();
681
2.83M
        if response_tx.is_none() {
682
0
            return Err(HtpStatus::ERROR);
683
2.83M
        }
684
2.83M
        if is_line_ignorable(self.cfg.server_personality, line) {
685
863k
            if self.response_status == HtpStreamState::CLOSED {
686
31
                self.response_state = State::Finalize
687
863k
            }
688
            // We have an empty/whitespace line, which we'll note, ignore and move on
689
863k
            let response_tx = self.response_mut().unwrap();
690
863k
            response_tx.response_ignored_lines = response_tx.response_ignored_lines.wrapping_add(1);
691
            // TODO How many lines are we willing to accept?
692
            // Start again
693
863k
            return Ok(());
694
1.96M
        }
695
        // Deallocate previous response line allocations, which we would have on a 100 response.
696
1.96M
        let response_tx = self.response_mut().unwrap();
697
1.96M
        response_tx.response_line = None;
698
1.96M
        response_tx.response_protocol = None;
699
1.96M
        response_tx.response_status = None;
700
1.96M
        response_tx.response_message = None;
701
702
        // Process response line.
703
        // If the response line is invalid, determine if it _looks_ like
704
        // a response line. If it does not look like a line, process the
705
        // data as a response body because that is what browsers do.
706
1.96M
        if treat_response_line_as_body(line) {
707
            // if we have a next line beginning with H, skip this one
708
1.94M
            if input.len() > 1 && (input.as_slice()[0] == b'H' || chomp(line).len() <= 2) {
709
789k
                response_tx.response_ignored_lines =
710
789k
                    response_tx.response_ignored_lines.wrapping_add(1);
711
789k
                return Ok(());
712
1.16M
            }
713
1.16M
            response_tx.response_content_encoding_processing = HtpContentEncoding::None;
714
1.16M
            self.response_body_data(Some(line))?;
715
            // Continue to process response body. Because we don't have
716
            // any headers to parse, we assume the body continues until
717
            // the end of the stream.
718
            // Have we seen the entire response body?
719
1.16M
            if input.is_empty() {
720
362k
                let response_tx = self.response_mut().unwrap();
721
362k
                response_tx.response_transfer_coding = HtpTransferCoding::Identity;
722
362k
                response_tx.response_progress = HtpResponseProgress::BODY;
723
362k
                self.response_body_data_left = None;
724
362k
                self.response_state = State::Finalize
725
797k
            }
726
1.16M
            return Ok(());
727
19.9k
        }
728
19.9k
        self.parse_response_line(line)?;
729
19.9k
        self.state_response_line()?;
730
        // Move on to the next phase.
731
19.9k
        self.response_state = State::Headers;
732
19.9k
        self.response_mut().unwrap().response_progress = HtpResponseProgress::HEADERS;
733
19.9k
        Ok(())
734
2.83M
    }
735
736
    /// Parses the response line.
737
19.9k
    pub(crate) fn parse_response_line(&mut self, response_line: &[u8]) -> Result<()> {
738
19.9k
        let response_tx = self.response_mut();
739
19.9k
        if response_tx.is_none() {
740
0
            return Err(HtpStatus::ERROR);
741
19.9k
        }
742
19.9k
        let response_tx = response_tx.unwrap();
743
744
19.9k
        response_tx.response_line = Some(Bstr::from(response_line));
745
19.9k
        response_tx.response_protocol_number = HtpProtocol::Invalid;
746
19.9k
        response_tx.response_status = None;
747
19.9k
        response_tx.response_status_number = HtpResponseNumber::Invalid;
748
19.9k
        response_tx.response_message = None;
749
750
19.9k
        let mut response_line_parser = tuple((
751
19.9k
            take_is_space_or_null,
752
19.9k
            take_not_is_space,
753
19.9k
            take_is_space,
754
19.9k
            take_not_is_space,
755
19.9k
            take_ascii_whitespace(),
756
19.9k
        ));
757
758
19.9k
        let (message, (_ls, response_protocol, ws1, status_code, ws2)) =
759
19.9k
            response_line_parser(response_line)?;
760
19.9k
        if response_protocol.is_empty() {
761
0
            return Ok(());
762
19.9k
        }
763
764
19.9k
        response_tx.response_protocol = Some(Bstr::from(response_protocol));
765
19.9k
        self.response_mut().unwrap().response_protocol_number =
766
19.9k
            parse_protocol(response_protocol, &mut self.logger);
767
768
19.9k
        if ws1.is_empty() || status_code.is_empty() {
769
1.20k
            return Ok(());
770
18.7k
        }
771
772
18.7k
        let response_tx = self.response_mut().unwrap();
773
18.7k
        response_tx.response_status = Some(Bstr::from(status_code));
774
18.7k
        response_tx.response_status_number = parse_status(status_code);
775
776
18.7k
        if ws2.is_empty() {
777
901
            return Ok(());
778
17.8k
        }
779
780
17.8k
        response_tx.response_message = Some(Bstr::from(chomp(message)));
781
17.8k
        Ok(())
782
19.9k
    }
783
784
    /// Response header parser.
785
    ///
786
    ///Returns a tuple of the unparsed data and a boolean indicating if the EOH was seen.
787
80.4k
    fn parse_response_headers<'a>(&mut self, data: &'a [u8]) -> Result<(&'a [u8], bool)> {
788
80.4k
        let resp = self.response_mut();
789
80.4k
        if resp.is_none() {
790
0
            return Err(HtpStatus::ERROR);
791
80.4k
        }
792
793
80.4k
        let rc = resp.unwrap().response_header_parser.headers()(data);
794
80.4k
        if let Ok((remaining, (headers, eoh))) = rc {
795
413k
            for h in headers {
796
383k
                let mut flags = 0;
797
383k
                let name_flags = &h.name.flags;
798
383k
                let value_flags = &h.value.flags;
799
383k
                if value_flags.is_set(HeaderFlags::DEFORMED_EOL)
800
365k
                    || name_flags.is_set(HeaderFlags::DEFORMED_EOL)
801
17.6k
                {
802
17.6k
                    htp_warn!(
803
17.6k
                        self.logger,
804
17.6k
                        HtpLogCode::DEFORMED_EOL,
805
17.6k
                        "Weird response end of lines mix"
806
17.6k
                    );
807
365k
                }
808
                // Ignore LWS after field-name.
809
383k
                if name_flags.is_set(HeaderFlags::NAME_TRAILING_WHITESPACE) {
810
1.89k
                    htp_warn_once!(
811
780
                        self.logger,
812
780
                        HtpLogCode::RESPONSE_INVALID_LWS_AFTER_NAME,
813
780
                        "Request field invalid: LWS after name",
814
1.89k
                        self.response_mut().unwrap().flags,
815
1.89k
                        flags,
816
                        HtpFlags::FIELD_INVALID
817
                    );
818
381k
                }
819
                //If there was leading whitespace, probably was invalid folding.
820
383k
                if name_flags.is_set(HeaderFlags::NAME_LEADING_WHITESPACE) {
821
762
                    htp_warn_once!(
822
230
                        self.logger,
823
230
                        HtpLogCode::INVALID_RESPONSE_FIELD_FOLDING,
824
230
                        "Invalid response field folding",
825
762
                        self.response_mut().unwrap().flags,
826
762
                        flags,
827
                        HtpFlags::INVALID_FOLDING
828
                    );
829
762
                    flags.set(HtpFlags::FIELD_INVALID);
830
382k
                }
831
                // Check that field-name is a token
832
383k
                if name_flags.is_set(HeaderFlags::NAME_NON_TOKEN_CHARS) {
833
                    // Incorrectly formed header name.
834
98.7k
                    htp_warn_once!(
835
1.74k
                        self.logger,
836
1.74k
                        HtpLogCode::RESPONSE_HEADER_NAME_NOT_TOKEN,
837
1.74k
                        "Response header name is not a token",
838
98.7k
                        self.response_mut().unwrap().flags,
839
98.7k
                        flags,
840
                        HtpFlags::FIELD_INVALID
841
                    );
842
284k
                }
843
                // No colon?
844
383k
                if name_flags.is_set(HeaderFlags::MISSING_COLON) {
845
                    // We handle this case as a header with an empty name, with the value equal
846
                    // to the entire input string.
847
                    // TODO Apache will respond to this problem with a 400.
848
                    // Now extract the name and the value
849
258k
                    htp_warn_once!(
850
7.05k
                        self.logger,
851
7.05k
                        HtpLogCode::RESPONSE_FIELD_MISSING_COLON,
852
7.05k
                        "Response field invalid: colon missing",
853
258k
                        self.response_mut().unwrap().flags,
854
258k
                        flags,
855
                        HtpFlags::FIELD_UNPARSEABLE
856
                    );
857
258k
                    flags.set(HtpFlags::FIELD_INVALID);
858
125k
                } else if name_flags.is_set(HeaderFlags::NAME_EMPTY) {
859
                    // Empty header name.
860
0
                    htp_warn_once!(
861
0
                        self.logger,
862
0
                        HtpLogCode::RESPONSE_INVALID_EMPTY_NAME,
863
0
                        "Response field invalid: empty name",
864
0
                        self.response_mut().unwrap().flags,
865
0
                        flags,
866
                        HtpFlags::FIELD_INVALID
867
                    );
868
125k
                }
869
383k
                self.process_response_header(Header::new_with_flags(
870
383k
                    h.name.name.into(),
871
383k
                    h.value.value.into(),
872
383k
                    flags,
873
0
                ))?;
874
            }
875
29.9k
            Ok((remaining, eoh))
876
        } else {
877
50.5k
            Ok((data, false))
878
        }
879
80.4k
    }
880
881
    /// Response header line(s) processor, which assembles folded lines
882
    /// into a single buffer before invoking the parsing function.
883
383k
    fn process_response_header(&mut self, header: Header) -> Result<()> {
884
383k
        let mut repeated = false;
885
383k
        let hl = self.cfg.number_headers_limit as usize;
886
383k
        let resp = self.response_mut();
887
383k
        if resp.is_none() {
888
0
            return Err(HtpStatus::ERROR);
889
383k
        }
890
383k
        let resp = resp.unwrap();
891
892
383k
        let reps = resp.response_header_repetitions;
893
383k
        let mut update_reps = false;
894
        // Do we already have a header with the same name?
895
383k
        if let Some(h_existing) = resp.response_headers.get_nocase_mut(header.name.as_slice()) {
896
347k
            if !h_existing.flags.is_set(HeaderFlags::FIELD_REPEATED) {
897
15.0k
                // This is the second occurence for this header.
898
15.0k
                repeated = true;
899
332k
            } else if reps < 64 {
900
56.4k
                update_reps = true;
901
56.4k
            } else {
902
276k
                return Ok(());
903
            }
904
71.5k
            h_existing.flags.set(HeaderFlags::FIELD_REPEATED);
905
            // For simplicity reasons, we count the repetitions of all headers
906
            // Having multiple C-L headers is against the RFC but many
907
            // browsers ignore the subsequent headers if the values are the same.
908
71.5k
            if header.name.cmp_nocase("Content-Length") {
909
                // Don't use string comparison here because we want to
910
                // ignore small formatting differences.
911
0
                let existing_cl = parse_content_length(&h_existing.value, None);
912
0
                let new_cl = parse_content_length(&(header.value), None);
913
0
                if existing_cl.is_none() || new_cl.is_none() || existing_cl != new_cl {
914
0
                    // Ambiguous response C-L value.
915
0
                    htp_warn!(
916
0
                        self.logger,
917
0
                        HtpLogCode::DUPLICATE_CONTENT_LENGTH_FIELD_IN_RESPONSE,
918
0
                        "Ambiguous response C-L value"
919
0
                    );
920
0
                }
921
71.5k
            } else {
922
71.5k
                // Add to the existing header.
923
71.5k
                h_existing.value.extend_from_slice(b", ");
924
71.5k
                h_existing.value.extend_from_slice(header.value.as_slice());
925
71.5k
            }
926
        } else {
927
35.9k
            if resp.response_headers.elements.len() > hl {
928
0
                if !resp.flags.is_set(HtpFlags::HEADERS_TOO_MANY) {
929
0
                    htp_warn!(
930
0
                        self.logger,
931
0
                        HtpLogCode::RESPONSE_TOO_MANY_HEADERS,
932
0
                        "Too many response headers"
933
0
                    );
934
0
                    let resp = self.response_mut().unwrap();
935
0
                    resp.flags.set(HtpFlags::HEADERS_TOO_MANY);
936
0
                }
937
0
                return Err(HtpStatus::ERROR);
938
35.9k
            }
939
35.9k
            resp.response_headers.elements.push(header);
940
        }
941
107k
        let resp = self.response_mut().unwrap();
942
107k
        if update_reps {
943
56.4k
            resp.response_header_repetitions = resp.response_header_repetitions.wrapping_add(1)
944
51.0k
        }
945
107k
        if repeated {
946
15.0k
            htp_warn!(
947
15.0k
                self.logger,
948
15.0k
                HtpLogCode::RESPONSE_HEADER_REPETITION,
949
15.0k
                "Repetition for header"
950
15.0k
            );
951
92.4k
        }
952
107k
        Ok(())
953
383k
    }
954
    /// Parses response headers.
955
    ///
956
    /// Returns HtpStatus::OK on state change, HtpStatus::ERROR on error, or HtpStatus::DATA when more data is needed.
957
102k
    pub(crate) fn response_headers(&mut self, input: &mut ParserData) -> Result<()> {
958
102k
        let response_index = self.response_index();
959
102k
        if self.response_status == HtpStreamState::CLOSED {
960
1.00k
            let resp = self.response_mut();
961
1.00k
            if resp.is_none() {
962
0
                return Err(HtpStatus::ERROR);
963
1.00k
            }
964
1.00k
            let resp = resp.unwrap();
965
1.00k
            resp.response_header_parser.set_complete(true);
966
            // Parse previous header, if any.
967
1.00k
            if let Some(response_header) = self.response_header.take() {
968
868
                self.parse_response_headers(response_header.as_slice())?;
969
137
            }
970
            // Finalize sending raw trailer data.
971
1.00k
            self.response_receiver_finalize_clear(input)?;
972
            // Run hook response_TRAILER
973
1.00k
            self.cfg
974
1.00k
                .hook_response_trailer
975
1.00k
                .clone()
976
1.00k
                .run_all(self, response_index)?;
977
1.00k
            self.response_state = State::Finalize;
978
1.00k
            return Ok(());
979
101k
        }
980
101k
        if let Ok((_, line)) = take_till_lf(input.as_slice()) {
981
79.5k
            if self.response_header.is_some() {
982
62.4k
                self.check_response_buffer_limit(line.len())?;
983
17.1k
            }
984
        } else {
985
22.2k
            let data = input.as_slice();
986
22.2k
            self.response_data_consume(input, data.len());
987
22.2k
            self.check_response_buffer_limit(data.len())?;
988
22.2k
            if let Some(rh) = &mut self.response_header {
989
19.5k
                rh.extend_from_slice(data);
990
19.5k
            } else {
991
2.70k
                self.response_header = Some(Bstr::from(data));
992
2.70k
            }
993
22.2k
            return Err(HtpStatus::DATA_BUFFER);
994
        }
995
79.5k
        let response_header = if let Some(mut response_header) = self.response_header.take() {
996
62.4k
            response_header.add(input.as_slice());
997
62.4k
            response_header
998
        } else {
999
17.1k
            Bstr::from(input.as_slice())
1000
        };
1001
1002
79.5k
        let (remaining, eoh) = self.parse_response_headers(response_header.as_slice())?;
1003
        //TODO: Update the response state machine so that we don't have to have this EOL check
1004
79.5k
        let eol = remaining.len() == response_header.len()
1005
49.9k
            && (remaining.eq(b"\r\n") || remaining.eq(b"\n"));
1006
        // If remaining is EOL or header parsing saw EOH this is end of headers
1007
79.5k
        if eoh || eol {
1008
18.4k
            if eol {
1009
4.12k
                //Consume the EOL so it isn't included in data processing
1010
4.12k
                self.response_data_consume(input, input.len());
1011
14.3k
            } else if remaining.len() <= input.len() {
1012
13.6k
                self.response_data_consume(input, input.len() - remaining.len());
1013
13.6k
            }
1014
            // We've seen all response headers. At terminator.
1015
            self.response_state =
1016
18.4k
                if self.response().unwrap().response_progress == HtpResponseProgress::HEADERS {
1017
                    // Response headers.
1018
                    // The next step is to determine if this response has a body.
1019
18.4k
                    State::BodyDetermine
1020
                } else {
1021
                    // Response trailer.
1022
                    // Finalize sending raw trailer data.
1023
0
                    self.response_receiver_finalize_clear(input)?;
1024
                    // Run hook response_TRAILER.
1025
0
                    self.cfg
1026
0
                        .hook_response_trailer
1027
0
                        .clone()
1028
0
                        .run_all(self, response_index)?;
1029
                    // The next step is to finalize this response.
1030
0
                    State::Finalize
1031
                };
1032
18.4k
            Ok(())
1033
        } else {
1034
61.0k
            self.response_data_consume(input, input.len());
1035
61.0k
            self.check_response_buffer_limit(remaining.len())?;
1036
61.0k
            let remaining = Bstr::from(remaining);
1037
61.0k
            self.response_header.replace(remaining);
1038
61.0k
            Err(HtpStatus::DATA_BUFFER)
1039
        }
1040
102k
    }
1041
1042
    /// Consumes response body data.
1043
    /// This function assumes that handling of chunked encoding is implemented
1044
    /// by the container. When you're done submitting body data, invoking a state
1045
    /// change (to RESPONSE) will finalize any processing that might be pending.
1046
    ///
1047
    /// The response body data will be decompressed if two conditions are met: one,
1048
    /// decompression is enabled in configuration and two, if the response headers
1049
    /// indicate compression. Alternatively, you can control decompression from
1050
    /// a RESPONSE_HEADERS callback, by setting tx->response_content_encoding either
1051
    /// to COMPRESSION_NONE (to disable compression), or to one of the supported
1052
    /// decompression algorithms.
1053
    ///
1054
    /// Returns HtpStatus::OK on success or HtpStatus::ERROR if the request transaction
1055
    /// is invalid or response body data hook fails.
1056
2.27M
    pub(crate) fn response_body_data(&mut self, data: Option<&[u8]>) -> Result<()> {
1057
        // None data is used to indicate the end of response body.
1058
        // Keep track of body size before decompression.
1059
2.27M
        let resp = self.response_mut();
1060
2.27M
        if resp.is_none() {
1061
0
            return Err(HtpStatus::ERROR);
1062
2.27M
        }
1063
2.27M
        let resp = resp.unwrap();
1064
1065
2.27M
        resp.response_message_len = resp
1066
2.27M
            .response_message_len
1067
2.27M
            .wrapping_add(data.unwrap_or(b"").len() as u64);
1068
1069
2.27M
        match resp.response_content_encoding_processing {
1070
            HtpContentEncoding::Gzip
1071
            | HtpContentEncoding::Deflate
1072
            | HtpContentEncoding::Zlib
1073
            | HtpContentEncoding::Brotli
1074
            | HtpContentEncoding::Lzma => {
1075
                // Send data buffer to the decompressor if it exists
1076
13.3k
                if resp.response_decompressor.is_none() && data.is_none() {
1077
0
                    return Ok(());
1078
13.3k
                }
1079
13.3k
                let mut decompressor = resp.response_decompressor.take().ok_or(HtpStatus::ERROR)?;
1080
13.3k
                if let Some(data) = data {
1081
13.2k
                    let _ = decompressor.decompress(data);
1082
1083
13.2k
                    if decompressor.time_spent()
1084
13.2k
                        > self.cfg.compression_options.get_time_limit() as u64
1085
0
                    {
1086
0
                        htp_error!(
1087
0
                            self.logger,
1088
0
                            HtpLogCode::COMPRESSION_BOMB,
1089
0
                            format!(
1090
0
                                "Compression bomb: spent {} us decompressing",
1091
0
                                decompressor.time_spent(),
1092
0
                            )
1093
0
                        );
1094
0
                        decompressor.set_passthrough(true);
1095
13.2k
                    }
1096
                    // put the decompressor back in its slot
1097
13.2k
                    self.response_mut()
1098
13.2k
                        .unwrap()
1099
13.2k
                        .response_decompressor
1100
13.2k
                        .replace(decompressor);
1101
142
                } else {
1102
142
                    // don't put the decompressor back in its slot
1103
142
                    // ignore errors
1104
142
                    let _ = decompressor.finish();
1105
142
                }
1106
            }
1107
            HtpContentEncoding::None => {
1108
                // When there's no decompression, response_entity_len.
1109
                // is identical to response_message_len.
1110
2.26M
                let data = ParserData::from(data);
1111
2.26M
                let mut tx_data = Data::new(resp, &data);
1112
2.26M
                resp.response_entity_len =
1113
2.26M
                    resp.response_entity_len.wrapping_add(tx_data.len() as u64);
1114
2.26M
                self.response_run_hook_body_data(&mut tx_data)?;
1115
            }
1116
        }
1117
2.27M
        Ok(())
1118
2.27M
    }
1119
1120
    /// Initialize the response decompression engine. We can deal with three
1121
    /// scenarios:
1122
    ///
1123
    /// 1. Decompression is enabled, compression indicated in headers, and we decompress.
1124
    ///
1125
    /// 2. As above, but the user disables decompression by setting response_content_encoding
1126
    ///    to COMPRESSION_NONE.
1127
    ///
1128
    /// 3. Decompression is disabled and we do not attempt to enable it, but the user
1129
    ///    forces decompression by setting response_content_encoding to one of the
1130
    ///    supported algorithms.
1131
16.6k
    pub(crate) fn response_initialize_decompressors(&mut self) -> Result<()> {
1132
16.6k
        let resp = self.response_mut();
1133
16.6k
        if resp.is_none() {
1134
0
            return Err(HtpStatus::ERROR);
1135
16.6k
        }
1136
16.6k
        let resp = resp.unwrap();
1137
1138
16.6k
        let ce = resp
1139
16.6k
            .response_headers
1140
16.6k
            .get_nocase_nozero("content-encoding")
1141
16.6k
            .map(|val| val.value.clone());
1142
        // Process multiple encodings if there is no match on fast path
1143
16.6k
        let mut slow_path = false;
1144
1145
        // Fast path - try to match directly on the encoding value
1146
16.6k
        resp.response_content_encoding = if let Some(ce) = &ce {
1147
298
            if ce.cmp_nocase_nozero(b"gzip") || ce.cmp_nocase_nozero(b"x-gzip") {
1148
0
                HtpContentEncoding::Gzip
1149
298
            } else if ce.cmp_nocase_nozero(b"deflate") || ce.cmp_nocase_nozero(b"x-deflate") {
1150
0
                HtpContentEncoding::Deflate
1151
298
            } else if ce.cmp_nocase_nozero(b"lzma") {
1152
126
                HtpContentEncoding::Lzma
1153
172
            } else if ce.cmp_nocase_nozero(b"br") {
1154
57
                HtpContentEncoding::Brotli
1155
115
            } else if ce.cmp_nocase_nozero(b"inflate") || ce.cmp_nocase_nozero(b"none") {
1156
11
                HtpContentEncoding::None
1157
            } else {
1158
104
                slow_path = true;
1159
104
                HtpContentEncoding::None
1160
            }
1161
        } else {
1162
16.3k
            HtpContentEncoding::None
1163
        };
1164
1165
        // Configure decompression, if enabled in the configuration.
1166
16.6k
        resp.response_content_encoding_processing = resp.response_content_encoding;
1167
1168
16.6k
        let response_content_encoding_processing = resp.response_content_encoding_processing;
1169
16.6k
        let compression_options = self.cfg.compression_options;
1170
16.6k
        match &response_content_encoding_processing {
1171
            HtpContentEncoding::Gzip
1172
            | HtpContentEncoding::Deflate
1173
            | HtpContentEncoding::Zlib
1174
            | HtpContentEncoding::Brotli
1175
            | HtpContentEncoding::Lzma => {
1176
183
                self.response_prepend_decompressor(response_content_encoding_processing)?;
1177
            }
1178
            HtpContentEncoding::None => {
1179
16.4k
                if slow_path {
1180
104
                    if let Some(ce) = &ce {
1181
104
                        let mut layers = 0;
1182
104
                        let mut lzma_layers = 0;
1183
9.51k
                        for encoding in ce.split(|c| *c == b',' || *c == b' ') {
1184
363
                            if encoding.is_empty() {
1185
162
                                continue;
1186
201
                            }
1187
201
                            layers += 1;
1188
1189
201
                            if let Some(limit) = compression_options.get_layer_limit() {
1190
                                // decompression layer depth check
1191
201
                                if layers > limit {
1192
35
                                    htp_warn!(
1193
35
                                        self.logger,
1194
35
                                        HtpLogCode::TOO_MANY_ENCODING_LAYERS,
1195
35
                                        "Too many response content encoding layers"
1196
35
                                    );
1197
35
                                    break;
1198
166
                                }
1199
0
                            }
1200
1201
166
                            let encoding = Bstr::from(encoding);
1202
166
                            let encoding = if encoding.index_of_nocase(b"gzip").is_some() {
1203
0
                                if !(encoding.cmp_slice(b"gzip") == Ordering::Equal
1204
0
                                    || encoding.cmp_slice(b"x-gzip") == Ordering::Equal)
1205
0
                                {
1206
0
                                    htp_warn!(
1207
0
                                        self.logger,
1208
0
                                        HtpLogCode::ABNORMAL_CE_HEADER,
1209
0
                                        "C-E gzip has abnormal value"
1210
0
                                    );
1211
0
                                }
1212
0
                                HtpContentEncoding::Gzip
1213
166
                            } else if encoding.index_of_nocase(b"deflate").is_some() {
1214
0
                                if !(encoding.cmp_slice(b"deflate") == Ordering::Equal
1215
0
                                    || encoding.cmp_slice(b"x-deflate") == Ordering::Equal)
1216
0
                                {
1217
0
                                    htp_warn!(
1218
0
                                        self.logger,
1219
0
                                        HtpLogCode::ABNORMAL_CE_HEADER,
1220
0
                                        "C-E deflate has abnormal value"
1221
0
                                    );
1222
0
                                }
1223
0
                                HtpContentEncoding::Deflate
1224
166
                            } else if encoding.cmp_slice(b"lzma") == Ordering::Equal {
1225
27
                                lzma_layers += 1;
1226
27
                                if let Some(limit) = compression_options.get_lzma_layers() {
1227
                                    // Lzma layer depth check
1228
0
                                    if lzma_layers > limit {
1229
0
                                        htp_warn!(
1230
0
                                            self.logger,
1231
0
                                            HtpLogCode::RESPONSE_TOO_MANY_LZMA_LAYERS,
1232
0
                                            "Too many response content encoding lzma layers"
1233
0
                                        );
1234
0
                                        break;
1235
0
                                    }
1236
27
                                }
1237
27
                                HtpContentEncoding::Lzma
1238
139
                            } else if encoding.cmp_slice(b"inflate") == Ordering::Equal
1239
139
                                || encoding.cmp_slice(b"none") == Ordering::Equal
1240
139
                                || encoding.cmp_slice(b"identity") == Ordering::Equal
1241
                            {
1242
0
                                HtpContentEncoding::None
1243
                            } else {
1244
139
                                htp_warn!(
1245
139
                                    self.logger,
1246
139
                                    HtpLogCode::ABNORMAL_CE_HEADER,
1247
139
                                    "C-E unknown setting"
1248
139
                                );
1249
139
                                HtpContentEncoding::None
1250
                            };
1251
1252
166
                            self.response_prepend_decompressor(encoding)?;
1253
                        }
1254
0
                    }
1255
16.3k
                }
1256
            }
1257
        }
1258
16.6k
        Ok(())
1259
16.6k
    }
1260
1261
6.97k
    fn response_decompressor_callback(&mut self, data: Option<&[u8]>) -> std::io::Result<usize> {
1262
        // If no data is passed, call the hooks with NULL to signify the end of the
1263
        // response body.
1264
6.97k
        let parser_data = ParserData::from(data);
1265
6.97k
        let compression_options = self.cfg.compression_options;
1266
6.97k
        let resp = self.response_mut().unwrap();
1267
6.97k
        let mut tx_data = Data::new(resp, &parser_data);
1268
1269
        // Keep track of actual response body length.
1270
6.97k
        resp.response_entity_len = resp.response_entity_len.wrapping_add(tx_data.len() as u64);
1271
1272
        // Invoke all callbacks.
1273
6.97k
        self.response_run_hook_body_data(&mut tx_data)
1274
6.97k
            .map_err(|_| std::io::Error::new(std::io::ErrorKind::Other, "body data hook failed"))?;
1275
6.97k
        let resp = self.response_mut().unwrap();
1276
6.97k
        if let Some(decompressor) = &mut resp.response_decompressor {
1277
0
            if decompressor.callback_inc() % compression_options.get_time_test_freq() == 0 {
1278
0
                if let Some(time_spent) = decompressor.timer_reset() {
1279
0
                    if time_spent > compression_options.get_time_limit() as u64 {
1280
0
                        decompressor.set_passthrough(true);
1281
0
                        htp_error!(
1282
0
                            self.logger,
1283
0
                            HtpLogCode::COMPRESSION_BOMB,
1284
0
                            format!("Compression bomb: spent {} us decompressing", time_spent)
1285
0
                        );
1286
0
                    }
1287
0
                }
1288
0
            }
1289
6.97k
        }
1290
1291
        // output > ratio * input ?
1292
6.97k
        let ratio = compression_options.get_bomb_ratio();
1293
6.97k
        let resp = self.response_mut().unwrap();
1294
6.97k
        let exceeds_ratio = if let Some(ratio) = resp.response_message_len.checked_mul(ratio) {
1295
6.97k
            resp.response_entity_len > ratio
1296
        } else {
1297
            // overflow occured
1298
0
            true
1299
        };
1300
1301
6.97k
        let bomb_limit = compression_options.get_bomb_limit();
1302
6.97k
        let response_entity_len = resp.response_entity_len;
1303
6.97k
        let response_message_len = resp.response_message_len;
1304
6.97k
        if response_entity_len > bomb_limit && exceeds_ratio {
1305
0
            htp_error!(
1306
0
                self.logger,
1307
0
                HtpLogCode::COMPRESSION_BOMB,
1308
0
                format!(
1309
0
                    "Compression bomb: decompressed {} bytes out of {}",
1310
0
                    response_entity_len, response_message_len,
1311
0
                )
1312
0
            );
1313
0
            self.bombs += 1;
1314
0
            if self.bombs == compression_options.get_max_bombs() {
1315
0
                htp_error!(
1316
0
                    self.logger,
1317
0
                    HtpLogCode::COMPRESSION_BOMB_LIMIT_REACHED,
1318
0
                    format!("Compression bomb: happened {} times", self.bombs,)
1319
0
                );
1320
0
            }
1321
0
            return Err(std::io::Error::other("compression_bomb_limit reached"));
1322
6.97k
        }
1323
6.97k
        Ok(tx_data.len())
1324
6.97k
    }
1325
1326
    /// Prepend response decompressor
1327
349
    fn response_prepend_decompressor(&mut self, encoding: HtpContentEncoding) -> Result<()> {
1328
349
        let compression_options = self.cfg.compression_options;
1329
349
        if self.bombs >= compression_options.get_max_bombs() {
1330
            // skip decompression for this flow if too many bombs were seen
1331
0
            return Ok(());
1332
349
        }
1333
349
        if encoding != HtpContentEncoding::None {
1334
            // ensured by caller
1335
210
            let resp = self.response_mut().unwrap();
1336
210
            if let Some(decompressor) = resp.response_decompressor.take() {
1337
11
                let decompressor = decompressor.prepend(encoding, compression_options)?;
1338
11
                resp.response_decompressor.replace(decompressor);
1339
            } else {
1340
                // The processing encoding will be the first one encountered
1341
199
                resp.response_content_encoding_processing = encoding;
1342
1343
                // Add the callback first because it will be called last in
1344
                // the chain of writers
1345
1346
                // TODO: fix lifetime error and remove this line!
1347
199
                let connp_ptr = self as *mut Self;
1348
199
                let decompressor = unsafe {
1349
199
                    Decompressor::new_with_callback(
1350
199
                        encoding,
1351
6.97k
                        Box::new(move |data: Option<&[u8]>| -> std::io::Result<usize> {
1352
6.97k
                            (*connp_ptr).response_decompressor_callback(data)
1353
6.97k
                        }),
1354
199
                        compression_options,
1355
0
                    )?
1356
                };
1357
199
                self.response_mut()
1358
199
                    .unwrap()
1359
199
                    .response_decompressor
1360
199
                    .replace(decompressor);
1361
            }
1362
139
        }
1363
349
        Ok(())
1364
349
    }
1365
1366
    /// Finalizes response parsing.
1367
967k
    pub(crate) fn response_finalize(&mut self, input: &mut ParserData) -> Result<()> {
1368
967k
        if input.is_gap() {
1369
3
            return self.state_response_complete(input);
1370
967k
        }
1371
967k
        let mut work = input.as_slice();
1372
967k
        if self.response_status != HtpStreamState::CLOSED {
1373
963k
            let response_next_byte = input.as_slice().first();
1374
963k
            if response_next_byte.is_none() {
1375
370k
                return self.state_response_complete(input);
1376
593k
            }
1377
593k
            let lf = response_next_byte
1378
593k
                .map(|byte| *byte == b'\n')
1379
593k
                .unwrap_or(false);
1380
593k
            if !lf {
1381
589k
                if let Ok((_, line)) = take_till_lf(work) {
1382
586k
                    self.response_data_consume(input, line.len());
1383
586k
                    work = line;
1384
586k
                } else {
1385
3.28k
                    return self.handle_response_absent_lf(input);
1386
                }
1387
3.64k
            } else {
1388
3.64k
                self.response_data_consume(input, work.len());
1389
3.64k
            }
1390
3.44k
        }
1391
593k
        if !self.response_buf.is_empty() {
1392
1.70k
            self.check_response_buffer_limit(work.len())?;
1393
592k
        }
1394
593k
        let mut data = take(&mut self.response_buf);
1395
593k
        let buf_len = data.len();
1396
593k
        data.add(work);
1397
1398
593k
        if data.is_empty() {
1399
            //closing
1400
3.36k
            return self.state_response_complete(input);
1401
590k
        }
1402
590k
        if treat_response_line_as_body(&data) {
1403
            // Interpret remaining bytes as body data
1404
582k
            htp_warn!(
1405
582k
                self.logger,
1406
582k
                HtpLogCode::RESPONSE_BODY_UNEXPECTED,
1407
582k
                "Unexpected response body"
1408
582k
            );
1409
582k
            return self.response_body_data(Some(data.as_slice()));
1410
7.56k
        }
1411
        // didnt use data, restore
1412
7.56k
        self.response_buf.add(&data[0..buf_len]);
1413
        //unread last end of line so that RES_LINE works
1414
7.56k
        self.response_data_unconsume(input, data.len());
1415
7.56k
        self.state_response_complete(input)
1416
967k
    }
1417
1418
    /// The response idle state will initialize response processing, as well as
1419
    /// finalize each transactions after we are done with it.
1420
    ///
1421
    /// Returns HtpStatus::OK on state change, HtpStatus::ERROR on error, or HtpStatus::DATA
1422
    /// when more data is needed.
1423
754k
    pub(crate) fn response_idle(&mut self, input: &ParserData) -> Result<()> {
1424
        // We want to start parsing the next response (and change
1425
        // the state from IDLE) only if there's at least one
1426
        // byte of data available. Otherwise we could be creating
1427
        // new structures even if there's no more data on the
1428
        // connection.
1429
754k
        if input.is_empty() {
1430
372k
            return Err(HtpStatus::DATA);
1431
382k
        }
1432
1433
        // Parsing a new response
1434
        // Log if we have not seen the corresponding request yet
1435
382k
        let resp = self.response();
1436
382k
        if resp.is_none() {
1437
8
            return Err(HtpStatus::ERROR);
1438
382k
        }
1439
382k
        if resp.unwrap().request_progress == HtpRequestProgress::NOT_STARTED {
1440
342k
            htp_error!(
1441
342k
                self.logger,
1442
342k
                HtpLogCode::UNABLE_TO_MATCH_RESPONSE_TO_REQUEST,
1443
342k
                "Unable to match response to request"
1444
342k
            );
1445
342k
            if self.request_state == State::Finalize {
1446
2.70k
                let _ = self.state_request_complete(&mut ParserData::from(None));
1447
340k
            }
1448
342k
            let tx = self.response_mut();
1449
342k
            if tx.is_none() {
1450
0
                return Err(HtpStatus::ERROR);
1451
342k
            }
1452
342k
            let tx = tx.unwrap();
1453
1454
342k
            let uri = Uri {
1455
342k
                path: Some(Bstr::from("/libhtp::request_uri_not_seen")),
1456
342k
                ..Default::default()
1457
342k
            };
1458
342k
            tx.request_uri = uri.path.clone();
1459
342k
            tx.parsed_uri = Some(uri);
1460
342k
            tx.request_progress = HtpRequestProgress::COMPLETE;
1461
342k
            self.request_next();
1462
39.8k
        }
1463
382k
        self.response_content_length = None;
1464
382k
        self.response_body_data_left = None;
1465
382k
        self.state_response_start()
1466
754k
    }
1467
1468
    /// Run the RESPONSE_BODY_DATA hook.
1469
2.27M
    fn response_run_hook_body_data(&mut self, d: &mut Data) -> Result<()> {
1470
        // Do not invoke callbacks with an empty data chunk.
1471
2.27M
        if d.is_empty() {
1472
366k
            return Ok(());
1473
1.90M
        }
1474
1.90M
        let resp = self.response().unwrap();
1475
        // Run transaction hooks first
1476
1.90M
        resp.hook_response_body_data.clone().run_all(self, d)?;
1477
        // Run configuration hooks second
1478
1.90M
        self.cfg.hook_response_body_data.run_all(self, d)?;
1479
1.90M
        Ok(())
1480
2.27M
    }
1481
1482
    /// Process a chunk of outbound (server or response) data.
1483
940k
    pub(crate) fn response_data(
1484
940k
        &mut self, mut chunk: ParserData, timestamp: Option<OffsetDateTime>,
1485
940k
    ) -> HtpStreamState {
1486
        // Reset consumed data tracker
1487
940k
        self.response_bytes_consumed = 0;
1488
1489
        // Return if the connection is in stop state
1490
940k
        if self.response_status == HtpStreamState::STOP {
1491
0
            htp_info!(
1492
0
                self.logger,
1493
0
                HtpLogCode::PARSER_STATE_ERROR,
1494
0
                "Outbound parser is in HTP_STREAM_STATE_STOP"
1495
0
            );
1496
0
            return HtpStreamState::STOP;
1497
940k
        }
1498
        // Return if the connection has had a fatal error
1499
940k
        if self.response_status == HtpStreamState::ERROR {
1500
28
            htp_error!(
1501
28
                self.logger,
1502
28
                HtpLogCode::PARSER_STATE_ERROR,
1503
28
                "Outbound parser is in HTP_STREAM_STATE_ERROR"
1504
28
            );
1505
28
            return HtpStreamState::ERROR;
1506
940k
        }
1507
1508
        // If the length of the supplied data chunk is zero, proceed
1509
        // only if the stream has been closed. We do not allow zero-sized
1510
        // chunks in the API, but we use it internally to force the parsers
1511
        // to finalize parsing.
1512
940k
        if chunk.is_empty() && self.response_status != HtpStreamState::CLOSED {
1513
0
            htp_error!(
1514
0
                self.logger,
1515
0
                HtpLogCode::ZERO_LENGTH_DATA_CHUNKS,
1516
0
                "Zero-length data chunks are not allowed"
1517
0
            );
1518
0
            return HtpStreamState::CLOSED;
1519
940k
        }
1520
        // Remember the timestamp of the current response data chunk
1521
940k
        if let Some(timestamp) = timestamp {
1522
940k
            self.response_timestamp = timestamp;
1523
940k
        }
1524
1525
        // Store the current chunk information
1526
940k
        self.conn.track_outbound_data(chunk.len());
1527
        // Return without processing any data if the stream is in tunneling
1528
        // mode (which it would be after an initial CONNECT transaction.
1529
940k
        if self.response_status == HtpStreamState::TUNNEL {
1530
2.25k
            return HtpStreamState::TUNNEL;
1531
938k
        }
1532
938k
        if chunk.is_gap() {
1533
            // Mark the transaction as having a gap
1534
52
            let idx = self.request_index();
1535
52
            let resp = self.response_mut();
1536
52
            if resp.is_none() {
1537
0
                return HtpStreamState::ERROR;
1538
52
            }
1539
52
            let resp = resp.unwrap();
1540
1541
52
            resp.flags.set(HtpFlags::RESPONSE_MISSING_BYTES);
1542
1543
52
            if idx == 0 && resp.response_progress == HtpResponseProgress::NOT_STARTED {
1544
                // We have a leading gap on the first transaction.
1545
4
                return HtpStreamState::CLOSED;
1546
48
            }
1547
937k
        }
1548
1549
        loop
1550
        // Invoke a processor, in a loop, until an error
1551
        // occurs or until we run out of data. Many processors
1552
        // will process a request, each pointing to the next
1553
        // processor that needs to run.
1554
        // Return if there's been an error
1555
        // or if we've run out of data. We are relying
1556
        // on processors to add error messages, so we'll
1557
        // keep quiet here.
1558
        {
1559
5.15M
            if chunk.is_gap()
1560
51
                && self.response_state != State::BodyIdentityCLKnown
1561
51
                && self.response_state != State::BodyIdentityStreamClose
1562
22
                && self.response_state != State::Finalize
1563
            {
1564
19
                htp_error!(
1565
19
                    self.logger,
1566
19
                    HtpLogCode::INVALID_GAP,
1567
19
                    "Gaps are not allowed during this state"
1568
19
                );
1569
19
                return HtpStreamState::CLOSED;
1570
5.15M
            }
1571
5.15M
            let mut rc = self.handle_response_state(&mut chunk);
1572
1573
5.15M
            if rc.is_ok() {
1574
4.21M
                if self.response_status == HtpStreamState::TUNNEL {
1575
40
                    return HtpStreamState::TUNNEL;
1576
4.21M
                }
1577
4.21M
                rc = self.response_handle_state_change(&mut chunk);
1578
937k
            }
1579
937k
            match rc {
1580
                // Continue looping.
1581
4.21M
                Ok(_) => {}
1582
                // Do we need more data?
1583
                Err(HtpStatus::DATA) | Err(HtpStatus::DATA_BUFFER) => {
1584
                    // Ignore result.
1585
936k
                    let _ = self.response_receiver_send_data(&mut chunk);
1586
936k
                    self.response_status = HtpStreamState::DATA;
1587
936k
                    return HtpStreamState::DATA;
1588
                }
1589
                // Check for stop
1590
                Err(HtpStatus::STOP) => {
1591
0
                    self.response_status = HtpStreamState::STOP;
1592
0
                    return HtpStreamState::STOP;
1593
                }
1594
                // Check for suspended parsing
1595
                Err(HtpStatus::DATA_OTHER) => {
1596
                    // We might have actually consumed the entire data chunk?
1597
1.72k
                    if chunk.is_empty() {
1598
1.69k
                        self.response_status = HtpStreamState::DATA;
1599
                        // Do not send STREAM_DATE_DATA_OTHER if we've
1600
                        // consumed the entire chunk
1601
1.69k
                        return HtpStreamState::DATA;
1602
                    } else {
1603
29
                        self.response_status = HtpStreamState::DATA_OTHER;
1604
                        // Partial chunk consumption
1605
29
                        return HtpStreamState::DATA_OTHER;
1606
                    }
1607
                }
1608
                // Permanent stream error.
1609
                Err(_) => {
1610
85
                    self.response_status = HtpStreamState::ERROR;
1611
85
                    return HtpStreamState::ERROR;
1612
                }
1613
            }
1614
        }
1615
940k
    }
1616
1617
    /// Advance out buffer cursor and buffer data.
1618
309k
    fn handle_response_absent_lf(&mut self, data: &ParserData) -> Result<()> {
1619
309k
        self.check_response_buffer_limit(data.len())?;
1620
309k
        self.response_buf.add(data.as_slice());
1621
309k
        self.response_data_consume(data, data.len());
1622
309k
        Err(HtpStatus::DATA_BUFFER)
1623
309k
    }
1624
}