Coverage Report

Created: 2026-02-14 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/libhtp/htp/htp_response.c
Line
Count
Source
1
/***************************************************************************
2
 * Copyright (c) 2009-2010 Open Information Security Foundation
3
 * Copyright (c) 2010-2013 Qualys, Inc.
4
 * All rights reserved.
5
 * 
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions are
8
 * met:
9
 * 
10
 * - Redistributions of source code must retain the above copyright
11
 *   notice, this list of conditions and the following disclaimer.
12
13
 * - Redistributions in binary form must reproduce the above copyright
14
 *   notice, this list of conditions and the following disclaimer in the
15
 *   documentation and/or other materials provided with the distribution.
16
17
 * - Neither the name of the Qualys, Inc. nor the names of its
18
 *   contributors may be used to endorse or promote products derived from
19
 *   this software without specific prior written permission.
20
 * 
21
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
 ***************************************************************************/
33
34
/**
35
 * @file
36
 * @author Ivan Ristic <ivanr@webkreator.com>
37
 */
38
39
#include "htp_config_auto.h"
40
41
#include "htp_private.h"
42
43
158k
#define OUT_TEST_NEXT_BYTE_OR_RETURN(X) \
44
158k
if ((X)->out_current_read_offset >= (X)->out_current_len) { \
45
65.8k
    return HTP_DATA; \
46
65.8k
}
47
48
1.73M
#define OUT_PEEK_NEXT(X) \
49
1.73M
if ((X)->out_current_read_offset >= (X)->out_current_len) { \
50
89.4k
    (X)->out_next_byte = -1; \
51
1.64M
} else { \
52
1.64M
    (X)->out_next_byte = (X)->out_current_data[(X)->out_current_read_offset]; \
53
1.64M
}
54
55
#define OUT_NEXT_BYTE(X) \
56
if ((X)->out_current_read_offset < (X)->out_current_len) { \
57
    (X)->out_next_byte = (X)->out_current_data[(X)->out_current_read_offset]; \
58
    (X)->out_current_read_offset++; \
59
    (X)->out_current_consume_offset++; \
60
    (X)->out_stream_offset++; \
61
} else { \
62
    (X)->out_next_byte = -1; \
63
}
64
65
148k
#define OUT_NEXT_BYTE_OR_RETURN(X) \
66
148k
if ((X)->out_current_read_offset < (X)->out_current_len) { \
67
147k
    (X)->out_next_byte = (X)->out_current_data[(X)->out_current_read_offset]; \
68
147k
    (X)->out_current_read_offset++; \
69
147k
    (X)->out_current_consume_offset++; \
70
147k
    (X)->out_stream_offset++; \
71
147k
} else { \
72
708
    return HTP_DATA; \
73
708
}
74
75
58.5M
#define OUT_COPY_BYTE_OR_RETURN(X) \
76
58.5M
if ((X)->out_current_read_offset < (X)->out_current_len) { \
77
58.3M
    (X)->out_next_byte = (X)->out_current_data[(X)->out_current_read_offset]; \
78
58.3M
    (X)->out_current_read_offset++; \
79
58.3M
    (X)->out_stream_offset++; \
80
58.3M
} else { \
81
157k
    return HTP_DATA_BUFFER; \
82
157k
}
83
84
94.7k
#define REQUEST_URI_NOT_SEEN "/libhtp::request_uri_not_seen"
85
86
/**
87
 * Sends outstanding connection data to the currently active data receiver hook.
88
 *
89
 * @param[in] connp
90
 * @param[in] is_last
91
 * @return HTP_OK, or a value returned from a callback.
92
 */
93
348k
static htp_status_t htp_connp_res_receiver_send_data(htp_connp_t *connp, int is_last) {
94
348k
    if (connp->out_data_receiver_hook == NULL) return HTP_OK;
95
96
109k
    htp_tx_data_t d;
97
109k
    d.tx = connp->out_tx;
98
109k
    d.data = connp->out_current_data + connp->out_current_receiver_offset;
99
109k
    d.len = connp->out_current_read_offset - connp->out_current_receiver_offset;
100
109k
    d.is_last = is_last;
101
102
109k
    htp_status_t rc = htp_hook_run_all(connp->out_data_receiver_hook, &d);
103
109k
    if (rc != HTP_OK) return rc;
104
105
109k
    connp->out_current_receiver_offset = connp->out_current_read_offset;
106
107
109k
    return HTP_OK;
108
109k
}
109
110
/**
111
 * Finalizes an existing data receiver hook by sending any outstanding data to it. The
112
 * hook is then removed so that it receives no more data.
113
 *
114
 * @param[in] connp
115
 * @return HTP_OK, or a value returned from a callback.
116
 */
117
194k
htp_status_t htp_connp_res_receiver_finalize_clear(htp_connp_t *connp) {
118
194k
    if (connp->out_data_receiver_hook == NULL) return HTP_OK;
119
120
54.9k
    htp_status_t rc = htp_connp_res_receiver_send_data(connp, 1 /* last */);
121
122
54.9k
    connp->out_data_receiver_hook = NULL;
123
124
54.9k
    return rc;
125
194k
}
126
127
/**
128
 * Configures the data receiver hook. If there is a previous hook, it will be finalized and cleared.
129
 *
130
 * @param[in] connp
131
 * @param[in] data_receiver_hook
132
 * @return HTP_OK, or a value returned from a callback.
133
 */
134
55.8k
static htp_status_t htp_connp_res_receiver_set(htp_connp_t *connp, htp_hook_t *data_receiver_hook) {
135
55.8k
    htp_status_t rc = htp_connp_res_receiver_finalize_clear(connp);
136
137
55.8k
    connp->out_data_receiver_hook = data_receiver_hook;
138
55.8k
    connp->out_current_receiver_offset = connp->out_current_read_offset;
139
140
55.8k
    return rc;
141
55.8k
}
142
143
/**
144
 * Handles request parser state changes. At the moment, this function is used only
145
 * to configure data receivers, which are sent raw connection data.
146
 *
147
 * @param[in] connp
148
 * @return HTP_OK, or a value returned from a callback.
149
 */
150
1.27M
static htp_status_t htp_res_handle_state_change(htp_connp_t *connp) {
151
1.27M
    if (connp->out_state_previous == connp->out_state) return HTP_OK;
152
153
427k
    if (connp->out_state == htp_connp_RES_HEADERS) {
154
55.8k
        htp_status_t rc = HTP_OK;
155
156
55.8k
        switch (connp->out_tx->response_progress) {
157
47.7k
            case HTP_RESPONSE_HEADERS:
158
47.7k
                rc = htp_connp_res_receiver_set(connp, connp->out_tx->cfg->hook_response_header_data);
159
47.7k
                break;
160
161
8.07k
            case HTP_RESPONSE_TRAILER:
162
8.07k
                rc = htp_connp_res_receiver_set(connp, connp->out_tx->cfg->hook_response_trailer_data);
163
8.07k
                break;
164
165
0
            default:
166
                // Do nothing; receivers are currently used only for header blocks.
167
0
                break;
168
55.8k
        }
169
170
55.8k
        if (rc != HTP_OK) return rc;
171
55.8k
    }
172
173
    // Same comment as in htp_req_handle_state_change(). Below is a copy.
174
175
    // Initially, I had the finalization of raw data sending here, but that
176
    // caused the last REQUEST_HEADER_DATA hook to be invoked after the
177
    // REQUEST_HEADERS hook -- which I thought made no sense. For that reason,
178
    // the finalization is now initiated from the request header processing code,
179
    // which is less elegant but provides a better user experience. Having some
180
    // (or all) hooks to be invoked on state change might work better.
181
182
427k
    connp->out_state_previous = connp->out_state;
183
184
427k
    return HTP_OK;
185
427k
}
186
187
/**
188
 * If there is any data left in the outbound data chunk, this function will preserve
189
 * it for later consumption. The maximum amount accepted for buffering is controlled
190
 * by htp_config_t::field_limit_hard.
191
 *
192
 * @param[in] connp
193
 * @return HTP_OK, or HTP_ERROR on fatal failure.
194
 */
195
232k
static htp_status_t htp_connp_res_buffer(htp_connp_t *connp) {
196
232k
    if (connp->out_current_data == NULL) return HTP_OK;
197
    
198
230k
    unsigned char *data = connp->out_current_data + connp->out_current_consume_offset;
199
230k
    size_t len = connp->out_current_read_offset - connp->out_current_consume_offset;
200
201
    // Check the hard (buffering) limit.
202
203
230k
    size_t newlen = connp->out_buf_size + len;   
204
205
    // When calculating the size of the buffer, take into account the
206
    // space we're using for the response header buffer.
207
230k
    if (connp->out_header != NULL) {
208
20.2k
        newlen += bstr_len(connp->out_header);
209
20.2k
    }
210
211
230k
    if (newlen > connp->out_tx->cfg->field_limit_hard) {
212
20
        htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Response the buffer limit: size %zd limit %zd.",
213
20
                newlen, connp->out_tx->cfg->field_limit_hard);
214
20
        return HTP_ERROR;
215
20
    }
