Coverage Report

Created: 2026-08-31 06:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libhtp/htp/htp_request.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
73.2k
#define IN_TEST_NEXT_BYTE_OR_RETURN(X) \
44
73.2k
if ((X)->in_current_read_offset >= (X)->in_current_len) { \
45
9.67k
    return HTP_DATA; \
46
9.67k
}
47
48
44.6M
#define IN_PEEK_NEXT(X) \
49
44.6M
if ((X)->in_current_read_offset >= (X)->in_current_len) { \
50
13.0k
    (X)->in_next_byte = -1; \
51
44.6M
} else { \
52
44.6M
    (X)->in_next_byte = (X)->in_current_data[(X)->in_current_read_offset]; \
53
44.6M
}
54
55
#define IN_NEXT_BYTE(X) \
56
if ((X)->in_current_read_offset < (X)->in_current_len) { \
57
    (X)->in_next_byte = (X)->in_current_data[(X)->in_current_read_offset]; \
58
    (X)->in_current_read_offset++; \
59
    (X)->in_current_consume_offset++; \
60
    (X)->in_stream_offset++; \
61
} else { \
62
    (X)->in_next_byte = -1; \
63
}
64
65
0
#define IN_NEXT_BYTE_OR_RETURN(X) \
66
0
if ((X)->in_current_read_offset < (X)->in_current_len) { \
67
0
    (X)->in_next_byte = (X)->in_current_data[(X)->in_current_read_offset]; \
68
0
    (X)->in_current_read_offset++; \
69
0
    (X)->in_current_consume_offset++; \
70
0
    (X)->in_stream_offset++; \
71
0
} else { \
72
0
    return HTP_DATA; \
73
0
}
74
75
62.3M
#define IN_COPY_BYTE_OR_RETURN(X) \
76
62.3M
if ((X)->in_current_read_offset < (X)->in_current_len) { \
77
62.3M
    (X)->in_next_byte = (X)->in_current_data[(X)->in_current_read_offset]; \
78
62.3M
    (X)->in_current_read_offset++; \
79
62.3M
    (X)->in_stream_offset++; \
80
62.3M
} else { \
81
13.8k
    return HTP_DATA_BUFFER; \
82
13.8k
}
83
84
/**
85
 * Sends outstanding connection data to the currently active data receiver hook.
86
 *
87
 * @param[in] connp
88
 * @param[in] is_last
89
 * @return HTP_OK, or a value returned from a callback.
90
 */
91
91.2k
static htp_status_t htp_connp_req_receiver_send_data(htp_connp_t *connp, int is_last) {
92
91.2k
    if (connp->in_data_receiver_hook == NULL) return HTP_OK;
93
94
65.9k
    htp_tx_data_t d;
95
65.9k
    d.tx = connp->in_tx;
96
65.9k
    d.data = connp->in_current_data + connp->in_current_receiver_offset;
97
65.9k
    d.len = connp->in_current_read_offset - connp->in_current_receiver_offset;
98
65.9k
    d.is_last = is_last;
99
100
65.9k
    htp_status_t rc = htp_hook_run_all(connp->in_data_receiver_hook, &d);
101
65.9k
    if (rc != HTP_OK) return rc;
102
103
65.9k
    connp->in_current_receiver_offset = connp->in_current_read_offset;
104
105
65.9k
    return HTP_OK;
106
65.9k
}
107
108
/**
109
 * Configures the data receiver hook. If there is a previous hook, it will be finalized and cleared.
110
 *
111
 * @param[in] connp
112
 * @param[in] data_receiver_hook
113
 * @return HTP_OK, or a value returned from a callback.
114
 */
115
60.0k
static htp_status_t htp_connp_req_receiver_set(htp_connp_t *connp, htp_hook_t *data_receiver_hook) {
116
60.0k
    htp_status_t rc = htp_connp_req_receiver_finalize_clear(connp);
117
118
60.0k
    connp->in_data_receiver_hook = data_receiver_hook;
119
60.0k
    connp->in_current_receiver_offset = connp->in_current_read_offset;
120
121
60.0k
    return rc;
122
60.0k
}
123
124
/**
125
 * Finalizes an existing data receiver hook by sending any outstanding data to it. The
126
 * hook is then removed so that it receives no more data.
127
 *
128
 * @param[in] connp
129
 * @return HTP_OK, or a value returned from a callback.
130
 */
131
212k
htp_status_t htp_connp_req_receiver_finalize_clear(htp_connp_t *connp) {
132
212k
    if (connp->in_data_receiver_hook == NULL) return HTP_OK;
133
134
59.9k
    htp_status_t rc = htp_connp_req_receiver_send_data(connp, 1 /* last */);
135
136
59.9k
    connp->in_data_receiver_hook = NULL;
137
138
59.9k
    return rc;
139
212k
}
140
141
/**
142
 * Handles request parser state changes. At the moment, this function is used only
143
 * to configure data receivers, which are sent raw connection data.
144
 *
145
 * @param[in] connp
146
 * @return HTP_OK, or a value returned from a callback.
147
 */
148
522k
static htp_status_t htp_req_handle_state_change(htp_connp_t *connp) {
149
522k
    if (connp->in_state_previous == connp->in_state) return HTP_OK;
150
151
431k
    if (connp->in_state == htp_connp_REQ_HEADERS) {
152
60.0k
        htp_status_t rc = HTP_OK;
153
154
60.0k
        switch (connp->in_tx->request_progress) {
155
60.0k
            case HTP_REQUEST_HEADERS:
156
60.0k
                rc = htp_connp_req_receiver_set(connp, connp->in_tx->cfg->hook_request_header_data);
157
60.0k
                break;
158
159
0
            case HTP_REQUEST_TRAILER:
160
0
                rc = htp_connp_req_receiver_set(connp, connp->in_tx->cfg->hook_request_trailer_data);
161
0
                break;
162
163
0
            default:
164
                // Do nothing; receivers are currently used only for header blocks.
165
0
                break;
166
60.0k
        }
167
168
60.0k
        if (rc != HTP_OK) return rc;
169
60.0k
    }
170
171
    // Initially, I had the finalization of raw data sending here, but that
172
    // caused the last REQUEST_HEADER_DATA hook to be invoked after the
173
    // REQUEST_HEADERS hook -- which I thought made no sense. For that reason,
174
    // the finalization is now initiated from the request header processing code,
175
    // which is less elegant but provides a better user experience. Having some
176
    // (or all) hooks to be invoked on state change might work better.
177
178
431k
    connp->in_state_previous = connp->in_state;
179
180
431k
    return HTP_OK;
181
431k
}
182
183
/**
184
 * If there is any data left in the inbound data chunk, this function will preserve
185
 * it for later consumption. The maximum amount accepted for buffering is controlled
186
 * by htp_config_t::field_limit_hard.
187
 *
188
 * @param[in] connp
189
 * @return HTP_OK, or HTP_ERROR on fatal failure.
190
 */
