Coverage Report

Created: 2025-11-16 07:09

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
160k
#define OUT_TEST_NEXT_BYTE_OR_RETURN(X) \
44
160k
if ((X)->out_current_read_offset >= (X)->out_current_len) { \
45
65.0k
    return HTP_DATA; \
46
65.0k
}
47
48
1.72M
#define OUT_PEEK_NEXT(X) \
49
1.72M
if ((X)->out_current_read_offset >= (X)->out_current_len) { \
50
92.3k
    (X)->out_next_byte = -1; \
51
1.63M
} else { \
52
1.63M
    (X)->out_next_byte = (X)->out_current_data[(X)->out_current_read_offset]; \
53
1.63M
}
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
146k
#define OUT_NEXT_BYTE_OR_RETURN(X) \
66
146k
if ((X)->out_current_read_offset < (X)->out_current_len) { \
67
145k
    (X)->out_next_byte = (X)->out_current_data[(X)->out_current_read_offset]; \
68
145k
    (X)->out_current_read_offset++; \
69
145k
    (X)->out_current_consume_offset++; \
70
145k
    (X)->out_stream_offset++; \
71
145k
} else { \
72
784
    return HTP_DATA; \
73
784
}
74
75
57.3M
#define OUT_COPY_BYTE_OR_RETURN(X) \
76
57.3M
if ((X)->out_current_read_offset < (X)->out_current_len) { \
77
57.2M
    (X)->out_next_byte = (X)->out_current_data[(X)->out_current_read_offset]; \
78
57.2M
    (X)->out_current_read_offset++; \
79
57.2M
    (X)->out_stream_offset++; \
80
57.2M
} else { \
81
138k
    return HTP_DATA_BUFFER; \
82
138k
}
83
84
102k
#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
320k
static htp_status_t htp_connp_res_receiver_send_data(htp_connp_t *connp, int is_last) {
94
320k
    if (connp->out_data_receiver_hook == NULL) return HTP_OK;
95
96
99.9k
    htp_tx_data_t d;
97
99.9k
    d.tx = connp->out_tx;
98
99.9k
    d.data = connp->out_current_data + connp->out_current_receiver_offset;
99
99.9k
    d.len = connp->out_current_read_offset - connp->out_current_receiver_offset;
100
99.9k
    d.is_last = is_last;
101
102
99.9k
    htp_status_t rc = htp_hook_run_all(connp->out_data_receiver_hook, &d);
103
99.9k
    if (rc != HTP_OK) return rc;
104
105
99.9k
    connp->out_current_receiver_offset = connp->out_current_read_offset;
106
107
99.9k
    return HTP_OK;
108
99.9k
}
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
199k
htp_status_t htp_connp_res_receiver_finalize_clear(htp_connp_t *connp) {
118
199k
    if (connp->out_data_receiver_hook == NULL) return HTP_OK;
119
120
55.2k
    htp_status_t rc = htp_connp_res_receiver_send_data(connp, 1 /* last */);
121
122
55.2k
    connp->out_data_receiver_hook = NULL;
123
124
55.2k
    return rc;
125
199k
}
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
56.0k
static htp_status_t htp_connp_res_receiver_set(htp_connp_t *connp, htp_hook_t *data_receiver_hook) {
135
56.0k
    htp_status_t rc = htp_connp_res_receiver_finalize_clear(connp);
136
137
56.0k
    connp->out_data_receiver_hook = data_receiver_hook;
138
56.0k
    connp->out_current_receiver_offset = connp->out_current_read_offset;
139
140
56.0k
    return rc;
141
56.0k
}
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.31M
static htp_status_t htp_res_handle_state_change(htp_connp_t *connp) {
151
1.31M
    if (connp->out_state_previous == connp->out_state) return HTP_OK;
152
153
433k
    if (connp->out_state == htp_connp_RES_HEADERS) {
154
56.0k
        htp_status_t rc = HTP_OK;
155
156
56.0k
        switch (connp->out_tx->response_progress) {
157
46.6k
            case HTP_RESPONSE_HEADERS:
158
46.6k
                rc = htp_connp_res_receiver_set(connp, connp->out_tx->cfg->hook_response_header_data);
159
46.6k
                break;
160
161
9.43k
            case HTP_RESPONSE_TRAILER:
162
9.43k
                rc = htp_connp_res_receiver_set(connp, connp->out_tx->cfg->hook_response_trailer_data);
163
9.43k
                break;
164
165
0
            default:
166
                // Do nothing; receivers are currently used only for header blocks.
167
0
                break;
168
56.0k
        }
169
170
56.0k
        if (rc != HTP_OK) return rc;
171
56.0k
    }
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
433k
    connp->out_state_previous = connp->out_state;
183
184
433k
    return HTP_OK;
185
433k
}
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
213k
static htp_status_t htp_connp_res_buffer(htp_connp_t *connp) {
196
213k
    if (connp->out_current_data == NULL) return HTP_OK;
197
    
198
211k
    unsigned char *data = connp->out_current_data + connp->out_current_consume_offset;
199
211k
    size_t len = connp->out_current_read_offset - connp->out_current_consume_offset;
200
201
    // Check the hard (buffering) limit.
202
203
211k
    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
211k
    if (connp->out_header != NULL) {
208
17.0k
        newlen += bstr_len(connp->out_header);
209
17.0k
    }
210
211
211k
    if (newlen > connp->out_tx->cfg->field_limit_hard) {
212
21
        htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Response the buffer limit: size %zd limit %zd.",
213
21
                newlen, connp->out_tx->cfg->field_limit_hard);
214
21
        return HTP_ERROR;
215
21
    }
216
217
    // Copy the data remaining in the buffer.
218
219
211k
    if (connp->out_buf == NULL) {
220
69.9k
        connp->out_buf = malloc(len);
221
69.9k
        if (connp->out_buf == NULL) return HTP_ERROR;
222
69.9k
        memcpy(connp->out_buf, data, len);
223
69.9k
        connp->out_buf_size = len;
224
141k
    } else {
225
141k
        size_t newsize = connp->out_buf_size + len;
226
141k
        unsigned char *newbuf = realloc(connp->out_buf, newsize);
227
141k
        if (newbuf == NULL) return HTP_ERROR;
228
141k
        connp->out_buf = newbuf;
229
141k
        memcpy(connp->out_buf + connp->out_buf_size, data, len);
230
141k
        connp->out_buf_size = newsize;
231
141k
    }