216
217
    // Copy the data remaining in the buffer.
218
219
230k
    if (connp->out_buf == NULL) {
220
73.2k
        connp->out_buf = malloc(len);
221
73.2k
        if (connp->out_buf == NULL) return HTP_ERROR;
222
73.2k
        memcpy(connp->out_buf, data, len);
223
73.2k
        connp->out_buf_size = len;
224
157k
    } else {
225
157k
        size_t newsize = connp->out_buf_size + len;
226
157k
        unsigned char *newbuf = realloc(connp->out_buf, newsize);
227
157k
        if (newbuf == NULL) return HTP_ERROR;
228
157k
        connp->out_buf = newbuf;
229
157k
        memcpy(connp->out_buf + connp->out_buf_size, data, len);
230
157k
        connp->out_buf_size = newsize;
231
157k
    }
232
233
    // Reset the consumer position.
234
230k
    connp->out_current_consume_offset = connp->out_current_read_offset;
235
236
230k
    return HTP_OK;
237
230k
}
238
239
/**
240
 * Returns to the caller the memory region that should be processed next. This function
241
 * hides away the buffering process from the rest of the code, allowing it to work with
242
 * non-buffered data that's in the outbound chunk, or buffered data that's in our structures.
243
 *
244
 * @param[in] connp
245
 * @param[out] data
246
 * @param[out] len
247
 * @return HTP_OK
248
 */
249
1.47M
static htp_status_t htp_connp_res_consolidate_data(htp_connp_t *connp, unsigned char **data, size_t *len) {    
250
1.47M
    if (connp->out_buf == NULL) {
251
        // We do not have any data buffered; point to the current data chunk.
252
1.39M
        *data = connp->out_current_data + connp->out_current_consume_offset;
253
1.39M
        *len = connp->out_current_read_offset - connp->out_current_consume_offset;
254
1.39M
    } else {
255
        // We do have data in the buffer. Add data from the current
256
        // chunk, and point to the consolidated buffer.
257
72.8k
        if (htp_connp_res_buffer(connp) != HTP_OK) {
258
13
            return HTP_ERROR;
259
13
        }
260
261
72.8k
        *data = connp->out_buf;
262
72.8k
        *len = connp->out_buf_size;
263
72.8k
    }
264
265
1.47M
    return HTP_OK;
266
1.47M
}
267
268
/**
269
 * Clears buffered outbound data and resets the consumer position to the reader position.
270
 *
271
 * @param[in] connp
272
 */
273
1.43M
static void htp_connp_res_clear_buffer(htp_connp_t *connp) {
274
1.43M
    connp->out_current_consume_offset = connp->out_current_read_offset;
275
276
1.43M
    if (connp->out_buf != NULL) {
277
70.1k
        free(connp->out_buf);
278
70.1k
        connp->out_buf = NULL;
279
70.1k
        connp->out_buf_size = 0;
280
70.1k
    }
281
1.43M
}
282
283
/**
284
 * Consumes bytes until the end of the current line.
285
 *
286
 * @param[in] connp
287
 * @returns HTP_OK on state change, HTP_ERROR on error, or HTP_DATA when more data is needed.
288
 */
289
11.7k
htp_status_t htp_connp_RES_BODY_CHUNKED_DATA_END(htp_connp_t *connp) {
290
    // TODO We shouldn't really see anything apart from CR and LF,
291
    //      so we should warn about anything else.
292
11.7k
    if (connp->out_status == HTP_STREAM_CLOSED) {
293
19
        connp->out_state = htp_connp_RES_FINALIZE;
294
        // Sends close signal to decompressors
295
19
        htp_status_t rc = htp_tx_res_process_body_data_ex(connp->out_tx, NULL, 0);
296
19
        return rc;
297
19
    }
298
299
148k
    for (;;) {
300
148k
        OUT_NEXT_BYTE_OR_RETURN(connp);
301
302
147k
        connp->out_tx->response_message_len++;
303
304
147k
        if (connp->out_next_byte == LF) {
305
11.0k
            connp->out_state = htp_connp_RES_BODY_CHUNKED_LENGTH;
306
307
11.0k
            return HTP_OK;
308
11.0k
        }
309
147k
    }
310
311
0
    return HTP_ERROR;
312
11.7k
}
313
314
/**
315
 * Processes a chunk of data.
316
 *
317
 * @param[in] connp
318
 * @returns HTP_OK on state change, HTP_ERROR on error, or HTP_DATA when more data is needed.
319
 */
320
14.4k
htp_status_t htp_connp_RES_BODY_CHUNKED_DATA(htp_connp_t *connp) {
321
14.4k
    size_t bytes_to_consume;
322
323
    // Determine how many bytes we can consume.
324
14.4k
    if (connp->out_current_len - connp->out_current_read_offset >= connp->out_chunked_length) {
325
11.0k
        bytes_to_consume = connp->out_chunked_length;
326
11.0k
    } else {
327
3.31k
        bytes_to_consume = connp->out_current_len - connp->out_current_read_offset;
328
3.31k
    }
329
330
14.4k
    if (connp->out_status == HTP_STREAM_CLOSED) {
331
53
        connp->out_state = htp_connp_RES_FINALIZE;
332
        // Sends close signal to decompressors
333
53
        htp_status_t rc = htp_tx_res_process_body_data_ex(connp->out_tx, NULL, 0);
334
53
        return rc;
335
53
    }
336
14.3k
    if (bytes_to_consume == 0) return HTP_DATA;
337
338
    // Consume the data.
339
14.0k
    htp_status_t rc = htp_tx_res_process_body_data_ex(connp->out_tx, connp->out_current_data + connp->out_current_read_offset, bytes_to_consume);
340
14.0k
    if (rc != HTP_OK) return rc;
341
342
    // Adjust the counters.
343
14.0k
    connp->out_current_read_offset += bytes_to_consume;
344
14.0k
    connp->out_current_consume_offset += bytes_to_consume;
345
14.0k
    connp->out_stream_offset += bytes_to_consume;
346
14.0k
    connp->out_chunked_length -= bytes_to_consume;
347
348
    // Have we seen the entire chunk?
349
14.0k
    if (connp->out_chunked_length == 0) {
350
11.0k
        connp->out_state = htp_connp_RES_BODY_CHUNKED_DATA_END;
351
11.0k
        return HTP_OK;
352
11.0k
    }
353
354
2.93k
    return HTP_DATA;
355
14.0k
}
356
357
5.72M
static inline int is_chunked_ctl_char(const unsigned char c) {
358
5.72M
    switch (c) {
359
1.12M
        case 0x0d:
360
1.12M
        case 0x0a:
361
1.15M
        case 0x20:
362
4.38M
        case 0x09:
363
4.57M
        case 0x0b:
364
4.59M
        case 0x0c:
365
4.59M
            return 1;
366
1.13M
        default:
367
1.13M
            return 0;
368
5.72M
    }
369
5.72M
}
370
371
/**
372
 * Peeks ahead into the data to try to see if it starts with a valid Chunked
373
 * length field.
374
 *
375
 * @returns 1 if it looks valid, 0 if it looks invalid
376
 */
377
565k
static inline int data_probe_chunk_length(htp_connp_t *connp) {
378
565k
    unsigned char *data = connp->out_current_data + connp->out_current_consume_offset;
379
565k
    size_t len = connp->out_current_read_offset - connp->out_current_consume_offset;
380
381
565k
    size_t i = 0;
382
5.09M
    while (i < len) {
383
5.09M
        unsigned char c = data[i];
384
385
5.09M
        if (is_chunked_ctl_char(c)) {
386
            // ctl char, still good.
387
4.53M
        } else if (isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
388
            // real chunklen char
389
478k
            return 1;
390
478k
        } else {
391
            // leading junk, bad
392
86.6k
            return 0;
393
86.6k
        }
394
4.53M
        i++;
395
4.53M
    }
396
0
    return 1;
397
565k
}
398
399
/**
400
 * Extracts chunk length.
401
 *
402
 * @param[in] connp
403
 * @returns HTP_OK on state change, HTP_ERROR on error, or HTP_DATA when more data is needed.
404
 */