191
23.0k
static htp_status_t htp_connp_req_buffer(htp_connp_t *connp) {
192
23.0k
    if (connp->in_current_data == NULL) return HTP_OK;
193
194
20.0k
    unsigned char *data = connp->in_current_data + connp->in_current_consume_offset;
195
20.0k
    size_t len = connp->in_current_read_offset - connp->in_current_consume_offset;
196
197
20.0k
    if (len == 0)
198
3.22k
        return HTP_OK;
199
200
    // Check the hard (buffering) limit.
201
   
202
16.7k
    size_t newlen = connp->in_buf_size + len;
203
204
    // When calculating the size of the buffer, take into account the
205
    // space we're using for the request header buffer.
206
16.7k
    if (connp->in_header != NULL) {
207
963
        newlen += bstr_len(connp->in_header);
208
963
    }
209
210
16.7k
    if (newlen > connp->in_tx->cfg->field_limit_hard) {
211
129
        htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Request buffer over the limit: size %zd limit %zd.",
212
129
                newlen, connp->in_tx->cfg->field_limit_hard);        
213
129
        return HTP_ERROR;
214
129
    }
215
216
    // Copy the data remaining in the buffer.
217
218
16.6k
    if (connp->in_buf == NULL) {
219
8.05k
        connp->in_buf = malloc(len);
220
8.05k
        if (connp->in_buf == NULL) return HTP_ERROR;
221
8.05k
        memcpy(connp->in_buf, data, len);
222
8.05k
        connp->in_buf_size = len;
223
8.61k
    } else {
224
8.61k
        size_t newsize = connp->in_buf_size + len;
225
8.61k
        unsigned char *newbuf = realloc(connp->in_buf, newsize);
226
8.61k
        if (newbuf == NULL) return HTP_ERROR;
227
8.61k
        connp->in_buf = newbuf;
228
8.61k
        memcpy(connp->in_buf + connp->in_buf_size, data, len);
229
8.61k
        connp->in_buf_size = newsize;
230
8.61k
    }
231
232
    // Reset the consumer position.
233
16.6k
    connp->in_current_consume_offset = connp->in_current_read_offset;
234
235
16.6k
    return HTP_OK;
236
16.6k
}
237
238
/**
239
 * Returns to the caller the memory region that should be processed next. This function
240
 * hides away the buffering process from the rest of the code, allowing it to work with
241
 * non-buffered data that's in the inbound chunk, or buffered data that's in our structures.
242
 *
243
 * @param[in] connp
244
 * @param[out] data
245
 * @param[out] len
246
 * @return HTP_OK
247
 */
248
368k
static htp_status_t htp_connp_req_consolidate_data(htp_connp_t *connp, unsigned char **data, size_t *len) {
249
368k
    if (connp->in_buf == NULL) {
250
        // We do not have any data buffered; point to the current data chunk.
251
359k
        *data = connp->in_current_data + connp->in_current_consume_offset;
252
359k
        *len = connp->in_current_read_offset - connp->in_current_consume_offset;
253
359k
    } else {
254
        // We already have some data in the buffer. Add the data from the current
255
        // chunk to it, and point to the consolidated buffer.
256
9.22k
        if (htp_connp_req_buffer(connp) != HTP_OK) {
257
95
            return HTP_ERROR;
258
95
        }
259
260
9.13k
        *data = connp->in_buf;
261
9.13k
        *len = connp->in_buf_size;
262
9.13k
    }
263
264
368k
    return HTP_OK;
265
368k
}
266
267
/**
268
 * Clears buffered inbound data and resets the consumer position to the reader position.
269
 *
270
 * @param[in] connp
271
 */
272
278k
static void htp_connp_req_clear_buffer(htp_connp_t *connp) {
273
278k
    connp->in_current_consume_offset = connp->in_current_read_offset;
274
275
278k
    if (connp->in_buf != NULL) {
276
7.99k
        free(connp->in_buf);
277
7.99k
        connp->in_buf = NULL;
278
7.99k
        connp->in_buf_size = 0;
279
7.99k
    }
280
278k
}
281
282
/**
283
 * Performs a check for a CONNECT transaction to decide whether inbound
284
 * parsing needs to be suspended.
285
 *
286
 * @param[in] connp
287
 * @return HTP_OK if the request does not use CONNECT, HTP_DATA_OTHER if
288
 *          inbound parsing needs to be suspended until we hear from the
289
 *          other side
290
 */
291
58.5k
htp_status_t htp_connp_REQ_CONNECT_CHECK(htp_connp_t *connp) {
292
    // If the request uses the CONNECT method, then there will
293
    // not be a request body, but first we need to wait to see the
294
    // response in order to determine if the tunneling request
295
    // was a success.
296
58.5k
    if (connp->in_tx->request_method_number == HTP_M_CONNECT) {        
297
5.40k
        connp->in_state = htp_connp_REQ_CONNECT_WAIT_RESPONSE;
298
5.40k
        connp->in_status = HTP_STREAM_DATA_OTHER;
299
5.40k
        return HTP_DATA_OTHER;
300
5.40k
    }
301
302
    // Continue to the next step to determine 
303
    // the presence of request body
304
53.1k
    connp->in_state = htp_connp_REQ_BODY_DETERMINE;
305
306
53.1k
    return HTP_OK;
307
58.5k
}
308
309
/**
310
 * Determines whether inbound parsing needs to continue or stop. In
311
 * case the data appears to be plain text HTTP, we try to continue.
312
 *
313
 * @param[in] connp
314
 * @return HTP_OK if the parser can resume parsing, HTP_DATA_BUFFER if
315
 *         we need more data.
316
 */