232
233
    // Reset the consumer position.
234
211k
    connp->out_current_consume_offset = connp->out_current_read_offset;
235
236
211k
    return HTP_OK;
237
211k
}
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.56M
static htp_status_t htp_connp_res_consolidate_data(htp_connp_t *connp, unsigned char **data, size_t *len) {    
250
1.56M
    if (connp->out_buf == NULL) {
251
        // We do not have any data buffered; point to the current data chunk.
252
1.49M
        *data = connp->out_current_data + connp->out_current_consume_offset;
253
1.49M
        *len = connp->out_current_read_offset - connp->out_current_consume_offset;
254
1.49M
    } else {
255
        // We do have data in the buffer. Add data from the current
256
        // chunk, and point to the consolidated buffer.
257
69.7k
        if (htp_connp_res_buffer(connp) != HTP_OK) {
258
12
            return HTP_ERROR;
259
12
        }
260
261
69.7k
        *data = connp->out_buf;
262
69.7k
        *len = connp->out_buf_size;
263
69.7k
    }
264
265
1.56M
    return HTP_OK;
266
1.56M
}
267
268
/**
269
 * Clears buffered outbound data and resets the consumer position to the reader position.
270
 *
271
 * @param[in] connp
272
 */
273
1.52M
static void htp_connp_res_clear_buffer(htp_connp_t *connp) {
274
1.52M
    connp->out_current_consume_offset = connp->out_current_read_offset;
275
276
1.52M
    if (connp->out_buf != NULL) {
277
67.0k
        free(connp->out_buf);
278
67.0k
        connp->out_buf = NULL;
279
67.0k
        connp->out_buf_size = 0;
280
67.0k
    }
281
1.52M
}
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.2k
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.2k
    if (connp->out_status == HTP_STREAM_CLOSED) {
293
20
        connp->out_state = htp_connp_RES_FINALIZE;
294
        // Sends close signal to decompressors
295
20
        htp_status_t rc = htp_tx_res_process_body_data_ex(connp->out_tx, NULL, 0);
296
20
        return rc;
297
20
    }
298
299
146k
    for (;;) {
300
146k
        OUT_NEXT_BYTE_OR_RETURN(connp);
301
302
145k
        connp->out_tx->response_message_len++;
303
304
145k
        if (connp->out_next_byte == LF) {
305
10.4k
            connp->out_state = htp_connp_RES_BODY_CHUNKED_LENGTH;
306
307
10.4k
            return HTP_OK;
308
10.4k
        }
309
145k
    }
310
311
0
    return HTP_ERROR;
312
11.2k
}
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.1k
htp_status_t htp_connp_RES_BODY_CHUNKED_DATA(htp_connp_t *connp) {
321
14.1k
    size_t bytes_to_consume;
322
323
    // Determine how many bytes we can consume.
324
14.1k
    if (connp->out_current_len - connp->out_current_read_offset >= connp->out_chunked_length) {
325
10.5k
        bytes_to_consume = connp->out_chunked_length;
326
10.5k
    } else {
327
3.57k
        bytes_to_consume = connp->out_current_len - connp->out_current_read_offset;
328
3.57k
    }
329
330
14.1k
    if (connp->out_status == HTP_STREAM_CLOSED) {
331
49
        connp->out_state = htp_connp_RES_FINALIZE;
332
        // Sends close signal to decompressors
333
49
        htp_status_t rc = htp_tx_res_process_body_data_ex(connp->out_tx, NULL, 0);
334
49
        return rc;
335
49
    }
336
14.0k
    if (bytes_to_consume == 0) return HTP_DATA;
337
338
    // Consume the data.
339
13.6k
    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
13.6k
    if (rc != HTP_OK) return rc;
341
342
    // Adjust the counters.
343
13.6k
    connp->out_current_read_offset += bytes_to_consume;
344
13.6k
    connp->out_current_consume_offset += bytes_to_consume;
345
13.6k
    connp->out_stream_offset += bytes_to_consume;
346
13.6k
    connp->out_chunked_length -= bytes_to_consume;
347
348
    // Have we seen the entire chunk?
349
13.6k
    if (connp->out_chunked_length == 0) {
350
10.5k
        connp->out_state = htp_connp_RES_BODY_CHUNKED_DATA_END;
351
10.5k
        return HTP_OK;
352
10.5k
    }
353
354
3.13k
    return HTP_DATA;
355
13.6k
}
356
357
5.64M
static inline int is_chunked_ctl_char(const unsigned char c) {
358
5.64M
    switch (c) {
359
1.12M
        case 0x0d:
360
1.12M
        case 0x0a:
361
1.15M
        case 0x20:
362
4.41M
        case 0x09:
363
4.54M
        case 0x0b:
364
4.55M
        case 0x0c:
365
4.55M
            return 1;
366
1.08M
        default:
367
1.08M
            return 0;
368
5.64M
    }
369
5.64M
}
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
543k
static inline int data_probe_chunk_length(htp_connp_t *connp) {
378
543k
    unsigned char *data = connp->out_current_data + connp->out_current_consume_offset;
379
543k
    size_t len = connp->out_current_read_offset - connp->out_current_consume_offset;
380
381
543k
    size_t i = 0;
382
5.04M
    while (i < len) {
383
5.04M
        unsigned char c = data[i];
384
385
5.04M
        if (is_chunked_ctl_char(c)) {
386
            // ctl char, still good.
387
4.49M
        } else if (isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
388
            // real chunklen char
389
455k
            return 1;
390
455k
        } else {
391
            // leading junk, bad
392
88.1k
            return 0;
393
88.1k
        }
394
4.49M
        i++;
395
4.49M
    }
396
0
    return 1;
397
543k
}
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
23.1k
htp_status_t htp_connp_RES_BODY_CHUNKED_LENGTH(htp_connp_t *connp) {
406
23.1k
    if (connp->out_status == HTP_STREAM_CLOSED) {
407
59
        connp->out_state = htp_connp_RES_FINALIZE;
408
        // Sends close signal to decompressors
409
59
        htp_status_t rc = htp_tx_res_process_body_data_ex(connp->out_tx, NULL, 0);
410
59
        return rc;
411
59
    }
412
413
629k
    for (;;) {
414
629k
        OUT_COPY_BYTE_OR_RETURN(connp);
415
416
        // Have we reached the end of the line? Or is this not chunked after all?
417
626k
        if (connp->out_next_byte == LF ||
418
604k
                (!is_chunked_ctl_char((unsigned char) connp->out_next_byte) && !data_probe_chunk_length(connp) && connp->out_buf == NULL)) {
419
22.3k
            unsigned char *data;
420
22.3k
            size_t len;
421
422
22.3k
            if (htp_connp_res_consolidate_data(connp, &data, &len) != HTP_OK) {
423
2
                return HTP_ERROR;
424
2
            }
425
426
22.3k
            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
22.3k
            int chunk_ext = 0;
433
22.3k
            connp->out_chunked_length = htp_parse_chunked_length(data, len, &chunk_ext);
434
22.3k
            if (chunk_ext == 1) {
435
2.78k
                htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Request chunk extension");
436
2.78k
            }
437
            // empty chunk length line, lets try to continue
438
22.3k
            if (connp->out_chunked_length == -1004) {
439
2.05k
                connp->out_current_consume_offset = connp->out_current_read_offset;
440
2.05k
                continue;
441
2.05k
            }
442
20.3k
            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
212
                if (len > (size_t)connp->out_current_read_offset) {
447
16
                    connp->out_current_read_offset = 0;
448
196
                } else {
449
196
                    connp->out_current_read_offset -= len;
450
196
                }
451
452
212
                connp->out_state = htp_connp_RES_BODY_IDENTITY_STREAM_CLOSE;
453
212
                connp->out_tx->response_transfer_coding = HTP_CODING_IDENTITY;
454
455
212
                htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0,
456
212
                        "Response chunk encoding: Invalid chunk length: %"PRId64"",
457
212
                        connp->out_chunked_length);
458
212
                return HTP_OK;
459
212
            }
460
20.0k
            htp_connp_res_clear_buffer(connp);
461
462
            // Handle chunk length
463
20.0k
            if (connp->out_chunked_length > 0) {
464
                // More data available
465
10.6k
                connp->out_state = htp_connp_RES_BODY_CHUNKED_DATA;
466
10.6k
            } else if (connp->out_chunked_length == 0) {
467
                // End of data
468
9.43k
                connp->out_state = htp_connp_RES_HEADERS;
469
9.43k
                connp->out_tx->response_progress = HTP_RESPONSE_TRAILER;
470
9.43k
            }
471
472
20.0k
            return HTP_OK;
473
20.3k
        }