405
22.5k
htp_status_t htp_connp_RES_BODY_CHUNKED_LENGTH(htp_connp_t *connp) {
406
22.5k
    if (connp->out_status == HTP_STREAM_CLOSED) {
407
46
        connp->out_state = htp_connp_RES_FINALIZE;
408
        // Sends close signal to decompressors
409
46
        htp_status_t rc = htp_tx_res_process_body_data_ex(connp->out_tx, NULL, 0);
410
46
        return rc;
411
46
    }
412
413
645k
    for (;;) {
414
645k
        OUT_COPY_BYTE_OR_RETURN(connp);
415
416
        // Have we reached the end of the line? Or is this not chunked after all?
417
642k
        if (connp->out_next_byte == LF ||
418
621k
                (!is_chunked_ctl_char((unsigned char) connp->out_next_byte) && !data_probe_chunk_length(connp) && connp->out_buf == NULL)) {
419
21.3k
            unsigned char *data;
420
21.3k
            size_t len;
421
422
21.3k
            if (htp_connp_res_consolidate_data(connp, &data, &len) != HTP_OK) {
423
2
                return HTP_ERROR;
424
2
            }
425
426
21.2k
            connp->out_tx->response_message_len += len;
427
428
            #ifdef HTP_DEBUG
429
            fprint_raw_data(stderr, "Chunk length line", data, len);
430
            #endif
431
432
21.2k
            int chunk_ext = 0;
433
21.2k
            connp->out_chunked_length = htp_parse_chunked_length(data, len, &chunk_ext);
434
21.2k
            if (chunk_ext == 1) {
435
2.61k
                htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Request chunk extension");
436
2.61k
            }
437
            // empty chunk length line, lets try to continue
438
21.2k
            if (connp->out_chunked_length == -1004) {
439
1.80k
                connp->out_current_consume_offset = connp->out_current_read_offset;
440
1.80k
                continue;
441
1.80k
            }
442
19.4k
            if (connp->out_chunked_length < 0) {
443
                // reset out_current_read_offset so htp_connp_RES_BODY_IDENTITY_STREAM_CLOSE
444
                // doesn't miss the first bytes
445
446
199
                if (len > (size_t)connp->out_current_read_offset) {
447
10
                    connp->out_current_read_offset = 0;
448
189
                } else {
449
189
                    connp->out_current_read_offset -= len;
450
189
                }
451
452
199
                connp->out_state = htp_connp_RES_BODY_IDENTITY_STREAM_CLOSE;
453
199
                connp->out_tx->response_transfer_coding = HTP_CODING_IDENTITY;
454
455
199
                htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0,
456
199
                        "Response chunk encoding: Invalid chunk length: %"PRId64"",
457
199
                        connp->out_chunked_length);
458
199
                return HTP_OK;
459
199
            }
460
19.2k
            htp_connp_res_clear_buffer(connp);
461
462
            // Handle chunk length
463
19.2k
            if (connp->out_chunked_length > 0) {
464
                // More data available
465
11.2k
                connp->out_state = htp_connp_RES_BODY_CHUNKED_DATA;
466
11.2k
            } else if (connp->out_chunked_length == 0) {
467
                // End of data
468
8.07k
                connp->out_state = htp_connp_RES_HEADERS;
469
8.07k
                connp->out_tx->response_progress = HTP_RESPONSE_TRAILER;
470
8.07k
            }
471
472
19.2k
            return HTP_OK;
473
19.4k
        }
474
642k
    }
475
476
0
    return HTP_ERROR;
477
22.4k
}
478
479
/**
480
 * Processes an identity response body of known length.
481
 *
482
 * @param[in] connp
483
 * @returns HTP_OK on state change, HTP_ERROR on error, or HTP_DATA when more data is needed.
484
 */
485
24.1k
htp_status_t htp_connp_RES_BODY_IDENTITY_CL_KNOWN(htp_connp_t *connp) {
486
24.1k
    size_t bytes_to_consume;   
487
        
488
    // Determine how many bytes we can consume.
489
24.1k
    if (connp->out_current_len - connp->out_current_read_offset >= connp->out_body_data_left) {
490
12.1k
        bytes_to_consume = connp->out_body_data_left;
491
12.1k
    } else {
492
12.0k
        bytes_to_consume = connp->out_current_len - connp->out_current_read_offset;
493
12.0k
    }       
494
    
495
24.1k
    if (connp->out_status == HTP_STREAM_CLOSED) {
496
146
        connp->out_state = htp_connp_RES_FINALIZE;
497
        // Sends close signal to decompressors
498
146
        htp_status_t rc = htp_tx_res_process_body_data_ex(connp->out_tx, NULL, 0);
499
146
        return rc;
500
146
    }
501
23.9k
    if (bytes_to_consume == 0) return HTP_DATA;    
502
503
    // Consume the data.
504
23.0k
    htp_status_t rc = htp_tx_res_process_body_data_ex(connp->out_tx, connp->out_current_data + connp->out_current_read_offset, bytes_to_consume);
505
23.0k
    if (rc != HTP_OK) return rc;
506
507
    // Adjust the counters.
508
23.0k
    connp->out_current_read_offset += bytes_to_consume;
509
23.0k
    connp->out_current_consume_offset += bytes_to_consume;
510
23.0k
    connp->out_stream_offset += bytes_to_consume;
511
23.0k
    connp->out_body_data_left -= bytes_to_consume;
512
513
    // Have we seen the entire response body?
514
23.0k
    if (connp->out_body_data_left == 0) {
515
12.1k
        connp->out_state = htp_connp_RES_FINALIZE;
516
        // Tells decompressors to output partially decompressed data
517
12.1k
        rc = htp_tx_res_process_body_data_ex(connp->out_tx, NULL, 0);
518
12.1k
        return rc;
519
12.1k
    }
520
521
10.9k
    return HTP_DATA;
522
23.0k
}
523
524
/**
525
 * Processes identity response body of unknown length. In this case, we assume the
526
 * response body consumes all data until the end of the stream.
527
 *
528
 * @param[in] connp
529
 * @returns HTP_OK on state change, HTP_ERROR on error, or HTP_DATA when more data is needed.
530
 */
531
53.4k
htp_status_t htp_connp_RES_BODY_IDENTITY_STREAM_CLOSE(htp_connp_t *connp) {        
532
    // Consume all data from the input buffer.
533
53.4k
    size_t bytes_to_consume = connp->out_current_len - connp->out_current_read_offset;
534
535
    #ifdef HTP_DEBUG
536
    fprintf(stderr, "bytes_to_consume %"PRIuMAX, (uintmax_t)bytes_to_consume);
537
    #endif
538
53.4k
    if (bytes_to_consume != 0) {
539
50.5k
        htp_status_t rc = htp_tx_res_process_body_data_ex(connp->out_tx, connp->out_current_data + connp->out_current_read_offset, bytes_to_consume);
540
50.5k
        if (rc != HTP_OK) return rc;
541
542
        // Adjust the counters.
543
50.5k
        connp->out_current_read_offset += bytes_to_consume;
544
50.5k
        connp->out_current_consume_offset += bytes_to_consume;
545
50.5k
        connp->out_stream_offset += bytes_to_consume;        
546
50.5k
    }
547
548
    // Have we seen the entire response body?
549
53.4k
    if (connp->out_status == HTP_STREAM_CLOSED) {
550
1.27k
        connp->out_state = htp_connp_RES_FINALIZE;
551
1.27k
        return HTP_OK;
552
1.27k
    }
553
   
554
52.1k
    return HTP_DATA;
555
53.4k
}
556
557
/**
558
 * Determines presence (and encoding) of a response body.
559
 *
560
 * @param[in] connp
561
 * @returns HTP_OK on state change, HTP_ERROR on error, or HTP_DATA when more data is needed.
562
 */