317
2.93k
htp_status_t htp_connp_REQ_CONNECT_PROBE_DATA(htp_connp_t *connp) {
318
53.3k
    for (;;) {//;i < max_read; i++) {
319
53.3k
        IN_PEEK_NEXT(connp);
320
        // Have we reached the end of the line? For some reason
321
        // we can't test after IN_COPY_BYTE_OR_RETURN */
322
53.3k
        if (connp->in_next_byte == LF || connp->in_next_byte == 0x00)
323
2.06k
            break;
324
325
51.2k
        IN_COPY_BYTE_OR_RETURN(connp);
326
327
50.4k
    }
328
329
2.06k
    unsigned char *data;
330
2.06k
    size_t len;
331
2.06k
    if (htp_connp_req_consolidate_data(connp, &data, &len) != HTP_OK) {
332
1
        return HTP_ERROR;
333
1
    }
334
#ifdef HTP_DEBUG
335
    fprint_raw_data(stderr, "PROBING", data, len);
336
#endif
337
338
2.06k
    size_t pos = 0;
339
2.06k
    size_t mstart = 0;
340
    // skip past leading whitespace. IIS allows this
341
2.33k
    while ((pos < len) && htp_is_space(data[pos]))
342
274
        pos++;
343
2.06k
    if (pos)
344
28
        mstart = pos;
345
    // The request method starts at the beginning of the
346
    // line and ends with the first whitespace character.
347
21.6k
    while ((pos < len) && (!htp_is_space(data[pos])))
348
19.6k
        pos++;
349
350
2.06k
    int methodi = HTP_M_UNKNOWN;
351
2.06k
    bstr *method = bstr_dup_mem(data + mstart, pos - mstart);
352
2.06k
    if (method) {
353
2.06k
        methodi = htp_convert_method_to_number(method);
354
2.06k
        bstr_free(method);
355
2.06k
    }
356
2.06k
    if (methodi != HTP_M_UNKNOWN) {
357
#ifdef HTP_DEBUG
358
        fprint_raw_data(stderr, "htp_connp_REQ_CONNECT_PROBE_DATA: tunnel contains plain text HTTP", data, len);
359
#endif
360
1.98k
        return htp_tx_state_request_complete(connp->in_tx);
361
1.98k
    } else {
362
#ifdef HTP_DEBUG
363
        fprint_raw_data(stderr, "htp_connp_REQ_CONNECT_PROBE_DATA: tunnel is not HTTP", data, len);
364
#endif
365
78
        connp->in_status = HTP_STREAM_TUNNEL;
366
78
        connp->out_status = HTP_STREAM_TUNNEL;
367
78
    }
368
369
    // not calling htp_connp_req_clear_buffer, we're not consuming the data
370
371
78
    return HTP_OK;
372
2.06k
}
373
374
/**
375
 * Determines whether inbound parsing, which was suspended after
376
 * encountering a CONNECT transaction, can proceed (after receiving
377
 * the response).
378
 *
379
 * @param[in] connp
380
 * @return HTP_OK if the parser can resume parsing, HTP_DATA_OTHER if
381
 *         it needs to continue waiting.
382
 */
383
7.14k
htp_status_t htp_connp_REQ_CONNECT_WAIT_RESPONSE(htp_connp_t *connp) {
384
    // Check that we saw the response line of the current inbound transaction.
385
7.14k
    if (connp->in_tx->response_progress <= HTP_RESPONSE_LINE) {
386
2.21k
        return HTP_DATA_OTHER;
387
2.21k
    }
388
389
    // A 2xx response means a tunnel was established. Anything
390
    // else means we continue to follow the HTTP stream.
391
4.92k
    if ((connp->in_tx->response_status_number >= 200) && (connp->in_tx->response_status_number <= 299)) {
392
        // TODO Check that the server did not accept a connection to itself.
393
394
        // The requested tunnel was established: we are going
395
        // to probe the remaining data on this stream to see
396
        // if we need to ignore it or parse it
397
2.09k
        connp->in_state = htp_connp_REQ_CONNECT_PROBE_DATA;
398
2.82k
    } else {
399
        // No tunnel; continue to the next transaction
400
2.82k
        connp->in_state = htp_connp_REQ_FINALIZE;
401
2.82k
    }
402
403
4.92k
    return HTP_OK;
404
7.14k
}
405
406
/**
407
 * Consumes bytes until the end of the current line.
408
 *
409
 * @param[in] connp
410
 * @returns HTP_OK on state change, HTP_ERROR on error, or HTP_DATA when more data is needed.
411
 */
412
0
htp_status_t htp_connp_REQ_BODY_CHUNKED_DATA_END(htp_connp_t *connp) {
413
    // TODO We shouldn't really see anything apart from CR and LF,
414
    //      so we should warn about anything else.
415
416
0
    for (;;) {
417
0
        IN_NEXT_BYTE_OR_RETURN(connp);
418
419
0
        connp->in_tx->request_message_len++;
420
421
0
        if (connp->in_next_byte == LF) {
422
0
            connp->in_state = htp_connp_REQ_BODY_CHUNKED_LENGTH;
423
0
            return HTP_OK;
424
0
        }
425
0
    }
426
427
0
    return HTP_ERROR;
428
0
}
429
430
/**
431
 * Processes a chunk of data.
432
 *
433
 * @param[in] connp
434
 * @returns HTP_OK on state change, HTP_ERROR on error, or HTP_DATA when more data is needed.
435
 */
436
0
htp_status_t htp_connp_REQ_BODY_CHUNKED_DATA(htp_connp_t *connp) {
437
    // Determine how many bytes we can consume.
438
0
    size_t bytes_to_consume;
439
0
    if (connp->in_current_len - connp->in_current_read_offset >= connp->in_chunked_length) {
440
        // Entire chunk available in the buffer; read all of it.
441
0
        bytes_to_consume = connp->in_chunked_length;
442
0
    } else {
443
        // Partial chunk available in the buffer; read as much as we can.
444
0
        bytes_to_consume = connp->in_current_len - connp->in_current_read_offset;
445
0
    }
446
447
    #ifdef HTP_DEBUG
448
    fprintf(stderr, "htp_connp_REQ_BODY_CHUNKED_DATA Consuming %zd bytes\n", bytes_to_consume);
449
    #endif
450
451
    // If the input buffer is empty, ask for more data.
452
0
    if (bytes_to_consume == 0) return HTP_DATA;
453
454
    // Consume the data.
455
0
    htp_status_t rc = htp_tx_req_process_body_data_ex(connp->in_tx, connp->in_current_data + connp->in_current_read_offset, bytes_to_consume);
456
0
    if (rc != HTP_OK) return rc;
457
458
    // Adjust counters.
459
0
    connp->in_current_read_offset += bytes_to_consume;
460
0
    connp->in_current_consume_offset += bytes_to_consume;
461
0
    connp->in_stream_offset += bytes_to_consume;
462
0
    connp->in_tx->request_message_len += bytes_to_consume;
463
0
    connp->in_chunked_length -= bytes_to_consume;
464
465
0
    if (connp->in_chunked_length == 0) {
466
        // End of the chunk.
467
0
        connp->in_state = htp_connp_REQ_BODY_CHUNKED_DATA_END;
468
0
        return HTP_OK;
469
0
    }
470
471
    // Ask for more data.
472
0
    return HTP_DATA;
473
0
}
474
475
/**
476
 * Extracts chunk length.
477
 *
478
 * @param[in] connp
479
 * @returns HTP_OK on state change, HTP_ERROR on error, or HTP_DATA when more data is needed.
480
 */