474
626k
    }
475
476
0
    return HTP_ERROR;
477
23.1k
}
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
17.3k
htp_status_t htp_connp_RES_BODY_IDENTITY_CL_KNOWN(htp_connp_t *connp) {
486
17.3k
    size_t bytes_to_consume;   
487
        
488
    // Determine how many bytes we can consume.
489
17.3k
    if (connp->out_current_len - connp->out_current_read_offset >= connp->out_body_data_left) {
490
8.48k
        bytes_to_consume = connp->out_body_data_left;
491
8.90k
    } else {
492
8.90k
        bytes_to_consume = connp->out_current_len - connp->out_current_read_offset;
493
8.90k
    }       
494
    
495
17.3k
    if (connp->out_status == HTP_STREAM_CLOSED) {
496
78
        connp->out_state = htp_connp_RES_FINALIZE;
497
        // Sends close signal to decompressors
498
78
        htp_status_t rc = htp_tx_res_process_body_data_ex(connp->out_tx, NULL, 0);
499
78
        return rc;
500
78
    }
501
17.3k
    if (bytes_to_consume == 0) return HTP_DATA;    
502
503
    // Consume the data.
504
16.7k
    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
16.7k
    if (rc != HTP_OK) return rc;
506
507
    // Adjust the counters.
508
16.7k
    connp->out_current_read_offset += bytes_to_consume;
509
16.7k
    connp->out_current_consume_offset += bytes_to_consume;
510
16.7k
    connp->out_stream_offset += bytes_to_consume;
511
16.7k
    connp->out_body_data_left -= bytes_to_consume;
512
513
    // Have we seen the entire response body?
514
16.7k
    if (connp->out_body_data_left == 0) {
515
8.48k
        connp->out_state = htp_connp_RES_FINALIZE;
516
        // Tells decompressors to output partially decompressed data
517
8.48k
        rc = htp_tx_res_process_body_data_ex(connp->out_tx, NULL, 0);
518
8.48k
        return rc;
519
8.48k
    }
520
521
8.27k
    return HTP_DATA;
522
16.7k
}
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
44.8k
htp_status_t htp_connp_RES_BODY_IDENTITY_STREAM_CLOSE(htp_connp_t *connp) {        
532
    // Consume all data from the input buffer.
533
44.8k
    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
44.8k
    if (bytes_to_consume != 0) {
539
42.7k
        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
42.7k
        if (rc != HTP_OK) return rc;
541
542
        // Adjust the counters.
543
42.7k
        connp->out_current_read_offset += bytes_to_consume;
544
42.7k
        connp->out_current_consume_offset += bytes_to_consume;
545
42.7k
        connp->out_stream_offset += bytes_to_consume;        
546
42.7k
    }
547
548
    // Have we seen the entire response body?
549
44.8k
    if (connp->out_status == HTP_STREAM_CLOSED) {
550
891
        connp->out_state = htp_connp_RES_FINALIZE;
551
891
        return HTP_OK;
552
891
    }
553
   
554
43.9k
    return HTP_DATA;
555
44.8k
}
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.0k
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.0k
    if (connp->out_tx->request_method_number == HTP_M_CONNECT) {
568
2.03k
        if ((connp->out_tx->response_status_number >= 200)
569
1.87k
                && (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
1.87k
            connp->out_state = htp_connp_RES_FINALIZE;
576
577
            // we may have response headers
578
1.87k
            htp_status_t rc = htp_tx_state_response_headers(connp->out_tx);
579
1.87k
            return rc;
580
1.87k
        } 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
160
        } else {
585
            // This is a failed CONNECT stream, which means that
586
            // we can unblock request parsing
587
160
            if (connp->in_status != HTP_STREAM_ERROR)
588
160
                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
160
            connp->out_data_other_at_tx_end = 1;
594
160
        }
595
2.03k
    }