563
45.6k
htp_status_t htp_connp_RES_BODY_DETERMINE(htp_connp_t *connp) {
564
    // If the request uses the CONNECT method, then not only are we
565
    // to assume there's no body, but we need to ignore all
566
    // subsequent data in the stream.
567
45.6k
    if (connp->out_tx->request_method_number == HTP_M_CONNECT) {
568
2.21k
        if ((connp->out_tx->response_status_number >= 200)
569
2.04k
                && (connp->out_tx->response_status_number <= 299)) {
570
            // This is a successful CONNECT stream, which means
571
            // we need to switch into tunneling mode: on the
572
            // request side we'll now probe the tunnel data to see
573
            // if we need to parse or ignore it. So on the response
574
            // side we wrap up the tx and wait.
575
2.03k
            connp->out_state = htp_connp_RES_FINALIZE;
576
577
            // we may have response headers
578
2.03k
            htp_status_t rc = htp_tx_state_response_headers(connp->out_tx);
579
2.03k
            return rc;
580
2.03k
        } else if (connp->out_tx->response_status_number == 407) {
581
            // proxy telling us to auth
582
0
            if (connp->in_status != HTP_STREAM_ERROR)
583
0
                connp->in_status = HTP_STREAM_DATA;
584
184
        } else {
585
            // This is a failed CONNECT stream, which means that
586
            // we can unblock request parsing
587
184
            if (connp->in_status != HTP_STREAM_ERROR)
588
184
                connp->in_status = HTP_STREAM_DATA;
589
590
            // We are going to continue processing this transaction,
591
            // adding a note for ourselves to stop at the end (because
592
            // we don't want to see the beginning of a new transaction).
593
184
            connp->out_data_other_at_tx_end = 1;
594
184
        }
595
2.21k
    }
596
597
43.6k
    htp_header_t *cl = htp_table_get_c(connp->out_tx->response_headers, "content-length");
598
43.6k
    htp_header_t *te = htp_table_get_c(connp->out_tx->response_headers, "transfer-encoding");
599
600
    // Check for "101 Switching Protocol" response.
601
    // If it's seen, it means that traffic after empty line following headers
602
    // is no longer HTTP. We can treat it similarly to CONNECT.
603
    // Unlike CONNECT, however, upgrades from HTTP to HTTP seem
604
    // rather unlikely, so don't try to probe tunnel for nested HTTP,
605
    // and switch to tunnel mode right away.
606
43.6k
    if (connp->out_tx->response_status_number == 101) {
607
827
        if (te == NULL && cl == NULL) {
608
413
            connp->out_state = htp_connp_RES_FINALIZE;
609
610
413
            if (connp->in_status != HTP_STREAM_ERROR)
611
413
                connp->in_status = HTP_STREAM_TUNNEL;
612
413
            connp->out_status = HTP_STREAM_TUNNEL;
613
614
            // we may have response headers
615
413
            htp_status_t rc = htp_tx_state_response_headers(connp->out_tx);
616
413
            return rc;
617
414
        } else {
618
414
            htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Switching Protocol with Content-Length");
619
414
        }
620
827
    }
621
622
    // Check for an interim "100 Continue" response. Ignore it if found, and revert back to RES_LINE.
623
43.1k
    if (connp->out_tx->response_status_number == 100 && te == NULL) {
624
2.64k
        int is100continue = 1;
625
2.64k
        if (cl != NULL){
626
383
            if (htp_parse_content_length(cl->value, connp) > 0) {
627
277
                is100continue = 0;
628
277
            }
629
383
        }
630
2.64k
        if (is100continue) {
631
2.36k
            if (connp->out_tx->seen_100continue != 0) {
632
1.27k
                htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Already seen 100-Continue.");
633
1.27k
            }
634
635
            // Ignore any response headers seen so far.
636
2.36k
            htp_header_t *h = NULL;
637
4.52k
            for (size_t i = 0, n = htp_table_size(connp->out_tx->response_headers); i < n; i++) {
638
2.16k
                h = htp_table_get_index(connp->out_tx->response_headers, i, NULL);
639
2.16k
                bstr_free(h->name);
640
2.16k
                bstr_free(h->value);
641
2.16k
                free(h);
642
2.16k
            }
643
644
2.36k
            htp_table_clear(connp->out_tx->response_headers);
645
646
            // Expecting to see another response line next.
647
2.36k
            connp->out_state = htp_connp_RES_LINE;
648
2.36k
            connp->out_tx->response_progress = HTP_RESPONSE_LINE;
649
2.36k
            connp->out_tx->seen_100continue++;
650
651
2.36k
            return HTP_OK;
652
2.36k
        }
653
2.64k
    }
654
655
    // A request can indicate it waits for headers validation
656
    // before sending its body cf
657
    // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expect
658
40.8k
    if (connp->out_tx->response_status_number >= 400 &&
659
3.02k
        connp->out_tx->response_status_number <= 499 &&
660
2.58k
        connp->in_content_length > 0 &&
661
422
        connp->in_body_data_left == connp->in_content_length) {
662
2
        htp_header_t *exp = htp_table_get_c(connp->out_tx->request_headers, "expect");
663
2
        if ((exp != NULL) && (bstr_cmp_c_nocase(exp->value, "100-continue") == 0)) {
664
0
            connp->in_state = htp_connp_REQ_FINALIZE;
665
0
        }
666
2
    }
667
668
    // 1. Any response message which MUST NOT include a message-body
669
    //  (such as the 1xx, 204, and 304 responses and any response to a HEAD
670
    //  request) is always terminated by the first empty line after the
671
    //  header fields, regardless of the entity-header fields present in the
672
    //  message.
673
40.8k
    if (connp->out_tx->request_method_number == HTP_M_HEAD) {
674
        // There's no response body whatsoever
675
0
        connp->out_tx->response_transfer_coding = HTP_CODING_NO_BODY;
676
0
        connp->out_state = htp_connp_RES_FINALIZE;
677
0
    }
678
40.8k
    else if (((connp->out_tx->response_status_number >= 100) && (connp->out_tx->response_status_number <= 199))
679
31.0k
            || (connp->out_tx->response_status_number == 204) || (connp->out_tx->response_status_number == 304)) {
680
        // There should be no response body
681
        // but browsers interpret content sent by the server as such
682
12.0k
        if (te == NULL && cl == NULL) {
683
10.6k
            connp->out_tx->response_transfer_coding = HTP_CODING_NO_BODY;
684
10.6k
            connp->out_state = htp_connp_RES_FINALIZE;
685
10.6k
        } else {
686
1.42k
            htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Unexpected Response body");
687
1.42k
        }
688
12.0k
    }
689
    // Hack condition to check that we do not assume "no body"
690
40.8k
    if (connp->out_state != htp_connp_RES_FINALIZE) {
691
        // We have a response body
692
30.1k
        htp_header_t *ct = htp_table_get_c(connp->out_tx->response_headers, "content-type");
693
30.1k
        if (ct != NULL) {
694
11.6k
            connp->out_tx->response_content_type = bstr_dup_lower(ct->value);
695
11.6k
            if (connp->out_tx->response_content_type == NULL) return HTP_ERROR;
696
697
            // Ignore parameters
698
11.6k
            unsigned char *data = bstr_ptr(connp->out_tx->response_content_type);
699
11.6k
            size_t len = bstr_len(ct->value);
700
11.6k
            size_t newlen = 0;
701
132k
            while (newlen < len) {
702
                // TODO Some platforms may do things differently here.
703
126k
                if (htp_is_space(data[newlen]) || (data[newlen] == ';')) {
704
5.18k
                    bstr_adjust_len(connp->out_tx->response_content_type, newlen);
705
5.18k
                    break;
706
5.18k
                }
707
708
121k
                newlen++;
709
121k
            }
710
11.6k
        }
711
712
        // 2. If a Transfer-Encoding header field (section 14.40) is present and
713
        //   indicates that the "chunked" transfer coding has been applied, then
714
        //   the length is defined by the chunked encoding (section 3.6).
715
30.1k
        if ((te != NULL) && (bstr_index_of_c_nocasenorzero(te->value, "chunked") != -1)) {
716
8.58k
            if (bstr_cmp_c_nocase(te->value, "chunked") != 0) {
717
5.66k
                htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0,
718
5.66k
                        "Transfer-encoding has abnormal chunked value");
719
5.66k
            }
720
721
            // spec says chunked is HTTP/1.1 only, but some browsers accept it
722
            // with 1.0 as well
723
8.58k
            if (connp->out_tx->response_protocol_number < HTP_PROTOCOL_1_1) {
724
6.54k
                htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0,
725
6.54k
                        "Chunked transfer-encoding on HTTP/0.9 or HTTP/1.0");
726
6.54k
            }
727
728
            // If the T-E header is present we are going to use it.
729
8.58k
            connp->out_tx->response_transfer_coding = HTP_CODING_CHUNKED;
730
731
            // We are still going to check for the presence of C-L
732
8.58k
            if (cl != NULL) {
733
                // This is a violation of the RFC
734
584
                connp->out_tx->flags |= HTP_REQUEST_SMUGGLING;
735
584
            }
736
737
8.58k
            connp->out_state = htp_connp_RES_BODY_CHUNKED_LENGTH;
738
8.58k
            connp->out_tx->response_progress = HTP_RESPONSE_BODY;
739
8.58k
        }// 3. If a Content-Length header field (section 14.14) is present, its
740
            //   value in bytes represents the length of the message-body.