481
0
htp_status_t htp_connp_REQ_BODY_CHUNKED_LENGTH(htp_connp_t *connp) {
482
0
    for (;;) {
483
0
        IN_COPY_BYTE_OR_RETURN(connp);
484
485
        // Have we reached the end of the line?
486
0
        if (connp->in_next_byte == LF) {
487
0
            unsigned char *data;
488
0
            size_t len;
489
490
0
            if (htp_connp_req_consolidate_data(connp, &data, &len) != HTP_OK) {
491
0
                return HTP_ERROR;
492
0
            }
493
494
0
            connp->in_tx->request_message_len += len;
495
496
            #ifdef HTP_DEBUG
497
            fprint_raw_data(stderr, "Chunk length line", data, len);
498
            #endif
499
500
0
            htp_chomp(data, &len);
501
502
0
            int chunk_ext = 0;
503
0
            connp->in_chunked_length = htp_parse_chunked_length(data, len, &chunk_ext);
504
0
            if (chunk_ext == 1) {
505
0
                htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Request chunk extension");
506
0
            }
507
508
0
            htp_connp_req_clear_buffer(connp);
509
510
            // Handle chunk length.
511
0
            if (connp->in_chunked_length > 0) {
512
                // More data available.                
513
0
                connp->in_state = htp_connp_REQ_BODY_CHUNKED_DATA;
514
0
            } else if (connp->in_chunked_length == 0) {
515
                // End of data.
516
0
                connp->in_state = htp_connp_REQ_HEADERS;
517
0
                connp->in_tx->request_progress = HTP_REQUEST_TRAILER;
518
0
            } else {
519
                // Invalid chunk length.
520
0
                htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Request chunk encoding: Invalid chunk length");
521
0
                return HTP_ERROR;
522
0
            }
523
524
0
            return HTP_OK;
525
0
        }
526
0
    }
527
528
0
    return HTP_ERROR;
529
0
}
530
531
/**
532
 * Processes identity request body.
533
 *
534
 * @param[in] connp
535
 * @returns HTP_OK on state change, HTP_ERROR on error, or HTP_DATA when more data is needed.
536
 */
537
0
htp_status_t htp_connp_REQ_BODY_IDENTITY(htp_connp_t *connp) {
538
    // Determine how many bytes we can consume.
539
0
    size_t bytes_to_consume;
540
0
    if (connp->in_current_len - connp->in_current_read_offset >= connp->in_body_data_left) {
541
0
        bytes_to_consume = connp->in_body_data_left;
542
0
    } else {
543
0
        bytes_to_consume = connp->in_current_len - connp->in_current_read_offset;
544
0
    }
545
546
    // If the input buffer is empty, ask for more data.
547
0
    if (bytes_to_consume == 0) return HTP_DATA;
548
549
    // Consume data.
550
0
    int rc = htp_tx_req_process_body_data_ex(connp->in_tx, connp->in_current_data + connp->in_current_read_offset, bytes_to_consume);
551
0
    if (rc != HTP_OK) return rc;
552
553
    // Adjust counters.
554
0
    connp->in_current_read_offset += bytes_to_consume;
555
0
    connp->in_current_consume_offset += bytes_to_consume;
556
0
    connp->in_stream_offset += bytes_to_consume;
557
0
    connp->in_tx->request_message_len += bytes_to_consume;
558
0
    connp->in_body_data_left -= bytes_to_consume;
559
560
0
    if (connp->in_body_data_left == 0) {
561
        // End of request body.
562
0
        connp->in_state = htp_connp_REQ_FINALIZE;
563
0
        return HTP_OK;
564
0
    }
565
566
    // Ask for more data.
567
0
    return HTP_DATA;
568
0
}
569
570
/**
571
 * Determines presence (and encoding) of a request body.
572
 *
573
 * @param[in] connp
574
 * @returns HTP_OK on state change, HTP_ERROR on error, or HTP_DATA when more data is needed.
575
 */
576
53.1k
htp_status_t htp_connp_REQ_BODY_DETERMINE(htp_connp_t *connp) {
577
    // Determine the next state based on the presence of the request
578
    // body, and the coding used.
579
53.1k
    switch (connp->in_tx->request_transfer_coding) {
580
581
0
        case HTP_CODING_CHUNKED:
582
0
            connp->in_state = htp_connp_REQ_BODY_CHUNKED_LENGTH;
583
0
            connp->in_tx->request_progress = HTP_REQUEST_BODY;
584
0
            break;
585
586
0
        case HTP_CODING_IDENTITY:
587
0
            connp->in_content_length = connp->in_tx->request_content_length;
588
0
            connp->in_body_data_left = connp->in_content_length;
589
590
0
            if (connp->in_content_length != 0) {
591
0
                connp->in_state = htp_connp_REQ_BODY_IDENTITY;
592
0
                connp->in_tx->request_progress = HTP_REQUEST_BODY;
593
0
            } else {
594
0
                connp->in_tx->connp->in_state = htp_connp_REQ_FINALIZE;
595
0
            }
596
0
            break;
597
598
53.1k
        case HTP_CODING_NO_BODY:
599
            // This request does not have a body, which
600
            // means that we're done with it
601
53.1k
            connp->in_state = htp_connp_REQ_FINALIZE;
602
53.1k
            break;
603
604
0
        default:
605
            // Should not be here
606
0
            return HTP_ERROR;
607
0
            break;
608
53.1k
    }
609
610
53.1k
    return HTP_OK;
611
53.1k
}
612
613
/**
614
 * Parses request headers.
615
 *
616
 * @param[in] connp
617
 * @returns HTP_OK on state change, HTP_ERROR on error, or HTP_DATA when more data is needed.
618
 */