596
597
43.2k
    htp_header_t *cl = htp_table_get_c(connp->out_tx->response_headers, "content-length");
598
43.2k
    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.2k
    if (connp->out_tx->response_status_number == 101) {
607
507
        if (te == NULL && cl == NULL) {
608
188
            connp->out_state = htp_connp_RES_FINALIZE;
609
610
188
            if (connp->in_status != HTP_STREAM_ERROR)
611
188
                connp->in_status = HTP_STREAM_TUNNEL;
612
188
            connp->out_status = HTP_STREAM_TUNNEL;
613
614
            // we may have response headers
615
188
            htp_status_t rc = htp_tx_state_response_headers(connp->out_tx);
616
188
            return rc;
617
319
        } else {
618
319
            htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Switching Protocol with Content-Length");
619
319
        }
620
507
    }
621
622
    // Check for an interim "100 Continue" response. Ignore it if found, and revert back to RES_LINE.
623
43.0k
    if (connp->out_tx->response_status_number == 100 && te == NULL) {
624
2.58k
        int is100continue = 1;
625
2.58k
        if (cl != NULL){
626
198
            if (htp_parse_content_length(cl->value, connp) > 0) {
627
158
                is100continue = 0;
628
158
            }
629
198
        }
630
2.58k
        if (is100continue) {
631
2.42k
            if (connp->out_tx->seen_100continue != 0) {
632
1.26k
                htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Already seen 100-Continue.");
633
1.26k
            }
634
635
            // Ignore any response headers seen so far.
636
2.42k
            htp_header_t *h = NULL;
637
5.31k
            for (size_t i = 0, n = htp_table_size(connp->out_tx->response_headers); i < n; i++) {
638
2.88k
                h = htp_table_get_index(connp->out_tx->response_headers, i, NULL);
639
2.88k
                bstr_free(h->name);
640
2.88k
                bstr_free(h->value);
641
2.88k
                free(h);
642
2.88k
            }
643
644
2.42k
            htp_table_clear(connp->out_tx->response_headers);
645
646
            // Expecting to see another response line next.
647
2.42k
            connp->out_state = htp_connp_RES_LINE;
648
2.42k
            connp->out_tx->response_progress = HTP_RESPONSE_LINE;
649
2.42k
            connp->out_tx->seen_100continue++;
650
651
2.42k
            return HTP_OK;
652
2.42k
        }
653
2.58k
    }
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.6k
    if (connp->out_tx->response_status_number >= 400 &&
659
1.50k
        connp->out_tx->response_status_number <= 499 &&
660
1.15k
        connp->in_content_length > 0 &&
661
257
        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.6k
    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.6k
    else if (((connp->out_tx->response_status_number >= 100) && (connp->out_tx->response_status_number <= 199))
679
28.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
15.0k
        if (te == NULL && cl == NULL) {
683
13.1k
            connp->out_tx->response_transfer_coding = HTP_CODING_NO_BODY;
684
13.1k
            connp->out_state = htp_connp_RES_FINALIZE;
685
13.1k
        } else {
686
1.86k
            htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Unexpected Response body");
687
1.86k
        }
688
15.0k
    }
689
    // Hack condition to check that we do not assume "no body"
690
40.6k
    if (connp->out_state != htp_connp_RES_FINALIZE) {
691
        // We have a response body
692
27.4k
        htp_header_t *ct = htp_table_get_c(connp->out_tx->response_headers, "content-type");
693
27.4k
        if (ct != NULL) {
694
7.95k
            connp->out_tx->response_content_type = bstr_dup_lower(ct->value);
695
7.95k
            if (connp->out_tx->response_content_type == NULL) return HTP_ERROR;
696
697
            // Ignore parameters
698
7.95k
            unsigned char *data = bstr_ptr(connp->out_tx->response_content_type);
699
7.95k
            size_t len = bstr_len(ct->value);
700
7.95k
            size_t newlen = 0;
701
106k
            while (newlen < len) {
702
                // TODO Some platforms may do things differently here.
703
101k
                if (htp_is_space(data[newlen]) || (data[newlen] == ';')) {
704
3.71k
                    bstr_adjust_len(connp->out_tx->response_content_type, newlen);
705
3.71k
                    break;
706
3.71k
                }
707
708
98.0k
                newlen++;
709
98.0k
            }
710
7.95k
        }
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
27.4k
        if ((te != NULL) && (bstr_index_of_c_nocasenorzero(te->value, "chunked") != -1)) {
716
9.94k
            if (bstr_cmp_c_nocase(te->value, "chunked") != 0) {
717
7.58k
                htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0,
718
7.58k
                        "Transfer-encoding has abnormal chunked value");
719
7.58k
            }
720
721
            // spec says chunked is HTTP/1.1 only, but some browsers accept it
722
            // with 1.0 as well
723
9.94k
            if (connp->out_tx->response_protocol_number < HTP_PROTOCOL_1_1) {
724
8.54k
                htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0,
725
8.54k
                        "Chunked transfer-encoding on HTTP/0.9 or HTTP/1.0");
726
8.54k
            }
727
728
            // If the T-E header is present we are going to use it.
729
9.94k
            connp->out_tx->response_transfer_coding = HTP_CODING_CHUNKED;
730
731
            // We are still going to check for the presence of C-L
732
9.94k
            if (cl != NULL) {
733
                // This is a violation of the RFC
734
438
                connp->out_tx->flags |= HTP_REQUEST_SMUGGLING;
735
438
            }
736
737
9.94k
            connp->out_state = htp_connp_RES_BODY_CHUNKED_LENGTH;
738
9.94k
            connp->out_tx->response_progress = HTP_RESPONSE_BODY;
739
9.94k
        }// 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