741
21.6k
        else if (cl != NULL) {
742
            // We know the exact length
743
19.0k
            connp->out_tx->response_transfer_coding = HTP_CODING_IDENTITY;
744
745
            // Check for multiple C-L headers
746
19.0k
            if (cl->flags & HTP_FIELD_REPEATED) {
747
4.79k
                connp->out_tx->flags |= HTP_REQUEST_SMUGGLING;
748
4.79k
            }
749
750
            // Get body length
751
19.0k
            connp->out_tx->response_content_length = htp_parse_content_length(cl->value, connp);
752
19.0k
            if (connp->out_tx->response_content_length < 0) {
753
31
                htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Invalid C-L field in response: %"PRId64"",
754
31
                        connp->out_tx->response_content_length);
755
31
                return HTP_ERROR;
756
19.0k
            } else {
757
19.0k
                connp->out_content_length = connp->out_tx->response_content_length;
758
19.0k
                connp->out_body_data_left = connp->out_content_length;
759
760
19.0k
                if (connp->out_content_length != 0) {
761
12.6k
                    connp->out_state = htp_connp_RES_BODY_IDENTITY_CL_KNOWN;
762
12.6k
                    connp->out_tx->response_progress = HTP_RESPONSE_BODY;
763
12.6k
                } else {                    
764
6.38k
                    connp->out_state = htp_connp_RES_FINALIZE;
765
6.38k
                }
766
19.0k
            }
767
19.0k
        } else {
768
            // 4. If the message uses the media type "multipart/byteranges", which is
769
            //   self-delimiting, then that defines the length. This media type MUST
770
            //   NOT be used unless the sender knows that the recipient can parse it;
771
            //   the presence in a request of a Range header with multiple byte-range
772
            //   specifiers implies that the client can parse multipart/byteranges
773
            //   responses.
774
2.54k
            if (ct != NULL) {
775
                // TODO Handle multipart/byteranges
776
390
                if (bstr_index_of_c_nocase(ct->value, "multipart/byteranges") != -1) {
777
2
                    htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0,
778
2
                            "C-T multipart/byteranges in responses not supported");
779
2
                    return HTP_ERROR;
780
2
                }
781
390
            }
782
783
            // 5. By the server closing the connection. (Closing the connection
784
            //   cannot be used to indicate the end of a request body, since that
785
            //   would leave no possibility for the server to send back a response.)
786
2.54k
            connp->out_state = htp_connp_RES_BODY_IDENTITY_STREAM_CLOSE;
787
2.54k
            connp->out_tx->response_transfer_coding = HTP_CODING_IDENTITY;
788
2.54k
            connp->out_tx->response_progress = HTP_RESPONSE_BODY;
789
2.54k
            connp->out_body_data_left = -1;
790
2.54k
        }
791
30.1k
    }
792
793
    // NOTE We do not need to check for short-style HTTP/0.9 requests here because
794
    //      that is done earlier, before response line parsing begins
795
796
40.7k
    htp_status_t rc = htp_tx_state_response_headers(connp->out_tx);
797
40.7k
    if (rc != HTP_OK) return rc;
798
799
40.7k
    return HTP_OK;
800
40.7k
}
801
802
/**
803
 * Parses response headers.
804
 *
805
 * @param[in] connp
806
 * @returns HTP_OK on state change, HTP_ERROR on error, or HTP_DATA when more data is needed.
807
 */
808
107k
htp_status_t htp_connp_RES_HEADERS(htp_connp_t *connp) {
809
107k
    int endwithcr;
810
107k
    int lfcrending = 0;
811
812
21.1M
    for (;;) {
813
21.1M
        if (connp->out_status == HTP_STREAM_CLOSED) {
814
            // Finalize sending raw trailer data.
815
1.36k
            htp_status_t rc = htp_connp_res_receiver_finalize_clear(connp);
816
1.36k
            if (rc != HTP_OK) return rc;
817
818
            // Run hook response_TRAILER.
819
1.36k
            rc = htp_hook_run_all(connp->cfg->hook_response_trailer, connp->out_tx);
820
1.36k
            if (rc != HTP_OK) return rc;
821
822
1.36k
            connp->out_state = htp_connp_RES_FINALIZE;
823
1.36k
            return HTP_OK;
824
1.36k
        }
825
21.1M
        OUT_COPY_BYTE_OR_RETURN(connp);
826
827
        // Have we reached the end of the line?
828
21.1M
        if (connp->out_next_byte != LF && connp->out_next_byte != CR) {
829
20.4M
            lfcrending = 0;
830
20.4M
        } else {
831
677k
            endwithcr = 0;
832
677k
            if (connp->out_next_byte == CR) {
833
487k
                OUT_PEEK_NEXT(connp);
834
487k
                if (connp->out_next_byte == -1) {
835
952
                    return HTP_DATA_BUFFER;
836
486k
                } else if (connp->out_next_byte == LF) {
837
217k
                    OUT_COPY_BYTE_OR_RETURN(connp);
838
217k
                    if (lfcrending) {
839
                        // Handling LFCRCRLFCRLF
840
                        // These 6 characters mean only 2 end of lines
841
4.25k
                        OUT_PEEK_NEXT(connp);
842
4.25k
                        if (connp->out_next_byte == CR) {
843
2.38k
                            OUT_COPY_BYTE_OR_RETURN(connp);
844
2.38k
                            connp->out_current_consume_offset++;
845
2.38k
                            OUT_PEEK_NEXT(connp);
846
2.38k
                            if (connp->out_next_byte == LF) {
847
1.15k
                                OUT_COPY_BYTE_OR_RETURN(connp);
848
1.15k
                                connp->out_current_consume_offset++;
849
1.15k
                                htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0,
850
1.15k
                                        "Weird response end of lines mix");
851
1.15k
                            }
852
2.38k
                        }
853
4.25k
                    }
854
268k
                } else if (connp->out_next_byte == CR) {
855
188k
                    continue;
856
188k
                }
857
298k
                lfcrending = 0;
858
298k
                endwithcr = 1;
859
298k
            } else {
860
                // connp->out_next_byte == LF
861
189k
                OUT_PEEK_NEXT(connp);
862
189k
                lfcrending = 0;
863
189k
                if (connp->out_next_byte == CR) {
864
                    // hanldes LF-CR sequence as end of line
865
12.4k
                    OUT_COPY_BYTE_OR_RETURN(connp);
866
12.4k
                    lfcrending = 1;
867
12.4k
                }
868
189k
            }
869
870
487k
            unsigned char *data;
871
487k
            size_t len;
872
873
487k
            if (htp_connp_res_consolidate_data(connp, &data, &len) != HTP_OK) {
874
3
                return HTP_ERROR;
875
3
            }
876
877
            // CRCRLF is not an empty line
878
487k
            if (endwithcr && len < 2) {
879
8.98k
                continue;
880
8.98k
            }
881
882
            #ifdef HTP_DEBUG
883
            fprint_raw_data(stderr, __func__, data, len);
884
            #endif
885
886
478k
            int next_no_lf = 0;
887
478k
            if (connp->out_current_read_offset < connp->out_current_len &&
888
456k
                connp->out_current_data[connp->out_current_read_offset] != LF) {
889
426k
                next_no_lf = 1;
890
426k
            }
891
            // Should we terminate headers?
892
478k
            if (htp_connp_is_line_terminator(connp, data, len, next_no_lf)) {
893
                // Parse previous header, if any.
894
53.6k
                if (connp->out_header != NULL) {
895
5.08k
                    if (connp->cfg->process_response_header(connp, bstr_ptr(connp->out_header),
896
5.08k
                            bstr_len(connp->out_header)) != HTP_OK) return HTP_ERROR;
897
898
5.08k
                    bstr_free(connp->out_header);
899
5.08k
                    connp->out_header = NULL;
900
5.08k
                }
901
902
53.6k
                htp_connp_res_clear_buffer(connp);
903
904
                // We've seen all response headers.
905
53.6k
                if (connp->out_tx->response_progress == HTP_RESPONSE_HEADERS) {
906
                    // Response headers.
907
908
                    // The next step is to determine if this response has a body.
909
45.6k
                    connp->out_state = htp_connp_RES_BODY_DETERMINE;
910
45.6k
                } else {
911
                    // Response trailer.
912
913
                    // Finalize sending raw trailer data.
914
8.04k
                    htp_status_t rc = htp_connp_res_receiver_finalize_clear(connp);
915
8.04k
                    if (rc != HTP_OK) return rc;
916
917
                    // Run hook response_TRAILER.
918
8.04k
                    rc = htp_hook_run_all(connp->cfg->hook_response_trailer, connp->out_tx);
919
8.04k
                    if (rc != HTP_OK) return rc;
920
921
                    // The next step is to finalize this response.
922
8.04k
                    connp->out_state = htp_connp_RES_FINALIZE;
923
8.04k
                }
924
925
53.6k
                return HTP_OK;
926
53.6k
            }
927
928
425k
            htp_chomp(data, &len);
929
930
            // Check for header folding.
931
425k
            if (htp_connp_is_line_folded(data, len) == 0) {
932
                // New header line.
933
934
                // Parse previous header, if any.
935
329k
                if (connp->out_header != NULL) {
936
31.5k
                    if (connp->cfg->process_response_header(connp, bstr_ptr(connp->out_header),
937
31.5k
                            bstr_len(connp->out_header)) != HTP_OK) return HTP_ERROR;
938
939
31.5k
                    bstr_free(connp->out_header);
940
31.5k
                    connp->out_header = NULL;
941
31.5k
                }
942
943
329k
                OUT_PEEK_NEXT(connp);
944
945
329k
                if (htp_is_folding_char(connp->out_next_byte) == 0) {
946
                    // Because we know this header is not folded, we can process the buffer straight away.
947
311k
                    if (connp->cfg->process_response_header(connp, data, len) != HTP_OK) return HTP_ERROR;
948
311k
                } else {
949
                    // Keep the partial header data for parsing later.
950
17.9k
                    connp->out_header = bstr_dup_mem(data, len);
951
17.9k
                    if (connp->out_header == NULL) return HTP_ERROR;
952
17.9k
                }
953
329k
            } else {
954
                // Folding; check that there's a previous header line to add to.
955
95.2k
                if (connp->out_header == NULL) {
956
                    // Invalid folding.
957
958
                    // Warn only once per transaction.
959
19.1k
                    if (!(connp->out_tx->flags & HTP_INVALID_FOLDING)) {
960
9.76k
                        connp->out_tx->flags |= HTP_INVALID_FOLDING;
961
9.76k
                        htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Invalid response field folding");
962
9.76k
                    }
963
964
                    // Keep the header data for parsing later.
965
19.1k
                    size_t trim = 0;
966
60.7k
                    while(trim < len) {
967
50.2k
                        if (!htp_is_folding_char(data[trim])) {
968
8.71k
                            break;
969
8.71k
                        }
970
41.5k
                        trim++;
971
41.5k
                    }
972
19.1k
                    connp->out_header = bstr_dup_mem(data + trim, len - trim);
973
19.1k
                    if (connp->out_header == NULL) return HTP_ERROR;
974
76.1k
                } else {
975
76.1k
                    size_t colon_pos = 0;
976
3.35M
                    while ((colon_pos < len) && (data[colon_pos] != ':')) colon_pos++;
977
978
76.1k
                    if (colon_pos < len &&
979
10.1k
                        bstr_chr(connp->out_header, ':') >= 0 &&
980
5.89k
                        connp->out_tx->response_protocol_number == HTP_PROTOCOL_1_1) {
981
                        // Warn only once per transaction.
982
1.26k
                        if (!(connp->out_tx->flags & HTP_INVALID_FOLDING)) {
983
345
                            connp->out_tx->flags |= HTP_INVALID_FOLDING;
984
345
                            htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Invalid response field folding");
985
345
                        }
986
1.26k
                        if (connp->cfg->process_response_header(connp, bstr_ptr(connp->out_header),
987
1.26k
                            bstr_len(connp->out_header)) != HTP_OK)
988
0
                            return HTP_ERROR;
989
1.26k
                        bstr_free(connp->out_header);
990
1.26k
                        connp->out_header = bstr_dup_mem(data+1, len-1);
991
1.26k
                        if (connp->out_header == NULL)
992
0
                            return HTP_ERROR;
993
74.8k
                    } else {
994
                        // Add to the existing header.
995
74.8k
                        if (bstr_len(connp->out_header) < HTP_MAX_HEADER_FOLDED) {
996
68.6k
                            bstr *new_out_header = bstr_add_mem(connp->out_header, data, len);
997
68.6k
                            if (new_out_header == NULL)
998
0
                                return HTP_ERROR;
999
68.6k
                            connp->out_header = new_out_header;
1000
68.6k
                        } else {
1001
6.19k
                            htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Response field length exceeds folded maximum");
1002
6.19k
                        }
1003
74.8k
                    }
1004
76.1k
                }
1005
95.2k
            }
1006
1007
425k
            htp_connp_res_clear_buffer(connp);
1008
425k
        }
1009
21.1M
    }