619
65.6k
htp_status_t htp_connp_REQ_HEADERS(htp_connp_t *connp) {
620
17.8M
    for (;;) {
621
17.8M
        if (connp->in_status == HTP_STREAM_CLOSED) {
622
            // Parse previous header, if any.
623
1.12k
            if (connp->in_header != NULL) {
624
596
                if (connp->cfg->process_request_header(connp, bstr_ptr(connp->in_header),
625
596
                                                       bstr_len(connp->in_header)) != HTP_OK)
626
0
                    return HTP_ERROR;
627
596
                bstr_free(connp->in_header);
628
596
                connp->in_header = NULL;
629
596
            }
630
631
1.12k
            htp_connp_req_clear_buffer(connp);
632
633
1.12k
            connp->in_tx->request_progress = HTP_REQUEST_TRAILER;
634
635
            // We've seen all the request headers.
636
1.12k
            return htp_tx_state_request_headers(connp->in_tx);
637
1.12k
        }
638
17.8M
        IN_COPY_BYTE_OR_RETURN(connp);
639
640
        // Have we reached the end of the line?
641
17.8M
        if (connp->in_next_byte == LF) {
642
123k
            unsigned char *data;
643
123k
            size_t len;
644
645
123k
            if (htp_connp_req_consolidate_data(connp, &data, &len) != HTP_OK) {
646
2
                return HTP_ERROR;
647
2
            }
648
649
            #ifdef HTP_DEBUG
650
            fprint_raw_data(stderr, __func__, data, len);
651
            #endif           
652
653
            // Should we terminate headers?
654
123k
            if (htp_connp_is_line_terminator(connp, data, len, 0)) {
655
                // Parse previous header, if any.
656
58.5k
                if (connp->in_header != NULL) {
657
2.27k
                    if (connp->cfg->process_request_header(connp, bstr_ptr(connp->in_header),
658
2.27k
                            bstr_len(connp->in_header)) != HTP_OK) return HTP_ERROR;
659
660
2.27k
                    bstr_free(connp->in_header);
661
2.27k
                    connp->in_header = NULL;
662
2.27k
                }
663
664
58.5k
                htp_connp_req_clear_buffer(connp);
665
666
                // We've seen all the request headers.
667
58.5k
                return htp_tx_state_request_headers(connp->in_tx);
668
58.5k
            }
669
670
64.5k
            htp_chomp(data, &len);
671
672
            // Check for header folding.
673
64.5k
            if (htp_connp_is_line_folded(data, len) == 0) {
674
                // New header line.
675
676
                // Parse previous header, if any.
677
53.7k
                if (connp->in_header != NULL) {
678
2.17k
                    if (connp->cfg->process_request_header(connp, bstr_ptr(connp->in_header),
679
2.17k
                            bstr_len(connp->in_header)) != HTP_OK) return HTP_ERROR;
680
681
2.17k
                    bstr_free(connp->in_header);
682
2.17k
                    connp->in_header = NULL;
683
2.17k
                }
684
685
53.7k
                IN_PEEK_NEXT(connp);
686
687
53.7k
                if (connp->in_next_byte != -1 && htp_is_folding_char(connp->in_next_byte) == 0) {
688
                    // Because we know this header is not folded, we can process the buffer straight away.
689
51.6k
                    if (connp->cfg->process_request_header(connp, data, len) != HTP_OK) return HTP_ERROR;
690
51.6k
                } else {
691
                    // Keep the partial header data for parsing later.
692
2.14k
                    connp->in_header = bstr_dup_mem(data, len);
693
2.14k
                    if (connp->in_header == NULL) return HTP_ERROR;
694
2.14k
                }
695
53.7k
            } else {
696
                // Folding; check that there's a previous header line to add to.
697
10.8k
                if (connp->in_header == NULL) {
698
                    // Invalid folding.
699
700
                    // Warn only once per transaction.
701
2.91k
                    if (!(connp->in_tx->flags & HTP_INVALID_FOLDING)) {
702
2.40k
                        connp->in_tx->flags |= HTP_INVALID_FOLDING;
703
2.40k
                        htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Invalid request field folding");
704
2.40k
                    }
705
706
                    // Keep the header data for parsing later.
707
2.91k
                    size_t trim = 0;
708
7.78k
                    while(trim < len) {
709
6.10k
                        if (!htp_is_folding_char(data[trim])) {
710
1.23k
                            break;
711
1.23k
                        }
712
4.87k
                        trim++;
713
4.87k
                    }
714
2.91k
                    connp->in_header = bstr_dup_mem(data + trim, len - trim);
715
2.91k
                    if (connp->in_header == NULL) return HTP_ERROR;
716
7.89k
                } else {
717
                    // Add to the existing header.
718
7.89k
                    if (bstr_len(connp->in_header) < HTP_MAX_HEADER_FOLDED) {
719
7.53k
                        bstr *new_in_header = bstr_add_mem(connp->in_header, data, len);
720
7.53k
                        if (new_in_header == NULL) return HTP_ERROR;
721
7.53k
                        connp->in_header = new_in_header;
722
7.53k
                    } else {
723
356
                        htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Request field length exceeds folded maximum");
724
356
                    }
725
7.89k
                }
726
10.8k
            }
727
728
64.5k
            htp_connp_req_clear_buffer(connp);
729
64.5k
        }
730
17.8M
    }
731
732
0
    return HTP_ERROR;
733
65.6k
}
734
735
// HTTP/0.9 is supposed to be only a request line without protocol.
736
// Libhtp will still consider the request to be HTTP/0.9 if there
737
// are some junk whitespaces after that request line.
738
// Libhtp allows the small value of 16 extra bytes/whitespaces,
739
// otherwise we consider it to be a HTTP/1.x request with missing protocol.
740
// It is unlikely to meet HTTP/0.9, and we want to limit probing.
741
56.1k
#define HTTP09_MAX_JUNK_LEN 16
742
743
/**
744
 * Determines request protocol.
745
 *
746
 * @param[in] connp
747
 * @returns HTP_OK on state change, HTP_ERROR on error, or HTP_DATA when more data is needed.
748
 */