17.4k
        else if (cl != NULL) {
742
            // We know the exact length
743
15.2k
            connp->out_tx->response_transfer_coding = HTP_CODING_IDENTITY;
744
745
            // Check for multiple C-L headers
746
15.2k
            if (cl->flags & HTP_FIELD_REPEATED) {
747
5.01k
                connp->out_tx->flags |= HTP_REQUEST_SMUGGLING;
748
5.01k
            }
749
750
            // Get body length
751
15.2k
            connp->out_tx->response_content_length = htp_parse_content_length(cl->value, connp);
752
15.2k
            if (connp->out_tx->response_content_length < 0) {
753
34
                htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Invalid C-L field in response: %"PRId64"",
754
34
                        connp->out_tx->response_content_length);
755
34
                return HTP_ERROR;
756
15.2k
            } else {
757
15.2k
                connp->out_content_length = connp->out_tx->response_content_length;
758
15.2k
                connp->out_body_data_left = connp->out_content_length;
759
760
15.2k
                if (connp->out_content_length != 0) {
761
8.85k
                    connp->out_state = htp_connp_RES_BODY_IDENTITY_CL_KNOWN;
762
8.85k
                    connp->out_tx->response_progress = HTP_RESPONSE_BODY;
763
8.85k
                } else {                    
764
6.34k
                    connp->out_state = htp_connp_RES_FINALIZE;
765
6.34k
                }
766
15.2k
            }
767
15.2k
        } 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.24k
            if (ct != NULL) {
775
                // TODO Handle multipart/byteranges
776
303
                if (bstr_index_of_c_nocase(ct->value, "multipart/byteranges") != -1) {
777
3
                    htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0,
778
3
                            "C-T multipart/byteranges in responses not supported");
779
3
                    return HTP_ERROR;
780
3
                }
781
303
            }
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.24k
            connp->out_state = htp_connp_RES_BODY_IDENTITY_STREAM_CLOSE;
787
2.24k
            connp->out_tx->response_transfer_coding = HTP_CODING_IDENTITY;
788
2.24k
            connp->out_tx->response_progress = HTP_RESPONSE_BODY;
789
2.24k
            connp->out_body_data_left = -1;
790
2.24k
        }
791
27.4k
    }
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.5k
    htp_status_t rc = htp_tx_state_response_headers(connp->out_tx);
797
40.5k
    if (rc != HTP_OK) return rc;
798
799
40.5k
    return HTP_OK;