1010
1011
0
    return HTP_ERROR;
1012
107k
}
1013
1014
/**
1015
 * Parses response line.
1016
 *
1017
 * @param[in] connp
1018
 * @returns HTP_OK on state change, HTP_ERROR on error, or HTP_DATA when more data is needed.
1019
 */
1020
791k
htp_status_t htp_connp_RES_LINE(htp_connp_t *connp) {
1021
24.6M
    for (;;) {
1022
        // Don't try to get more data if the stream is closed. If we do, we'll return, asking for more data.
1023
24.6M
        if (connp->out_status != HTP_STREAM_CLOSED) {
1024
            // Get one byte
1025
24.6M
            OUT_COPY_BYTE_OR_RETURN(connp);
1026
24.6M
        }
1027
1028
        // Have we reached the end of the line? We treat stream closure as end of line in
1029
        // order to handle the case when the first line of the response is actually response body
1030
        // (and we wish it processed as such).
1031
24.6M
        if (connp->out_next_byte == CR) {
1032
388k
            OUT_PEEK_NEXT(connp);
1033
388k
            if (connp->out_next_byte == -1) {
1034
1.50k
                return HTP_DATA_BUFFER;
1035
386k
            } else if (connp->out_next_byte == LF) {
1036
84.6k
                continue;
1037
84.6k
            }
1038
302k
            connp->out_next_byte = LF;
1039
302k
        }
1040
24.5M
        if ((connp->out_next_byte == LF)||(connp->out_status == HTP_STREAM_CLOSED)) {
1041
719k
            unsigned char *data;
1042
719k
            size_t len;
1043
1044
719k
            if (htp_connp_res_consolidate_data(connp, &data, &len) != HTP_OK) {
1045
4
                return HTP_ERROR;
1046
4
            }
1047
1048
            #ifdef HTP_DEBUG
1049
            fprint_raw_data(stderr, __func__, data, len);
1050
            #endif
1051
1052
            // Is this a line that should be ignored?
1053
719k
            if (htp_connp_is_line_ignorable(connp, data, len)) {
1054
328k
                if (connp->out_status == HTP_STREAM_CLOSED) {
1055
9
                    connp->out_state = htp_connp_RES_FINALIZE;
1056
9
                }
1057
                // We have an empty/whitespace line, which we'll note, ignore and move on
1058
328k
                connp->out_tx->response_ignored_lines++;
1059
1060
                // TODO How many lines are we willing to accept?
1061
1062
                // Start again
1063
328k
                htp_connp_res_clear_buffer(connp);
1064
1065
328k
                return HTP_OK;
1066
328k
            }
1067
1068
            // Deallocate previous response line allocations, which we would have on a 100 response.
1069
1070
390k
            if (connp->out_tx->response_line != NULL) {
1071
2.35k
                bstr_free(connp->out_tx->response_line);
1072
2.35k
                connp->out_tx->response_line = NULL;
1073
2.35k
            }
1074
1075
390k
            if (connp->out_tx->response_protocol != NULL) {
1076
2.35k
                bstr_free(connp->out_tx->response_protocol);
1077
2.35k
                connp->out_tx->response_protocol = NULL;
1078
2.35k
            }
1079
1080
390k
            if (connp->out_tx->response_status != NULL) {
1081
2.35k
                bstr_free(connp->out_tx->response_status);
1082
2.35k
                connp->out_tx->response_status = NULL;
1083
2.35k
            }
1084
1085
390k
            if (connp->out_tx->response_message != NULL) {
1086
2.24k
                bstr_free(connp->out_tx->response_message);
1087
2.24k
                connp->out_tx->response_message = NULL;
1088
2.24k
            }
1089
1090
            // Process response line.           
1091
1092
390k
            int chomp_result = htp_chomp(data, &len);
1093
1094
            // If the response line is invalid, determine if it _looks_ like
1095
            // a response line. If it does not look like a line, process the
1096
            // data as a response body because that is what browsers do.
1097
           
1098
390k
            if (htp_treat_response_line_as_body(data, len)) {
1099
                // if we have a next line beginning with H, skip this one
1100
342k
                if (connp->out_current_read_offset+1 < connp->out_current_len && (connp->out_current_data[connp->out_current_read_offset] == 'H' || len <= 2)) {
1101
53.2k
                    connp->out_tx->response_ignored_lines++;
1102
53.2k
                    htp_connp_res_clear_buffer(connp);
1103
53.2k
                    return HTP_OK;
1104
53.2k
                }
1105
289k
                connp->out_tx->response_content_encoding_processing = HTP_COMPRESSION_NONE;
1106
1107
289k
                connp->out_current_consume_offset = connp->out_current_read_offset;
1108
289k
                htp_status_t rc = htp_tx_res_process_body_data_ex(connp->out_tx, data, len + chomp_result);
1109
289k
                htp_connp_res_clear_buffer(connp);
1110
289k
                if (rc != HTP_OK) return rc;
1111
1112
                // Continue to process response body. Because we don't have
1113
                // any headers to parse, we assume the body continues until
1114
                // the end of the stream.
1115
1116
                // Have we seen the entire response body?
1117
289k
                if (connp->out_current_len <= connp->out_current_read_offset) {
1118
45.2k
                    connp->out_tx->response_transfer_coding = HTP_CODING_IDENTITY;
1119
45.2k
                    connp->out_tx->response_progress = HTP_RESPONSE_BODY;
1120
45.2k
                    connp->out_body_data_left = -1;
1121
45.2k
                    connp->out_state = htp_connp_RES_FINALIZE;
1122
45.2k
                }
1123
1124
289k
                return HTP_OK;
1125
289k
            }
1126
1127
47.7k
            connp->out_tx->response_line = bstr_dup_mem(data, len);
1128
47.7k
            if (connp->out_tx->response_line == NULL) return HTP_ERROR;
1129
1130
47.7k
            if (connp->cfg->parse_response_line(connp) != HTP_OK) return HTP_ERROR;
1131
1132
47.7k
            htp_status_t rc = htp_tx_state_response_line(connp->out_tx);
1133
47.7k
            if (rc != HTP_OK) return rc;
1134
1135
47.7k
            htp_connp_res_clear_buffer(connp);
1136
1137
            // Move on to the next phase.
1138
47.7k
            connp->out_state = htp_connp_RES_HEADERS;
1139
47.7k
            connp->out_tx->response_progress = HTP_RESPONSE_HEADERS;
1140
1141
47.7k
            return HTP_OK;
1142
47.7k
        }
1143
24.5M
    }
1144
1145
0
    return HTP_ERROR;
1146
791k
}
1147
1148
179k
size_t htp_connp_res_data_consumed(htp_connp_t *connp) {
1149
179k
    return connp->out_current_read_offset;
1150
179k
}
1151
1152
336k
htp_status_t htp_connp_RES_FINALIZE(htp_connp_t *connp) {
1153
336k
    if (connp->out_status != HTP_STREAM_CLOSED) {
1154
332k
        OUT_PEEK_NEXT(connp);
1155
332k
        if (connp->out_next_byte == -1) {
1156
61.5k
            return htp_tx_state_response_complete_ex(connp->out_tx, 0);
1157
61.5k
        }
1158
270k
        if (connp->out_next_byte != LF || connp->out_current_consume_offset >= connp->out_current_read_offset) {
1159
11.8M
            for (;;) {//;i < max_read; i++) {
1160
11.8M
                OUT_COPY_BYTE_OR_RETURN(connp);
1161
                // Have we reached the end of the line? For some reason
1162
                // we can't test after IN_COPY_BYTE_OR_RETURN */
1163
11.7M
                if (connp->out_next_byte == LF)
1164
238k
                    break;
1165
11.7M
            }
1166
270k
        }
1167
270k
    }
1168
242k
    size_t bytes_left;
1169
242k
    unsigned char * data;
1170
1171
242k
    if (htp_connp_res_consolidate_data(connp, &data, &bytes_left) != HTP_OK) {
1172
4
        return HTP_ERROR;
1173
4
    }
1174
#ifdef HTP_DEBUG
1175
    fprint_raw_data(stderr, "PROBING response finalize", data, bytes_left);
1176
#endif
1177
242k
    if (bytes_left == 0) {
1178
        //closing
1179
2.62k
        return htp_tx_state_response_complete_ex(connp->out_tx, 0);
1180
2.62k
    }
1181
1182
240k
    if (htp_treat_response_line_as_body(data, bytes_left)) {
1183
        // Interpret remaining bytes as body data
1184
218k
        htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Unexpected response body");
1185
218k
        htp_status_t rc = htp_tx_res_process_body_data_ex(connp->out_tx, data, bytes_left);
1186
218k
        htp_connp_res_clear_buffer(connp);
1187
218k
        return rc;
1188
218k
    }
1189
1190
    //unread last end of line so that RES_LINE works
1191
22.0k
    if (connp->out_current_read_offset < (int64_t)bytes_left) {
1192
2.10k
        connp->out_current_read_offset=0;
1193
19.9k
    } else {
1194
19.9k
        connp->out_current_read_offset-=bytes_left;
1195
19.9k
    }
1196
22.0k
    if (connp->out_current_read_offset < connp->out_current_consume_offset) {
1197
2.07k
        connp->out_current_consume_offset=connp->out_current_read_offset;
1198
2.07k
    }
1199
22.0k
    return htp_tx_state_response_complete_ex(connp->out_tx, 0 /* not hybrid mode */);
1200
240k
}
1201
1202
/**
1203
 * The response idle state will initialize response processing, as well as
1204
 * finalize each transactions after we are done with it.
1205
 *
1206
 * @param[in] connp
1207
 * @returns HTP_OK on state change, HTP_ERROR on error, or HTP_DATA when more data is needed.
1208
 */