749
63.2k
htp_status_t htp_connp_REQ_PROTOCOL(htp_connp_t *connp) {
750
    // Is this a short-style HTTP/0.9 request? If it is,
751
    // we will not want to parse request headers.
752
63.2k
    if (connp->in_tx->is_protocol_0_9 == 0) {
753
        // Switch to request header parsing.
754
7.14k
        connp->in_state = htp_connp_REQ_HEADERS;
755
7.14k
        connp->in_tx->request_progress = HTP_REQUEST_HEADERS;
756
56.1k
    } else {
757
        // Let's check if the protocol was simply missing
758
56.1k
        int64_t pos = connp->in_current_read_offset;
759
        // Probe if data looks like a header line
760
56.1k
        if (connp->in_current_len > connp->in_current_read_offset + HTTP09_MAX_JUNK_LEN) {
761
45.9k
            htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Request line: missing protocol");
762
45.9k
            connp->in_tx->is_protocol_0_9 = 0;
763
            // Switch to request header parsing.
764
45.9k
            connp->in_state = htp_connp_REQ_HEADERS;
765
45.9k
            connp->in_tx->request_progress = HTP_REQUEST_HEADERS;
766
45.9k
            return HTP_OK;
767
45.9k
        }
768
18.7k
        while (pos < connp->in_current_len) {
769
15.4k
            if (!htp_is_space(connp->in_current_data[pos])) {
770
6.87k
                htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Request line: missing protocol");
771
6.87k
                connp->in_tx->is_protocol_0_9 = 0;
772
                // Switch to request header parsing.
773
6.87k
                connp->in_state = htp_connp_REQ_HEADERS;
774
6.87k
                connp->in_tx->request_progress = HTP_REQUEST_HEADERS;
775
6.87k
                return HTP_OK;
776
6.87k
            }
777
8.56k
            pos++;
778
8.56k
        }
779
        // We're done with this request.
780
3.28k
        connp->in_state = htp_connp_REQ_FINALIZE;
781
3.28k
    }
782
783
10.4k
    return HTP_OK;
784
63.2k
}
785
786
/**
787
 * Parse the request line.
788
 *
789
 * @param[in] connp
790
 * @returns HTP_OK on succesful parse, HTP_ERROR on error.
791
 */
792
131k
htp_status_t htp_connp_REQ_LINE_complete(htp_connp_t *connp) {
793
131k
    unsigned char *data;
794
131k
    size_t len;
795
796
131k
    if (htp_connp_req_consolidate_data(connp, &data, &len) != HTP_OK) {
797
1
        return HTP_ERROR;
798
1
    }
799
800
    #ifdef HTP_DEBUG
801
    fprint_raw_data(stderr, __func__, data, len);
802
    #endif
803
131k
    if (len == 0) {
804
102
        htp_connp_req_clear_buffer(connp);
805
102
        return HTP_DATA;
806
102
    }
807
808
    // Is this a line that should be ignored?
809
131k
    if (htp_connp_is_line_ignorable(connp, data, len)) {
810
        // We have an empty/whitespace line, which we'll note, ignore and move on.
811
68.0k
        connp->in_tx->request_ignored_lines++;
812
813
68.0k
        htp_connp_req_clear_buffer(connp);
814
815
68.0k
        return HTP_OK;
816
68.0k
    }
817
818
    // Process request line.
819
820
63.3k
    htp_chomp(data, &len);
821
822
63.3k
    connp->in_tx->request_line = bstr_dup_mem(data, len);
823
63.3k
    if (connp->in_tx->request_line == NULL)
824
0
        return HTP_ERROR;
825
826
63.3k
    if (connp->cfg->parse_request_line(connp) != HTP_OK)
827
0
        return HTP_ERROR;
828
829
    // Finalize request line parsing.
830
831
63.3k
    if (htp_tx_state_request_line(connp->in_tx) != HTP_OK)
832
10
        return HTP_ERROR;
833
834
63.2k
    htp_connp_req_clear_buffer(connp);
835
836
63.2k
    return HTP_OK;
837
63.3k
}
838
839
/**
840
 * Parses request line.
841
 *
842
 * @param[in] connp
843
 * @returns HTP_OK on state change, HTP_ERROR on error, or HTP_DATA when more data is needed.
844
 */
845
136k
htp_status_t htp_connp_REQ_LINE(htp_connp_t *connp) {
846
39.5M
    for (;;) {
847
        // Get one byte
848
39.5M
        IN_PEEK_NEXT(connp);
849
39.5M
        if (connp->in_status == HTP_STREAM_CLOSED && connp->in_next_byte == -1) {
850
2.61k
            return htp_connp_REQ_LINE_complete(connp);
851
2.61k
        }
852
39.5M
        IN_COPY_BYTE_OR_RETURN(connp);
853
854
        // Have we reached the end of the line?
855
39.5M
        if (connp->in_next_byte == LF) {
856
128k
            return htp_connp_REQ_LINE_complete(connp);
857
128k
        }
858
39.5M
    }
859
860
0
    return HTP_ERROR;
861
136k
}
862
863
93.2k
htp_status_t htp_connp_REQ_FINALIZE(htp_connp_t *connp) {
864
93.2k
    if (connp->in_status != HTP_STREAM_CLOSED) {
865
82.2k
        IN_PEEK_NEXT(connp);
866
82.2k
        if (connp->in_next_byte == -1) {
867
1.46k
            return htp_tx_state_request_complete(connp->in_tx);
868
1.46k
        }
869
80.8k
        if (connp->in_next_byte != LF || connp->in_current_consume_offset >= connp->in_current_read_offset) {
870
4.95M
            for (;;) {//;i < max_read; i++) {
871
                // peek until LF but do not mark it read so that REQ_LINE works
872
4.95M
                IN_PEEK_NEXT(connp);
873
4.95M
                if (connp->in_next_byte == LF)
874
78.7k
                    break;
875
4.88M
                IN_COPY_BYTE_OR_RETURN(connp);
876
4.87M
            }
877
80.8k
        }
878
80.8k
    }
879
880
89.7k
    unsigned char *data;
881
89.7k
    size_t len;
882
89.7k
    if (htp_connp_req_consolidate_data(connp, &data, &len) != HTP_OK) {
883
4
        return HTP_ERROR;
884
4
    }
885
#ifdef HTP_DEBUG
886
    fprint_raw_data(stderr, "PROBING request finalize", data, len);
887
#endif
888
89.7k
    if (len == 0) {
889
        //closing
890
59.8k
        return htp_tx_state_request_complete(connp->in_tx);
891
59.8k
    }
892
893
29.8k
    size_t pos = 0;
894
29.8k
    size_t mstart = 0;
895
    // skip past leading whitespace. IIS allows this
896
35.5k
    while ((pos < len) && htp_is_space(data[pos]))
897
5.73k
        pos++;
898
29.8k
    if (pos)
899
2.31k
        mstart = pos;
900
    // The request method starts at the beginning of the
901
    // line and ends with the first whitespace character.
902
2.60M
    while ((pos < len) && (!htp_is_space(data[pos])))
903
2.57M
        pos++;
904
905
29.8k
    if (pos > mstart) {
906
        //non empty whitespace line
907
28.1k
        int methodi = HTP_M_UNKNOWN;
908
28.1k
        bstr *method = bstr_dup_mem(data + mstart, pos - mstart);
909
28.1k
        if (method) {
910
28.1k
            methodi = htp_convert_method_to_number(method);
911
28.1k
            bstr_free(method);
912
28.1k
        }
913
28.1k
        if (methodi != HTP_M_UNKNOWN) {
914
6.94k
            connp->in_body_data_left = -1;
915
6.94k
            return htp_tx_state_request_complete(connp->in_tx);
916
6.94k
        } // else continue
917
21.1k
        if (connp->in_body_data_left <= 0) {
918
            // log only once per transaction
919
21.1k
            htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Unexpected request body");
920
21.1k
        } else {
921
0
            connp->in_body_data_left = 1;
922
0
        }
923
21.1k
    }
924
    //Adds linefeed to the buffer if there was one
925
22.9k
    if (connp->in_next_byte == LF) {
926
22.4k
        IN_COPY_BYTE_OR_RETURN(connp);
927
22.4k
        htp_connp_req_consolidate_data(connp, &data, &len);
928
22.4k
    }
929
    // Interpret remaining bytes as body data
930
22.9k
    htp_status_t rc = htp_tx_req_process_body_data_ex(connp->in_tx, data, len);
931
22.9k
    htp_connp_req_clear_buffer(connp);
932
22.9k
    return rc;
933
22.9k
}
934
935
7.69k
htp_status_t htp_connp_REQ_IGNORE_DATA_AFTER_HTTP_0_9(htp_connp_t *connp) {
936
    // Consume whatever is left in the buffer.
937
938
7.69k
    size_t bytes_left = connp->in_current_len - connp->in_current_read_offset;
939
940
7.69k
    if (bytes_left > 0) {
941
4.33k
        connp->conn->flags |= HTP_CONN_HTTP_0_9_EXTRA;
942
4.33k
    }
943
944
7.69k
    connp->in_current_read_offset += bytes_left;
945
7.69k
    connp->in_current_consume_offset += bytes_left;
946
7.69k
    connp->in_stream_offset += bytes_left;
947
948
7.69k
    return HTP_DATA;
949
7.69k
}
950
951
/**
952
 * The idle state is where the parser will end up after a transaction is processed.
953
 * If there is more data available, a new request will be started.
954
 *
955
 * @param[in] connp
956
 * @returns HTP_OK on state change, HTP_ERROR on error, or HTP_DATA when more data is needed.
957
 */