800
40.5k
}
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
96.6k
htp_status_t htp_connp_RES_HEADERS(htp_connp_t *connp) {
809
96.6k
    int endwithcr;
810
96.6k
    int lfcrending = 0;
811
812
20.4M
    for (;;) {
813
20.4M
        if (connp->out_status == HTP_STREAM_CLOSED) {
814
            // Finalize sending raw trailer data.
815
868
            htp_status_t rc = htp_connp_res_receiver_finalize_clear(connp);
816
868
            if (rc != HTP_OK) return rc;
817
818
            // Run hook response_TRAILER.
819
868
            rc = htp_hook_run_all(connp->cfg->hook_response_trailer, connp->out_tx);
820
868
            if (rc != HTP_OK) return rc;
821
822
868
            connp->out_state = htp_connp_RES_FINALIZE;
823
868
            return HTP_OK;
824
868
        }
825
20.4M
        OUT_COPY_BYTE_OR_RETURN(connp);
826
827
        // Have we reached the end of the line?
828
20.3M
        if (connp->out_next_byte != LF && connp->out_next_byte != CR) {
829
19.6M
            lfcrending = 0;
830
19.6M
        } else {
831
692k
            endwithcr = 0;
832
692k
            if (connp->out_next_byte == CR) {
833
424k
                OUT_PEEK_NEXT(connp);
834
424k
                if (connp->out_next_byte == -1) {
835
926
                    return HTP_DATA_BUFFER;
836
423k
                } else if (connp->out_next_byte == LF) {
837
164k
                    OUT_COPY_BYTE_OR_RETURN(connp);
838
164k
                    if (lfcrending) {
839
                        // Handling LFCRCRLFCRLF
840
                        // These 6 characters mean only 2 end of lines
841
4.18k
                        OUT_PEEK_NEXT(connp);
842
4.18k
                        if (connp->out_next_byte == CR) {
843
2.85k
                            OUT_COPY_BYTE_OR_RETURN(connp);
844
2.85k
                            connp->out_current_consume_offset++;
845
2.85k
                            OUT_PEEK_NEXT(connp);
846
2.85k
                            if (connp->out_next_byte == LF) {
847
806
                                OUT_COPY_BYTE_OR_RETURN(connp);
848
806
                                connp->out_current_consume_offset++;
849
806
                                htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0,
850
806
                                        "Weird response end of lines mix");
851
806
                            }
852
2.85k
                        }
853
4.18k
                    }
854
258k
                } else if (connp->out_next_byte == CR) {
855
163k
                    continue;
856
163k
                }
857
260k
                lfcrending = 0;
858
260k
                endwithcr = 1;
859
268k
            } else {
860
                // connp->out_next_byte == LF
861
268k
                OUT_PEEK_NEXT(connp);
862
268k
                lfcrending = 0;
863
268k
                if (connp->out_next_byte == CR) {
864
                    // hanldes LF-CR sequence as end of line
865
38.9k
                    OUT_COPY_BYTE_OR_RETURN(connp);
866
38.9k
                    lfcrending = 1;
867
38.9k
                }
868
268k
            }
869
870
528k
            unsigned char *data;
871
528k
            size_t len;
872
873
528k
            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
528k
            if (endwithcr && len < 2) {
879
7.58k
                continue;
880
7.58k
            }
881
882
            #ifdef HTP_DEBUG
883
            fprint_raw_data(stderr, __func__, data, len);
884
            #endif
885
886
520k
            int next_no_lf = 0;
887
520k
            if (connp->out_current_read_offset < connp->out_current_len &&
888
500k
                connp->out_current_data[connp->out_current_read_offset] != LF) {
889
436k
                next_no_lf = 1;
890
436k
            }
891
            // Should we terminate headers?
892
520k
            if (htp_connp_is_line_terminator(connp, data, len, next_no_lf)) {
893
                // Parse previous header, if any.
894
54.4k
                if (connp->out_header != NULL) {
895
5.57k
                    if (connp->cfg->process_response_header(connp, bstr_ptr(connp->out_header),
896
5.57k
                            bstr_len(connp->out_header)) != HTP_OK) return HTP_ERROR;
897
898
5.57k
                    bstr_free(connp->out_header);
899
5.57k
                    connp->out_header = NULL;
900
5.57k
                }
901
902
54.4k
                htp_connp_res_clear_buffer(connp);
903
904
                // We've seen all response headers.
905
54.4k
                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.0k
                    connp->out_state = htp_connp_RES_BODY_DETERMINE;
910
45.0k
                } else {
911
                    // Response trailer.
912
913
                    // Finalize sending raw trailer data.
914
9.40k
                    htp_status_t rc = htp_connp_res_receiver_finalize_clear(connp);
915
9.40k
                    if (rc != HTP_OK) return rc;
916
917
                    // Run hook response_TRAILER.
918
9.40k
                    rc = htp_hook_run_all(connp->cfg->hook_response_trailer, connp->out_tx);
919
9.40k
                    if (rc != HTP_OK) return rc;
920
921
                    // The next step is to finalize this response.
922
9.40k
                    connp->out_state = htp_connp_RES_FINALIZE;
923
9.40k
                }
924
925
54.4k
                return HTP_OK;
926
54.4k
            }
927
928
466k
            htp_chomp(data, &len);
929
930
            // Check for header folding.
931
466k
            if (htp_connp_is_line_folded(data, len) == 0) {
932
                // New header line.
933
934
                // Parse previous header, if any.
935
292k
                if (connp->out_header != NULL) {
936
35.0k
                    if (connp->cfg->process_response_header(connp, bstr_ptr(connp->out_header),
937
35.0k
                            bstr_len(connp->out_header)) != HTP_OK) return HTP_ERROR;
938
939
35.0k
                    bstr_free(connp->out_header);
940
35.0k
                    connp->out_header = NULL;
941
35.0k
                }
942
943
292k
                OUT_PEEK_NEXT(connp);
944
945
292k
                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
274k
                    if (connp->cfg->process_response_header(connp, data, len) != HTP_OK) return HTP_ERROR;
948
274k
                } else {
949
                    // Keep the partial header data for parsing later.
950
18.5k
                    connp->out_header = bstr_dup_mem(data, len);
951
18.5k
                    if (connp->out_header == NULL) return HTP_ERROR;
952
18.5k
                }
953
292k
            } else {
954
                // Folding; check that there's a previous header line to add to.
955
173k
                if (connp->out_header == NULL) {
956
                    // Invalid folding.
957
958
                    // Warn only once per transaction.
959
22.5k
                    if (!(connp->out_tx->flags & HTP_INVALID_FOLDING)) {
960
11.8k
                        connp->out_tx->flags |= HTP_INVALID_FOLDING;
961
11.8k
                        htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Invalid response field folding");
962
11.8k
                    }
963
964
                    // Keep the header data for parsing later.
965
22.5k
                    size_t trim = 0;
966
69.8k
                    while(trim < len) {
967
57.9k
                        if (!htp_is_folding_char(data[trim])) {
968
10.5k
                            break;
969
10.5k
                        }
970
47.3k
                        trim++;
971
47.3k
                    }
972
22.5k
                    connp->out_header = bstr_dup_mem(data + trim, len - trim);
973
22.5k
                    if (connp->out_header == NULL) return HTP_ERROR;
974
150k
                } else {
975
150k
                    size_t colon_pos = 0;
976
3.00M
                    while ((colon_pos < len) && (data[colon_pos] != ':')) colon_pos++;
977
978
150k
                    if (colon_pos < len &&
979
35.5k
                        bstr_chr(connp->out_header, ':') >= 0 &&
980
30.7k
                        connp->out_tx->response_protocol_number == HTP_PROTOCOL_1_1) {
981
                        // Warn only once per transaction.
982
928
                        if (!(connp->out_tx->flags & HTP_INVALID_FOLDING)) {
983
187
                            connp->out_tx->flags |= HTP_INVALID_FOLDING;
984
187
                            htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Invalid response field folding");
985
187
                        }
986
928
                        if (connp->cfg->process_response_header(connp, bstr_ptr(connp->out_header),
987
928
                            bstr_len(connp->out_header)) != HTP_OK)
988
0
                            return HTP_ERROR;
989
928
                        bstr_free(connp->out_header);
990
928
                        connp->out_header = bstr_dup_mem(data+1, len-1);
991
928
                        if (connp->out_header == NULL)
992
0
                            return HTP_ERROR;
993
150k
                    } else {
994
                        // Add to the existing header.
995
150k
                        if (bstr_len(connp->out_header) < HTP_MAX_HEADER_FOLDED) {
996
142k
                            bstr *new_out_header = bstr_add_mem(connp->out_header, data, len);
997
142k
                            if (new_out_header == NULL)
998
0
                                return HTP_ERROR;
999
142k
                            connp->out_header = new_out_header;
1000
142k
                        } else {
1001
7.39k
                            htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Response field length exceeds folded maximum");
1002
7.39k
                        }
1003
150k
                    }
1004
150k
                }
1005
173k
            }
1006
1007
466k
            htp_connp_res_clear_buffer(connp);
1008
466k
        }
1009
20.3M
    }
1010
1011
0
    return HTP_ERROR;