1209
158k
htp_status_t htp_connp_RES_IDLE(htp_connp_t *connp) {
1210
1211
    // We want to start parsing the next response (and change
1212
    // the state from IDLE) only if there's at least one
1213
    // byte of data available. Otherwise we could be creating
1214
    // new structures even if there's no more data on the
1215
    // connection.
1216
158k
    OUT_TEST_NEXT_BYTE_OR_RETURN(connp);
1217
1218
    // Parsing a new response
1219
1220
    // Find the next outgoing transaction
1221
    // If there is none, we just create one so that responses without
1222
    // request can still be processed.
1223
92.9k
    connp->out_tx = htp_list_get(connp->conn->transactions, connp->out_next_tx_index);
1224
92.9k
    if (connp->out_tx == NULL) {
1225
47.3k
        htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Unable to match response to request");
1226
        // finalize dangling request waiting for next request or body
1227
47.3k
        if (connp->in_state == htp_connp_REQ_FINALIZE) {
1228
27.0k
            htp_tx_state_request_complete(connp->in_tx);
1229
27.0k
        }
1230
47.3k
        connp->out_tx = htp_connp_tx_create(connp);
1231
47.3k
        if (connp->out_tx == NULL) {
1232
11
            return HTP_ERROR;
1233
11
        }
1234
47.3k
        connp->out_tx->parsed_uri = htp_uri_alloc();
1235
47.3k
        if (connp->out_tx->parsed_uri == NULL) {
1236
0
            return HTP_ERROR;
1237
0
        }
1238
47.3k
        connp->out_tx->parsed_uri->path = bstr_dup_c(REQUEST_URI_NOT_SEEN);
1239
47.3k
        if (connp->out_tx->parsed_uri->path == NULL) {
1240
0
            return HTP_ERROR;
1241
0
        }
1242
47.3k
        connp->out_tx->request_uri = bstr_dup_c(REQUEST_URI_NOT_SEEN);
1243
47.3k
        if (connp->out_tx->request_uri == NULL) {
1244
0
            return HTP_ERROR;
1245
0
        }
1246
1247
47.3k
        connp->in_state = htp_connp_REQ_FINALIZE;
1248
#ifdef HTP_DEBUG
1249
        fprintf(stderr, "picked up response w/o request");
1250
#endif
1251
        // We've used one transaction
1252
47.3k
        connp->out_next_tx_index++;
1253
47.3k
    } else {
1254
        // We've used one transaction
1255
45.5k
        connp->out_next_tx_index++;
1256
1257
        // TODO Detect state mismatch
1258
1259
45.5k
        connp->out_content_length = -1;
1260
45.5k
        connp->out_body_data_left = -1;
1261
45.5k
    }
1262
1263
92.9k
    htp_status_t rc = htp_tx_state_response_start(connp->out_tx);
1264
92.9k
    if (rc != HTP_OK) return rc;
1265
1266
92.9k
    return HTP_OK;
1267
92.9k
}
1268
1269
298k
int htp_connp_res_data(htp_connp_t *connp, const htp_time_t *timestamp, const void *data, size_t len) {
1270
    #ifdef HTP_DEBUG
1271
    fprintf(stderr, "htp_connp_res_data(connp->out_status %x)\n", connp->out_status);
1272
    fprint_raw_data(stderr, __func__, data, len);
1273
    #endif
1274
1275
    // Return if the connection is in stop state
1276
298k
    if (connp->out_status == HTP_STREAM_STOP) {
1277
0
        htp_log(connp, HTP_LOG_MARK, HTP_LOG_INFO, 0, "Outbound parser is in HTP_STREAM_STOP");
1278
1279
0
        return HTP_STREAM_STOP;
1280
0
    }
1281
1282
    // Return if the connection has had a fatal error
1283
298k
    if (connp->out_status == HTP_STREAM_ERROR) {
1284
186
        htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Outbound parser is in HTP_STREAM_ERROR");
1285
1286
        #ifdef HTP_DEBUG
1287
        fprintf(stderr, "htp_connp_res_data: returning HTP_STREAM_DATA (previous error)\n");
1288
        #endif
1289
1290
186
        return HTP_STREAM_ERROR;
1291
186
    }
1292
1293
    // Sanity check: we must have a transaction pointer if the state is not IDLE (no outbound transaction)
1294
297k
    if ((connp->out_tx == NULL)&&(connp->out_state != htp_connp_RES_IDLE)) {
1295
31
        connp->out_status = HTP_STREAM_ERROR;
1296
1297
31
        htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Missing outbound transaction data");
1298
1299
31
        return HTP_STREAM_ERROR;
1300
31
    }
1301
1302
    // If the length of the supplied data chunk is zero, proceed
1303
    // only if the stream has been closed. We do not allow zero-sized
1304
    // chunks in the API, but we use it internally to force the parsers
1305
    // to finalize parsing.
1306
297k
    if (len == 0 && connp->out_status != HTP_STREAM_CLOSED) {
1307
0
        htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Zero-length data chunks are not allowed");
1308
1309
        #ifdef HTP_DEBUG
1310
        fprintf(stderr, "htp_connp_res_data: returning HTP_STREAM_DATA (zero-length chunk)\n");
1311
        #endif
1312
1313
0
        return HTP_STREAM_CLOSED;
1314
0
    }
1315
1316
    // Remember the timestamp of the current response data chunk
1317
297k
    if (timestamp != NULL) {
1318
297k
        memcpy(&connp->out_timestamp, timestamp, sizeof (*timestamp));
1319
297k
    }
1320
1321
    // Store the current chunk information
1322
297k
    connp->out_current_data = (unsigned char *) data;
1323
297k
    connp->out_current_len = len;
1324
297k
    connp->out_current_read_offset = 0;
1325
297k
    connp->out_current_consume_offset = 0;
1326
297k
    connp->out_current_receiver_offset = 0;
1327
1328
297k
    htp_conn_track_outbound_data(connp->conn, len, timestamp);
1329
1330
    // Return without processing any data if the stream is in tunneling
1331
    // mode (which it would be after an initial CONNECT transaction.
1332
297k
    if (connp->out_status == HTP_STREAM_TUNNEL) {
1333
        #ifdef HTP_DEBUG
1334
        fprintf(stderr, "htp_connp_res_data: returning HTP_STREAM_TUNNEL\n");
1335
        #endif
1336
1337
1.19k
        return HTP_STREAM_TUNNEL;
1338
1.19k
    }
1339
1340
    // Invoke a processor, in a loop, until an error
1341
    // occurs or until we run out of data. Many processors
1342
    // will process a request, each pointing to the next
1343
    // processor that needs to run.
1344
1.56M
    for (;;) {
1345
        #ifdef HTP_DEBUG
1346
        fprintf(stderr, "htp_connp_res_data: out state=%s, progress=%s\n",
1347
                htp_connp_out_state_as_string(connp),
1348
                htp_tx_response_progress_as_string(connp->out_tx));
1349
        #endif
1350
1351
        // Return if there's been an error
1352
        // or if we've run out of data. We are relying
1353
        // on processors to add error messages, so we'll
1354
        // keep quiet here.
1355
1.56M
        htp_status_t rc;
1356
1357
        //handle gap
1358
1.56M
        if (data == NULL && len > 0) {
1359
1.77k
            if (connp->out_state == htp_connp_RES_BODY_IDENTITY_CL_KNOWN ||
1360
1.43k
                connp->out_state == htp_connp_RES_BODY_IDENTITY_STREAM_CLOSE) {
1361
518
                rc = connp->out_state(connp);
1362
1.25k
            } else if (connp->out_state == htp_connp_RES_FINALIZE) {
1363
51
                rc = htp_tx_state_response_complete_ex(connp->out_tx, 0);
1364
1.20k
            } else {
1365
1.20k
                htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Gaps are not allowed during this state");
1366
1.20k
                return HTP_STREAM_CLOSED;
1367
1.20k
            }
1368
1.56M
        } else {
1369
1.56M
            rc = connp->out_state(connp);
1370
1.56M
        }
1371
1.56M
        if (rc == HTP_OK) {
1372
1.27M
            if (connp->out_status == HTP_STREAM_TUNNEL) {
1373
                #ifdef HTP_DEBUG
1374
                fprintf(stderr, "htp_connp_res_data: returning HTP_STREAM_TUNNEL\n");
1375
                #endif
1376
1377
413
                return HTP_STREAM_TUNNEL;
1378
413
            }
1379
1380
1.27M
            rc = htp_res_handle_state_change(connp);
1381
1.27M
        }
1382
1383
1.56M
        if (rc != HTP_OK) {
1384
            // Do we need more data?
1385
295k
            if ((rc == HTP_DATA) || (rc == HTP_DATA_BUFFER)) {
1386
293k
                htp_connp_res_receiver_send_data(connp, 0 /* not last */);
1387
1388
293k
                if (rc == HTP_DATA_BUFFER) {
1389
159k
                    if (htp_connp_res_buffer(connp) != HTP_OK) {
1390
7
                        connp->out_status = HTP_STREAM_ERROR;
1391
7
                        return HTP_STREAM_ERROR;
1392
7
                    }
1393
159k
                }
1394
1395
                #ifdef HTP_DEBUG
1396
                fprintf(stderr, "htp_connp_res_data: returning HTP_STREAM_DATA\n");
1397
                #endif
1398
1399
293k
                connp->out_status = HTP_STREAM_DATA;
1400
1401
293k
                return HTP_STREAM_DATA;
1402
293k
            }
1403
1404
            // Check for stop
1405
1.36k
            if (rc == HTP_STOP) {
1406
                #ifdef HTP_DEBUG
1407
                fprintf(stderr, "htp_connp_res_data: returning HTP_STREAM_STOP\n");
1408
                #endif
1409
1410
0
                connp->out_status = HTP_STREAM_STOP;
1411
1412
0
                return HTP_STREAM_STOP;
1413
0
            }
1414
1415
            // Check for suspended parsing
1416
1.36k
            if (rc == HTP_DATA_OTHER) {
1417
                // We might have actually consumed the entire data chunk?
1418
232
                if (connp->out_current_read_offset >= connp->out_current_len) {
1419
                    #ifdef HTP_DEBUG
1420
                    fprintf(stderr, "htp_connp_res_data: returning HTP_STREAM_DATA (suspended parsing)\n");
1421
                    #endif
1422
1423
169
                    connp->out_status = HTP_STREAM_DATA;
1424
1425
                    // Do not send STREAM_DATE_DATA_OTHER if we've
1426
                    // consumed the entire chunk
1427
169
                    return HTP_STREAM_DATA;
1428
169
                } else {
1429
                    #ifdef HTP_DEBUG
1430
                    fprintf(stderr, "htp_connp_res_data: returning HTP_STREAM_DATA_OTHER\n");
1431
                    #endif
1432
1433
63
                    connp->out_status = HTP_STREAM_DATA_OTHER;
1434
1435
                    // Partial chunk consumption
1436
63
                    return HTP_STREAM_DATA_OTHER;
1437
63
                }
1438
232
            }
1439
1440
            #ifdef HTP_DEBUG
1441
            fprintf(stderr, "htp_connp_res_data: returning HTP_STREAM_ERROR\n");
1442
            #endif
1443
1444
            // Permanent stream error.
1445
1.13k
            connp->out_status = HTP_STREAM_ERROR;
1446
1447
1.13k
            return HTP_STREAM_ERROR;
1448
1.36k
        }
1449
1.56M
    }
1450
296k
}