958
73.2k
htp_status_t htp_connp_REQ_IDLE(htp_connp_t * connp) {
959
    // We want to start parsing the next request (and change
960
    // the state from IDLE) only if there's at least one
961
    // byte of data available. Otherwise we could be creating
962
    // new structures even if there's no more data on the
963
    // connection.
964
73.2k
    IN_TEST_NEXT_BYTE_OR_RETURN(connp);
965
966
63.5k
    connp->in_tx = htp_connp_tx_create(connp);
967
63.5k
    if (connp->in_tx == NULL) return HTP_ERROR;
968
969
    // Change state to TRANSACTION_START
970
63.5k
    htp_tx_state_request_start(connp->in_tx);
971
972
63.5k
    return HTP_OK;
973
63.5k
}
974
975
/**
976
 * Returns how many bytes from the current data chunks were consumed so far.
977
 *
978
 * @param[in] connp
979
 * @return The number of bytes consumed.
980
 */
981
3.11k
size_t htp_connp_req_data_consumed(htp_connp_t *connp) {
982
3.11k
    return connp->in_current_read_offset;
983
3.11k
}
984
985
42.8k
int htp_connp_req_data(htp_connp_t *connp, const htp_time_t *timestamp, const void *data, size_t len) {
986
    #ifdef HTP_DEBUG
987
    fprintf(stderr, "htp_connp_req_data(connp->in_status %x)\n", connp->in_status);
988
    fprint_raw_data(stderr, __func__, data, len);
989
    #endif
990
991
    // Return if the connection is in stop state.
992
42.8k
    if (connp->in_status == HTP_STREAM_STOP) {
993
0
        htp_log(connp, HTP_LOG_MARK, HTP_LOG_INFO, 0, "Inbound parser is in HTP_STREAM_STOP");
994
0
        return HTP_STREAM_STOP;
995
0
    }
996
997
    // Return if the connection had a fatal error earlier
998
42.8k
    if (connp->in_status == HTP_STREAM_ERROR) {
999
57
        htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Inbound parser is in HTP_STREAM_ERROR");
1000
1001
        #ifdef HTP_DEBUG
1002
        fprintf(stderr, "htp_connp_req_data: returning HTP_STREAM_DATA (previous error)\n");
1003
        #endif
1004
1005
57
        return HTP_STREAM_ERROR;
1006
57
    }
1007
1008
    // Sanity check: we must have a transaction pointer if the state is not IDLE (no inbound transaction)
1009
42.7k
    if ((connp->in_tx == NULL)&&
1010
12.1k
        (connp->in_state != htp_connp_REQ_IDLE && connp->in_state != htp_connp_REQ_IGNORE_DATA_AFTER_HTTP_0_9)) {
1011
0
        connp->in_status = HTP_STREAM_ERROR;
1012
1013
0
        htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Missing inbound transaction data");
1014
1015
0
        return HTP_STREAM_ERROR;
1016
0
    }
1017
1018
    // If the length of the supplied data chunk is zero, proceed
1019
    // only if the stream has been closed. We do not allow zero-sized
1020
    // chunks in the API, but we use them internally to force the parsers
1021
    // to finalize parsing.
1022
42.7k
    if (len == 0 && connp->in_status != HTP_STREAM_CLOSED) {
1023
0
        htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Zero-length data chunks are not allowed");
1024
1025
        #ifdef HTP_DEBUG
1026
        fprintf(stderr, "htp_connp_req_data: returning HTP_STREAM_DATA (zero-length chunk)\n");
1027
        #endif
1028
1029
0
        return HTP_STREAM_CLOSED;
1030
0
    }
1031
1032
    // Remember the timestamp of the current request data chunk
1033
42.7k
    if (timestamp != NULL) {
1034
0
        memcpy(&connp->in_timestamp, timestamp, sizeof (*timestamp));
1035
0
    }
1036
1037
    // Store the current chunk information    
1038
42.7k
    connp->in_current_data = (unsigned char *) data;
1039
42.7k
    connp->in_current_len = len;
1040
42.7k
    connp->in_current_read_offset = 0;
1041
42.7k
    connp->in_current_consume_offset = 0;
1042
42.7k
    connp->in_current_receiver_offset = 0;
1043
42.7k
    connp->in_chunk_count++;
1044
1045
42.7k
    htp_conn_track_inbound_data(connp->conn, len, timestamp);
1046
1047
1048
    // Return without processing any data if the stream is in tunneling
1049
    // mode (which it would be after an initial CONNECT transaction).
1050
42.7k
    if (connp->in_status == HTP_STREAM_TUNNEL) {
1051
        #ifdef HTP_DEBUG
1052
        fprintf(stderr, "htp_connp_req_data: returning HTP_STREAM_TUNNEL\n");
1053
        #endif
1054
1055
233
        return HTP_STREAM_TUNNEL;
1056
233
    }
1057
1058
42.5k
    if (connp->out_status == HTP_STREAM_DATA_OTHER) {
1059
987
        connp->out_status = HTP_STREAM_DATA;
1060
987
    }
1061
1062
    // Invoke a processor, in a loop, until an error
1063
    // occurs or until we run out of data. Many processors
1064
    // will process a request, each pointing to the next
1065
    // processor that needs to run.
1066
565k
    for (;;) {
1067
        #ifdef HTP_DEBUG
1068
        fprintf(stderr, "htp_connp_req_data: in state=%s, progress=%s\n",
1069
                htp_connp_in_state_as_string(connp),
1070
                htp_tx_request_progress_as_string(connp->in_tx));
1071
        #endif
1072
1073
        // Return if there's been an error or if we've run out of data. We are relying
1074
        // on processors to supply error messages, so we'll keep quiet here.
1075
1076
565k
        htp_status_t rc;
1077
        //handle gap
1078
565k
        if (data == NULL && len > 0) {
1079
            //cannot switch over a function pointer in C
1080
3.99k
            if (connp->in_state == htp_connp_REQ_BODY_IDENTITY ||
1081
3.99k
                connp->in_state == htp_connp_REQ_IGNORE_DATA_AFTER_HTTP_0_9) {
1082
232
                rc = connp->in_state(connp);
1083
3.76k
            } else if (connp->in_state == htp_connp_REQ_FINALIZE) {
1084
                //simple version without probing
1085
258
                rc = htp_tx_state_request_complete(connp->in_tx);
1086
3.50k
            } else {
1087
                // go to htp_connp_REQ_CONNECT_PROBE_DATA ?
1088
3.50k
                htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Gaps are not allowed during this state");
1089
3.50k
                return HTP_STREAM_CLOSED;
1090
3.50k
            }
1091
561k
        } else {
1092
561k
            rc = connp->in_state(connp);
1093
561k
        }
1094
561k
        if (rc == HTP_OK) {
1095
522k
            if (connp->in_status == HTP_STREAM_TUNNEL) {
1096
                #ifdef HTP_DEBUG
1097
                fprintf(stderr, "htp_connp_req_data: returning HTP_STREAM_TUNNEL\n");
1098
                #endif
1099
1100
78
                return HTP_STREAM_TUNNEL;
1101
78
            }
1102
1103
522k
            rc = htp_req_handle_state_change(connp);
1104
522k
        }
1105
1106
561k
        if (rc != HTP_OK) {
1107
            // Do we need more data?
1108
38.9k
            if ((rc == HTP_DATA) || (rc == HTP_DATA_BUFFER)) {
1109
31.3k
                htp_connp_req_receiver_send_data(connp, 0 /* not last */);
1110
1111
31.3k
                if (rc == HTP_DATA_BUFFER) {
1112
13.8k
                    if (htp_connp_req_buffer(connp) != HTP_OK) {
1113
34
                        connp->in_status = HTP_STREAM_ERROR;
1114
34
                        return HTP_STREAM_ERROR;
1115
34
                    }
1116
13.8k
                }
1117
1118
                #ifdef HTP_DEBUG
1119
                fprintf(stderr, "htp_connp_req_data: returning HTP_STREAM_DATA\n");
1120
                #endif
1121
1122
31.2k
                connp->in_status = HTP_STREAM_DATA;
1123
1124
31.2k
                return HTP_STREAM_DATA;
1125
31.3k
            }
1126
1127
            // Check for suspended parsing.
1128
7.64k
            if (rc == HTP_DATA_OTHER) {
1129
                // We might have actually consumed the entire data chunk?
1130
7.62k
                if (connp->in_current_read_offset >= connp->in_current_len) {
1131
                    // Do not send STREAM_DATE_DATA_OTHER if we've consumed the entire chunk.
1132
1133
                    #ifdef HTP_DEBUG
1134
                    fprintf(stderr, "htp_connp_req_data: returning HTP_STREAM_DATA (suspended parsing)\n");
1135
                    #endif
1136
1137
3.68k
                    connp->in_status = HTP_STREAM_DATA;
1138
1139
3.68k
                    return HTP_STREAM_DATA;
1140
3.94k
                } else {
1141
                    // Partial chunk consumption.
1142
1143
                    #ifdef HTP_DEBUG
1144
                    fprintf(stderr, "htp_connp_req_data: returning HTP_STREAM_DATA_OTHER\n");
1145
                    #endif
1146
1147
3.94k
                    connp->in_status = HTP_STREAM_DATA_OTHER;
1148
1149
3.94k
                    return HTP_STREAM_DATA_OTHER;
1150
3.94k
                }
1151
7.62k
            }
1152
1153
            // Check for the stop signal.
1154
24
            if (rc == HTP_STOP) {
1155
                #ifdef HTP_DEBUG
1156
                fprintf(stderr, "htp_connp_req_data: returning HTP_STREAM_STOP\n");
1157
                #endif
1158
1159
0
                connp->in_status = HTP_STREAM_STOP;
1160
1161
0
                return HTP_STREAM_STOP;
1162
0
            }
1163
1164
            #ifdef HTP_DEBUG
1165
            fprintf(stderr, "htp_connp_req_data: returning HTP_STREAM_ERROR\n");
1166
            #endif
1167
1168
            // Permanent stream error.
1169
24
            connp->in_status = HTP_STREAM_ERROR;
1170
1171
24
            return HTP_STREAM_ERROR;
1172
24
        }
1173
561k
    }
1174
42.5k
}