1012
96.6k
}
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
800k
htp_status_t htp_connp_RES_LINE(htp_connp_t *connp) {
1021
23.9M
    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
23.9M
        if (connp->out_status != HTP_STREAM_CLOSED) {
1024
            // Get one byte
1025
23.9M
            OUT_COPY_BYTE_OR_RETURN(connp);
1026
23.9M
        }
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
23.9M
        if (connp->out_next_byte == CR) {
1032
365k
            OUT_PEEK_NEXT(connp);
1033
365k
            if (connp->out_next_byte == -1) {
1034
4.00k
                return HTP_DATA_BUFFER;
1035
361k
            } else if (connp->out_next_byte == LF) {
1036
72.6k
                continue;
1037
72.6k
            }
1038
288k
            connp->out_next_byte = LF;
1039
288k
        }
1040
23.8M
        if ((connp->out_next_byte == LF)||(connp->out_status == HTP_STREAM_CLOSED)) {
1041
733k
            unsigned char *data;
1042
733k
            size_t len;
1043
1044
733k
            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
733k
            if (htp_connp_is_line_ignorable(connp, data, len)) {
1054
328k
                if (connp->out_status == HTP_STREAM_CLOSED) {
1055
7
                    connp->out_state = htp_connp_RES_FINALIZE;
1056
7
                }
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
404k
            if (connp->out_tx->response_line != NULL) {
1071
2.42k
                bstr_free(connp->out_tx->response_line);
1072
2.42k
                connp->out_tx->response_line = NULL;
1073
2.42k
            }
1074
1075
404k
            if (connp->out_tx->response_protocol != NULL) {
1076
2.42k
                bstr_free(connp->out_tx->response_protocol);
1077
2.42k
                connp->out_tx->response_protocol = NULL;
1078
2.42k
            }
1079
1080
404k
            if (connp->out_tx->response_status != NULL) {
1081
2.42k
                bstr_free(connp->out_tx->response_status);
1082
2.42k
                connp->out_tx->response_status = NULL;
1083
2.42k
            }
1084
1085
404k
            if (connp->out_tx->response_message != NULL) {
1086
2.10k
                bstr_free(connp->out_tx->response_message);
1087
2.10k
                connp->out_tx->response_message = NULL;
1088
2.10k
            }
1089
1090
            // Process response line.           
1091
1092
404k
            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
404k
            if (htp_treat_response_line_as_body(data, len)) {
1099
                // if we have a next line beginning with H, skip this one
1100
358k
                if (connp->out_current_read_offset+1 < connp->out_current_len && (connp->out_current_data[connp->out_current_read_offset] == 'H' || len <= 2)) {
1101
69.2k
                    connp->out_tx->response_ignored_lines++;
1102
69.2k
                    htp_connp_res_clear_buffer(connp);
1103
69.2k
                    return HTP_OK;
1104
69.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
49.6k
                    connp->out_tx->response_transfer_coding = HTP_CODING_IDENTITY;
1119
49.6k
                    connp->out_tx->response_progress = HTP_RESPONSE_BODY;
1120
49.6k
                    connp->out_body_data_left = -1;
1121
49.6k
                    connp->out_state = htp_connp_RES_FINALIZE;
1122
49.6k
                }
1123
1124
289k
                return HTP_OK;
1125
289k
            }
1126
1127
46.6k
            connp->out_tx->response_line = bstr_dup_mem(data, len);
1128
46.6k
            if (connp->out_tx->response_line == NULL) return HTP_ERROR;
1129
1130
46.6k
            if (connp->cfg->parse_response_line(connp) != HTP_OK) return HTP_ERROR;
1131
1132
46.6k
            htp_status_t rc = htp_tx_state_response_line(connp->out_tx);
1133
46.6k
            if (rc != HTP_OK) return rc;
1134
1135
46.6k
            htp_connp_res_clear_buffer(connp);
1136
1137
            // Move on to the next phase.
1138
46.6k
            connp->out_state = htp_connp_RES_HEADERS;
1139
46.6k
            connp->out_tx->response_progress = HTP_RESPONSE_HEADERS;
1140
1141
46.6k
            return HTP_OK;
1142
46.6k
        }
1143
23.8M
    }
1144
1145
0
    return HTP_ERROR;
1146
800k
}
1147
1148
186k
size_t htp_connp_res_data_consumed(htp_connp_t *connp) {
1149
186k
    return connp->out_current_read_offset;
1150
186k
}
1151
1152
371k
htp_status_t htp_connp_RES_FINALIZE(htp_connp_t *connp) {
1153
371k
    if (connp->out_status != HTP_STREAM_CLOSED) {
1154
368k
        OUT_PEEK_NEXT(connp);
1155
368k
        if (connp->out_next_byte == -1) {
1156
62.1k
            return htp_tx_state_response_complete_ex(connp->out_tx, 0);
1157
62.1k
        }
1158
306k
        if (connp->out_next_byte != LF || connp->out_current_consume_offset >= connp->out_current_read_offset) {
1159
12.1M
            for (;;) {//;i < max_read; i++) {
1160
12.1M
                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
12.1M
                if (connp->out_next_byte == LF)
1164
273k
                    break;
1165
12.1M
            }
1166
306k
        }
1167
306k
    }
1168
276k
    size_t bytes_left;
1169
276k
    unsigned char * data;
1170
1171
276k
    if (htp_connp_res_consolidate_data(connp, &data, &bytes_left) != HTP_OK) {
1172
3
        return HTP_ERROR;
1173
3
    }
1174
#ifdef HTP_DEBUG
1175
    fprint_raw_data(stderr, "PROBING response finalize", data, bytes_left);
1176
#endif
1177
276k
    if (bytes_left == 0) {
1178
        //closing
1179
2.13k
        return htp_tx_state_response_complete_ex(connp->out_tx, 0);
1180
2.13k
    }
1181
1182
274k
    if (htp_treat_response_line_as_body(data, bytes_left)) {
1183
        // Interpret remaining bytes as body data
1184
248k
        htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Unexpected response body");
1185
248k
        htp_status_t rc = htp_tx_res_process_body_data_ex(connp->out_tx, data, bytes_left);
1186
248k
        htp_connp_res_clear_buffer(connp);
1187
248k
        return rc;
1188
248k
    }
1189
1190
    //unread last end of line so that RES_LINE works
1191
25.9k
    if (connp->out_current_read_offset < (int64_t)bytes_left) {
1192
2.07k
        connp->out_current_read_offset=0;
1193
23.8k
    } else {
1194
23.8k
        connp->out_current_read_offset-=bytes_left;
1195
23.8k
    }
1196
25.9k
    if (connp->out_current_read_offset < connp->out_current_consume_offset) {
1197
2.04k
        connp->out_current_consume_offset=connp->out_current_read_offset;
1198
2.04k
    }
1199
25.9k
    return htp_tx_state_response_complete_ex(connp->out_tx, 0 /* not hybrid mode */);
1200
274k
}
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
160k
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
160k
    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
95.8k
    connp->out_tx = htp_list_get(connp->conn->transactions, connp->out_next_tx_index);
