Coverage Report

Created: 2025-07-23 07:29

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