1224
95.8k
    if (connp->out_tx == NULL) {
1225
51.5k
        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
51.5k
        if (connp->in_state == htp_connp_REQ_FINALIZE) {
1228
28.5k
            htp_tx_state_request_complete(connp->in_tx);
1229
28.5k
        }
1230
51.5k
        connp->out_tx = htp_connp_tx_create(connp);
1231
51.5k
        if (connp->out_tx == NULL) {
1232
16
            return HTP_ERROR;
1233
16
        }
1234
51.4k
        connp->out_tx->parsed_uri = htp_uri_alloc();
1235
51.4k
        if (connp->out_tx->parsed_uri == NULL) {
1236
0
            return HTP_ERROR;
1237
0
        }
1238
51.4k
        connp->out_tx->parsed_uri->path = bstr_dup_c(REQUEST_URI_NOT_SEEN);
1239
51.4k
        if (connp->out_tx->parsed_uri->path == NULL) {
1240
0
            return HTP_ERROR;
1241
0
        }
1242
51.4k
        connp->out_tx->request_uri = bstr_dup_c(REQUEST_URI_NOT_SEEN);
1243
51.4k
        if (connp->out_tx->request_uri == NULL) {
1244
0
            return HTP_ERROR;
1245
0
        }
1246
1247
51.4k
        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
51.4k
        connp->out_next_tx_index++;
1253
51.4k
    } else {
1254
        // We've used one transaction
1255
44.3k
        connp->out_next_tx_index++;
1256
1257
        // TODO Detect state mismatch
1258
1259
44.3k
        connp->out_content_length = -1;
1260
44.3k
        connp->out_body_data_left = -1;
1261
44.3k
    }
1262
1263
95.8k
    htp_status_t rc = htp_tx_state_response_start(connp->out_tx);
1264
95.8k
    if (rc != HTP_OK) return rc;
1265
1266
95.8k
    return HTP_OK;
1267
95.8k
}
1268
1269
268k
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
268k
    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
268k
    if (connp->out_status == HTP_STREAM_ERROR) {
1284
85
        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
85
        return HTP_STREAM_ERROR;
1291
85
    }
1292
1293
    // Sanity check: we must have a transaction pointer if the state is not IDLE (no outbound transaction)
1294
268k
    if ((connp->out_tx == NULL)&&(connp->out_state != htp_connp_RES_IDLE)) {
1295
26
        connp->out_status = HTP_STREAM_ERROR;
1296
1297
26
        htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Missing outbound transaction data");
1298
1299
26
        return HTP_STREAM_ERROR;
1300
26
    }
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
268k
    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
268k
    if (timestamp != NULL) {
1318
268k
        memcpy(&connp->out_timestamp, timestamp, sizeof (*timestamp));
1319
268k
    }
1320
1321
    // Store the current chunk information
1322
268k
    connp->out_current_data = (unsigned char *) data;
1323
268k
    connp->out_current_len = len;
1324
268k
    connp->out_current_read_offset = 0;
1325
268k
    connp->out_current_consume_offset = 0;
1326
268k
    connp->out_current_receiver_offset = 0;
1327
1328
268k
    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
268k
    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
727
        return HTP_STREAM_TUNNEL;
1338
727
    }
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.58M
    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.58M
        htp_status_t rc;
1356
1357
        //handle gap
1358
1.58M
        if (data == NULL && len > 0) {
1359
1.33k
            if (connp->out_state == htp_connp_RES_BODY_IDENTITY_CL_KNOWN ||
1360
1.02k
                connp->out_state == htp_connp_RES_BODY_IDENTITY_STREAM_CLOSE) {
1361
469
                rc = connp->out_state(connp);
1362
869
            } else if (connp->out_state == htp_connp_RES_FINALIZE) {
1363
42
                rc = htp_tx_state_response_complete_ex(connp->out_tx, 0);
1364
827
            } else {
1365
827
                htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Gaps are not allowed during this state");
1366
827
                return HTP_STREAM_CLOSED;
1367
827
            }
1368
1.58M
        } else {
1369
1.58M
            rc = connp->out_state(connp);
1370
1.58M
        }
1371
1.58M
        if (rc == HTP_OK) {
1372
1.31M
            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
188
                return HTP_STREAM_TUNNEL;
1378
188
            }
1379
1380
1.31M
            rc = htp_res_handle_state_change(connp);
1381
1.31M
        }
1382
1383
1.58M
        if (rc != HTP_OK) {
1384
            // Do we need more data?
1385
266k
            if ((rc == HTP_DATA) || (rc == HTP_DATA_BUFFER)) {
1386
265k
                htp_connp_res_receiver_send_data(connp, 0 /* not last */);
1387
1388
265k
                if (rc == HTP_DATA_BUFFER) {
1389
143k
                    if (htp_connp_res_buffer(connp) != HTP_OK) {
1390
9
                        connp->out_status = HTP_STREAM_ERROR;
1391
9
                        return HTP_STREAM_ERROR;
1392
9
                    }
1393
143k
                }
1394
1395
                #ifdef HTP_DEBUG
1396
                fprintf(stderr, "htp_connp_res_data: returning HTP_STREAM_DATA\n");
1397
                #endif
1398
1399
265k
                connp->out_status = HTP_STREAM_DATA;
1400
1401
265k
                return HTP_STREAM_DATA;
1402
265k
            }
1403
1404
            // Check for stop
1405
882
            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
882
            if (rc == HTP_DATA_OTHER) {
1417
                // We might have actually consumed the entire data chunk?
1418
221
                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
165
                    connp->out_status = HTP_STREAM_DATA;
1424
1425
                    // Do not send STREAM_DATE_DATA_OTHER if we've
1426
                    // consumed the entire chunk
1427
165
                    return HTP_STREAM_DATA;
1428
165
                } else {
1429
                    #ifdef HTP_DEBUG
1430
                    fprintf(stderr, "htp_connp_res_data: returning HTP_STREAM_DATA_OTHER\n");
1431
                    #endif
1432
1433
56
                    connp->out_status = HTP_STREAM_DATA_OTHER;
1434
1435
                    // Partial chunk consumption
1436
56
                    return HTP_STREAM_DATA_OTHER;
1437
56
                }
1438
221
            }
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
661
            connp->out_status = HTP_STREAM_ERROR;
1446
1447
661
            return HTP_STREAM_ERROR;
1448
882
        }
1449
1.58M
    }
1450
267k
}