]> git.ipfire.org Git - people/ms/suricata.git/blame - src/app-layer-htp.c
doc: update file-extraction section
[people/ms/suricata.git] / src / app-layer-htp.c
CommitLineData
5532af46 1/* Copyright (C) 2007-2013 Open Information Security Foundation
ce019275
WM
2 *
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
5 * Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
07f7ba55 17
60a99915
EL
18/**
19 * \ingroup httplayer
20 *
21 * @{
22 */
23
07f7ba55 24/**
ce019275 25 * \file
07f7ba55 26 *
9d5d46c4 27 * \author Victor Julien <victor@inliniac.net>
07f7ba55 28 * \author Gurvinder Singh <gurvindersinghdahiya@gmail.com>
0165b3f0 29 * \author Pablo Rincon <pablo.rincon.crespo@gmail.com>
a9cdd2bb 30 * \author Brian Rectanus <brectanu@gmail.com>
5e2d9dbd 31 * \author Anoop Saldanha <anoopsaldanha@gmail.com>
07f7ba55 32 *
ce019275 33 * This file provides a HTTP protocol support for the engine using HTP library.
07f7ba55
GS
34 */
35
5c6a65dc 36#include "suricata.h"
ecf86f9c 37#include "suricata-common.h"
1235c578 38#include "conf.h"
07f7ba55
GS
39#include "debug.h"
40#include "decode.h"
41#include "threads.h"
cddbb0f6 42#include "counters.h"
07f7ba55
GS
43
44#include "util-print.h"
45#include "util-pool.h"
a9cdd2bb 46#include "util-radix-tree.h"
e1022ee5 47#include "util-file.h"
07f7ba55
GS
48
49#include "stream-tcp-private.h"
50#include "stream-tcp-reassemble.h"
6a53ab9c 51#include "stream-tcp.h"
07f7ba55
GS
52#include "stream.h"
53
54#include "app-layer-protos.h"
55#include "app-layer-parser.h"
a0ee6ade 56
429c6388 57#include "app-layer.h"
fc2f7f29 58#include "app-layer-htp.h"
a0ee6ade
VJ
59#include "app-layer-htp-body.h"
60#include "app-layer-htp-file.h"
48cf0585 61#include "app-layer-htp-libhtp.h"
1235c578 62#include "app-layer-htp-xff.h"
07f7ba55 63
705471e4 64#include "util-spm.h"
07f7ba55 65#include "util-debug.h"
fc2f7f29 66#include "util-time.h"
e0c13434 67#include "util-misc.h"
07f7ba55 68
06a65cb4
PR
69#include "util-unittest.h"
70#include "util-unittest-helper.h"
71#include "flow-util.h"
72
73#include "detect-engine.h"
74#include "detect-engine-state.h"
75#include "detect-parse.h"
76
5e2d9dbd 77#include "decode-events.h"
a9cdd2bb 78
4537f889 79#include "util-memcmp.h"
535d9e35 80#include "util-random.h"
e6494114 81#include "util-validate.h"
4537f889 82
32fb9f37
VJ
83//#define PRINT
84
ead13bda 85/** Fast lookup tree (radix) for the various HTP configurations */
a9cdd2bb 86static SCRadixTree *cfgtree;
ead13bda 87/** List of HTP configurations. */
a9cdd2bb
BR
88static HTPCfgRec cfglist;
89
07f7ba55 90#ifdef DEBUG
5532af46 91static SCMutex htp_state_mem_lock = SCMUTEX_INITIALIZER;
07f7ba55
GS
92static uint64_t htp_state_memuse = 0;
93static uint64_t htp_state_memcnt = 0;
94#endif
97d49d8f 95
f713b653
VJ
96SCEnumCharMap http_decoder_event_table[ ] = {
97 { "UNKNOWN_ERROR",
98 HTTP_DECODER_EVENT_UNKNOWN_ERROR},
99 { "GZIP_DECOMPRESSION_FAILED",
100 HTTP_DECODER_EVENT_GZIP_DECOMPRESSION_FAILED},
101 { "REQUEST_FIELD_MISSING_COLON",
102 HTTP_DECODER_EVENT_REQUEST_FIELD_MISSING_COLON},
93d121bf
VJ
103 { "RESPONSE_FIELD_MISSING_COLON",
104 HTTP_DECODER_EVENT_RESPONSE_FIELD_MISSING_COLON},
f713b653
VJ
105 { "INVALID_REQUEST_CHUNK_LEN",
106 HTTP_DECODER_EVENT_INVALID_REQUEST_CHUNK_LEN},
107 { "INVALID_RESPONSE_CHUNK_LEN",
108 HTTP_DECODER_EVENT_INVALID_RESPONSE_CHUNK_LEN},
109 { "INVALID_TRANSFER_ENCODING_VALUE_IN_REQUEST",
110 HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_REQUEST},
111 { "INVALID_TRANSFER_ENCODING_VALUE_IN_RESPONSE",
112 HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_RESPONSE},
113 { "INVALID_CONTENT_LENGTH_FIELD_IN_REQUEST",
114 HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_REQUEST},
115 { "INVALID_CONTENT_LENGTH_FIELD_IN_RESPONSE",
116 HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_RESPONSE},
117 { "100_CONTINUE_ALREADY_SEEN",
118 HTTP_DECODER_EVENT_100_CONTINUE_ALREADY_SEEN},
119 { "UNABLE_TO_MATCH_RESPONSE_TO_REQUEST",
120 HTTP_DECODER_EVENT_UNABLE_TO_MATCH_RESPONSE_TO_REQUEST},
121 { "INVALID_SERVER_PORT_IN_REQUEST",
122 HTTP_DECODER_EVENT_INVALID_SERVER_PORT_IN_REQUEST},
123 { "INVALID_AUTHORITY_PORT",
124 HTTP_DECODER_EVENT_INVALID_AUTHORITY_PORT},
93d121bf 125 { "REQUEST_HEADER_INVALID",
f713b653 126 HTTP_DECODER_EVENT_REQUEST_HEADER_INVALID},
93d121bf
VJ
127 { "RESPONSE_HEADER_INVALID",
128 HTTP_DECODER_EVENT_RESPONSE_HEADER_INVALID},
f713b653
VJ
129 { "MISSING_HOST_HEADER",
130 HTTP_DECODER_EVENT_MISSING_HOST_HEADER},
131 { "HOST_HEADER_AMBIGUOUS",
132 HTTP_DECODER_EVENT_HOST_HEADER_AMBIGUOUS},
133 { "INVALID_REQUEST_FIELD_FOLDING",
134 HTTP_DECODER_EVENT_INVALID_REQUEST_FIELD_FOLDING},
135 { "INVALID_RESPONSE_FIELD_FOLDING",
136 HTTP_DECODER_EVENT_INVALID_RESPONSE_FIELD_FOLDING},
137 { "REQUEST_FIELD_TOO_LONG",
138 HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG},
139 { "RESPONSE_FIELD_TOO_LONG",
140 HTTP_DECODER_EVENT_RESPONSE_FIELD_TOO_LONG},
b5f3e032
PA
141 { "REQUEST_LINE_INVALID",
142 HTTP_DECODER_EVENT_REQUEST_LINE_INVALID},
143 { "REQUEST_BODY_UNEXPECTED",
144 HTTP_DECODER_EVENT_REQUEST_BODY_UNEXPECTED},
9f519e95
VJ
145 { "REQUEST_SERVER_PORT_TCP_PORT_MISMATCH",
146 HTTP_DECODER_EVENT_REQUEST_SERVER_PORT_TCP_PORT_MISMATCH},
cb150003
VJ
147 { "REQUEST_URI_HOST_INVALID",
148 HTTP_DECODER_EVENT_URI_HOST_INVALID},
149 { "REQUEST_HEADER_HOST_INVALID",
150 HTTP_DECODER_EVENT_HEADER_HOST_INVALID},
a1c6e091
PA
151 { "REQUEST_AUTH_UNRECOGNIZED",
152 HTTP_DECODER_EVENT_AUTH_UNRECOGNIZED},
b6b7778e
PA
153 { "REQUEST_HEADER_REPETITION",
154 HTTP_DECODER_EVENT_REQUEST_HEADER_REPETITION},
155 { "RESPONSE_HEADER_REPETITION",
156 HTTP_DECODER_EVENT_RESPONSE_HEADER_REPETITION},
8a339e73
PA
157 { "DOUBLE_ENCODED_URI",
158 HTTP_DECODER_EVENT_DOUBLE_ENCODED_URI},
5ad7198d
VJ
159 { "URI_DELIM_NON_COMPLIANT",
160 HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT},
e78e33a4
VJ
161 { "METHOD_DELIM_NON_COMPLIANT",
162 HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT},
52195a41
VJ
163 { "REQUEST_LINE_LEADING_WHITESPACE",
164 HTTP_DECODER_EVENT_REQUEST_LINE_LEADING_WHITESPACE},
d0cded25
VJ
165 { "TOO_MANY_ENCODING_LAYERS",
166 HTTP_DECODER_EVENT_TOO_MANY_ENCODING_LAYERS},
167 { "ABNORMAL_CE_HEADER",
168 HTTP_DECODER_EVENT_ABNORMAL_CE_HEADER},
3e120668
PA
169 { "RESPONSE_MULTIPART_BYTERANGES",
170 HTTP_DECODER_EVENT_RESPONSE_MULTIPART_BYTERANGES},
171 { "RESPONSE_ABNORMAL_TRANSFER_ENCODING",
172 HTTP_DECODER_EVENT_RESPONSE_ABNORMAL_TRANSFER_ENCODING},
173 { "RESPONSE_CHUNKED_OLD_PROTO",
174 HTTP_DECODER_EVENT_RESPONSE_CHUNKED_OLD_PROTO},
175 { "RESPONSE_INVALID_PROTOCOL",
176 HTTP_DECODER_EVENT_RESPONSE_INVALID_PROTOCOL},
177 { "RESPONSE_INVALID_STATUS",
178 HTTP_DECODER_EVENT_RESPONSE_INVALID_STATUS},
179 { "REQUEST_LINE_INCOMPLETE",
180 HTTP_DECODER_EVENT_REQUEST_LINE_INCOMPLETE},
cb150003 181
c9c23d5c
VJ
182 { "LZMA_MEMLIMIT_REACHED",
183 HTTP_DECODER_EVENT_LZMA_MEMLIMIT_REACHED},
184
e21d8cdf
VJ
185 /* suricata warnings/errors */
186 { "MULTIPART_GENERIC_ERROR",
187 HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR},
188 { "MULTIPART_NO_FILEDATA",
189 HTTP_DECODER_EVENT_MULTIPART_NO_FILEDATA},
190 { "MULTIPART_INVALID_HEADER",
191 HTTP_DECODER_EVENT_MULTIPART_INVALID_HEADER},
192
f713b653
VJ
193 { NULL, -1 },
194};
195
d4d18e31
AS
196static void *HTPStateGetTx(void *alstate, uint64_t tx_id);
197static int HTPStateGetAlstateProgress(void *tx, uint8_t direction);
198static uint64_t HTPStateGetTxCnt(void *alstate);
199static int HTPStateGetAlstateProgressCompletionStatus(uint8_t direction);
200
9a58a025 201#ifdef DEBUG
a9cdd2bb
BR
202/**
203 * \internal
204 *
205 * \brief Lookup the HTP personality string from the numeric personality.
206 *
207 * \todo This needs to be a libhtp function.
208 */
209static const char *HTPLookupPersonalityString(int p)
210{
211#define CASE_HTP_PERSONALITY_STRING(p) \
212 case HTP_SERVER_ ## p: return #p
213
214 switch (p) {
215 CASE_HTP_PERSONALITY_STRING(MINIMAL);
216 CASE_HTP_PERSONALITY_STRING(GENERIC);
217 CASE_HTP_PERSONALITY_STRING(IDS);
218 CASE_HTP_PERSONALITY_STRING(IIS_4_0);
219 CASE_HTP_PERSONALITY_STRING(IIS_5_0);
220 CASE_HTP_PERSONALITY_STRING(IIS_5_1);
221 CASE_HTP_PERSONALITY_STRING(IIS_6_0);
222 CASE_HTP_PERSONALITY_STRING(IIS_7_0);
223 CASE_HTP_PERSONALITY_STRING(IIS_7_5);
48cf0585 224 CASE_HTP_PERSONALITY_STRING(APACHE_2);
a9cdd2bb
BR
225 }
226
227 return NULL;
228}
9a58a025 229#endif /* DEBUG */
a9cdd2bb
BR
230
231/**
232 * \internal
233 *
234 * \brief Lookup the numeric HTP personality from a string.
235 *
236 * \todo This needs to be a libhtp function.
237 */
238static int HTPLookupPersonality(const char *str)
239{
240#define IF_HTP_PERSONALITY_NUM(p) \
241 if (strcasecmp(#p, str) == 0) return HTP_SERVER_ ## p
242
243 IF_HTP_PERSONALITY_NUM(MINIMAL);
244 IF_HTP_PERSONALITY_NUM(GENERIC);
245 IF_HTP_PERSONALITY_NUM(IDS);
246 IF_HTP_PERSONALITY_NUM(IIS_4_0);
247 IF_HTP_PERSONALITY_NUM(IIS_5_0);
248 IF_HTP_PERSONALITY_NUM(IIS_5_1);
249 IF_HTP_PERSONALITY_NUM(IIS_6_0);
250 IF_HTP_PERSONALITY_NUM(IIS_7_0);
251 IF_HTP_PERSONALITY_NUM(IIS_7_5);
48cf0585 252 IF_HTP_PERSONALITY_NUM(APACHE_2);
51c2e1ea 253 if (strcasecmp("TOMCAT_6_0", str) == 0) {
48cf0585
AS
254 SCLogError(SC_WARN_OPTION_OBSOLETE, "Personality %s no "
255 "longer supported by libhtp.", str);
256 return -1;
51c2e1ea
VJ
257 } else if ((strcasecmp("APACHE", str) == 0) ||
258 (strcasecmp("APACHE_2_2", str) == 0))
259 {
260 SCLogWarning(SC_WARN_OPTION_OBSOLETE, "Personality %s no "
261 "longer supported by libhtp, failing back to "
262 "Apache2 personality.", str);
263 return HTP_SERVER_APACHE_2;
48cf0585 264 }
a9cdd2bb
BR
265
266 return -1;
267}
268
ab1200fb 269static void HTPSetEvent(HtpState *s, HtpTxUserData *htud, uint8_t e)
3f5acc54
VJ
270{
271 SCLogDebug("setting event %u", e);
272
273 if (htud) {
274 AppLayerDecoderEventsSetEventRaw(&htud->decoder_events, e);
275 s->events++;
276 return;
277 }
278
279 htp_tx_t *tx = HTPStateGetTx(s, s->transaction_cnt);
83e7ddf4
VJ
280 if (tx == NULL && s->transaction_cnt > 0)
281 tx = HTPStateGetTx(s, s->transaction_cnt - 1);
3f5acc54
VJ
282 if (tx != NULL) {
283 htud = (HtpTxUserData *) htp_tx_get_user_data(tx);
284 if (htud != NULL) {
285 AppLayerDecoderEventsSetEventRaw(&htud->decoder_events, e);
286 s->events++;
287 return;
288 }
289 }
290 SCLogDebug("couldn't set event %u", e);
291}
292
d568e7fa 293static AppLayerDecoderEvents *HTPGetEvents(void *tx)
3f5acc54 294{
d568e7fa 295 SCLogDebug("get HTTP events for TX %p", tx);
3f5acc54 296
d568e7fa
JL
297 HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx);
298 if (htud != NULL) {
299 SCLogDebug("has htud, htud->decoder_events %p", htud->decoder_events);
300 return htud->decoder_events;
3f5acc54 301 }
d568e7fa 302
3f5acc54
VJ
303 return NULL;
304}
305
07f7ba55
GS
306/** \brief Function to allocates the HTTP state memory and also creates the HTTP
307 * connection parser to be used by the HTP library
308 */
309static void *HTPStateAlloc(void)
310{
48248687
VJ
311 SCEnter();
312
ced01da8 313 HtpState *s = HTPMalloc(sizeof(HtpState));
bfc4be23
VJ
314 if (unlikely(s == NULL)) {
315 SCReturnPtr(NULL, "void");
316 }
07f7ba55 317
48248687 318 memset(s, 0x00, sizeof(HtpState));
07f7ba55 319
187949b9
VJ
320#ifdef DEBUG
321 SCMutexLock(&htp_state_mem_lock);
322 htp_state_memcnt++;
323 htp_state_memuse += sizeof(HtpState);
6fca55e0 324 SCLogDebug("htp memory %"PRIu64" (%"PRIu64")", htp_state_memuse, htp_state_memcnt);
187949b9
VJ
325 SCMutexUnlock(&htp_state_mem_lock);
326#endif
70b32f73 327
48248687 328 SCReturnPtr((void *)s, "void");
07f7ba55
GS
329}
330
f536099a 331static void HtpTxUserDataFree(HtpState *state, HtpTxUserData *htud)
8f1d7503 332{
f536099a 333 if (likely(htud)) {
6f2cb141
VJ
334 HtpBodyFree(&htud->request_body);
335 HtpBodyFree(&htud->response_body);
336 bstr_free(htud->request_uri_normalized);
337 if (htud->request_headers_raw)
ced01da8 338 HTPFree(htud->request_headers_raw, htud->request_headers_raw_len);
6f2cb141 339 if (htud->response_headers_raw)
ced01da8 340 HTPFree(htud->response_headers_raw, htud->response_headers_raw_len);
3f5acc54 341 AppLayerDecoderEventsFreeEvents(&htud->decoder_events);
6f2cb141 342 if (htud->boundary)
ced01da8 343 HTPFree(htud->boundary, htud->boundary_len);
774bb903
VJ
344 if (htud->de_state != NULL) {
345 DetectEngineStateFree(htud->de_state);
346 }
ced01da8 347 HTPFree(htud, sizeof(HtpTxUserData));
6f2cb141
VJ
348 }
349}
350
07f7ba55
GS
351/** \brief Function to frees the HTTP state memory and also frees the HTTP
352 * connection parser memory which was used by the HTP library
353 */
25a3a5c6 354void HTPStateFree(void *state)
07f7ba55 355{
48248687
VJ
356 SCEnter();
357
358 HtpState *s = (HtpState *)state;
a56592e5
GIG
359 if (s == NULL) {
360 SCReturn;
361 }
48248687 362
07f7ba55 363 /* free the connection parser memory used by HTP library */
a56592e5 364 if (s->connp != NULL) {
6fca55e0
VJ
365 SCLogDebug("freeing HTP state");
366
d4d18e31
AS
367 uint64_t tx_id;
368 uint64_t total_txs = HTPStateGetTxCnt(state);
bc55fb27 369 /* free the list of body chunks */
48cf0585 370 if (s->conn != NULL) {
d4d18e31
AS
371 for (tx_id = 0; tx_id < total_txs; tx_id++) {
372 htp_tx_t *tx = HTPStateGetTx(s, tx_id);
bc55fb27 373 if (tx != NULL) {
66a3cd96 374 HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx);
f536099a
VJ
375 HtpTxUserDataFree(s, htud);
376 htp_tx_set_user_data(tx, NULL);
06a65cb4
PR
377 }
378 }
48248687 379 }
bc55fb27 380 htp_connp_destroy_all(s->connp);
48248687 381 }
07f7ba55 382
d59ca75e
VJ
383 FileContainerFree(s->files_ts);
384 FileContainerFree(s->files_tc);
ced01da8 385 HTPFree(s, sizeof(HtpState));
48248687 386
07f7ba55 387#ifdef DEBUG
e26833be 388 SCMutexLock(&htp_state_mem_lock);
07f7ba55 389 htp_state_memcnt--;
187949b9 390 htp_state_memuse -= sizeof(HtpState);
6fca55e0 391 SCLogDebug("htp memory %"PRIu64" (%"PRIu64")", htp_state_memuse, htp_state_memcnt);
e26833be 392 SCMutexUnlock(&htp_state_mem_lock);
07f7ba55 393#endif
48248687
VJ
394
395 SCReturn;
07f7ba55
GS
396}
397
70b32f73
VJ
398/**
399 * \brief HTP transaction cleanup callback
400 *
401 * \warning We cannot actually free the transactions here. It seems that
402 * HTP only accepts freeing of transactions in the response callback.
403 */
8f1d7503
KS
404static void HTPStateTransactionFree(void *state, uint64_t id)
405{
70b32f73
VJ
406 SCEnter();
407
408 HtpState *s = (HtpState *)state;
409
f59f9033 410 SCLogDebug("state %p, id %"PRIu64, s, id);
70b32f73 411
0fd9b0c4
VJ
412 htp_tx_t *tx = HTPStateGetTx(s, id);
413 if (tx != NULL) {
414 /* This will remove obsolete body chunks */
415 HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx);
f536099a
VJ
416 HtpTxUserDataFree(s, htud);
417 htp_tx_set_user_data(tx, NULL);
70b32f73 418
bbc9874b
VJ
419 /* hack: even if libhtp considers the tx incomplete, we want to
420 * free it here. htp_tx_destroy however, will refuse to do this.
421 * As htp_tx_destroy_incomplete isn't available in the public API,
422 * we hack around it here. */
423 if (unlikely(!(
424 tx->request_progress == HTP_REQUEST_COMPLETE &&
425 tx->response_progress == HTP_RESPONSE_COMPLETE)))
426 {
427 tx->request_progress = HTP_REQUEST_COMPLETE;
428 tx->response_progress = HTP_RESPONSE_COMPLETE;
429 }
0fd9b0c4
VJ
430 htp_tx_destroy(tx);
431 }
70b32f73
VJ
432}
433
97d49d8f
AS
434/**
435 * \brief Sets a flag that informs the HTP app layer that some module in the
436 * engine needs the http request body data.
bc55fb27 437 * \initonly
97d49d8f
AS
438 */
439void AppLayerHtpEnableRequestBodyCallback(void)
440{
70b32f73 441 SCEnter();
92679442
EL
442
443 SC_ATOMIC_OR(htp_config_flags, HTP_REQUIRE_REQUEST_BODY);
70b32f73 444 SCReturn;
97d49d8f
AS
445}
446
b402d971
VJ
447/**
448 * \brief Sets a flag that informs the HTP app layer that some module in the
449 * engine needs the http request body data.
450 * \initonly
451 */
452void AppLayerHtpEnableResponseBodyCallback(void)
453{
454 SCEnter();
92679442
EL
455
456 SC_ATOMIC_OR(htp_config_flags, HTP_REQUIRE_RESPONSE_BODY);
b402d971
VJ
457 SCReturn;
458}
459
6d60b3a7
PR
460/**
461 * \brief Sets a flag that informs the HTP app layer that some module in the
ef053679
VJ
462 * engine needs the http request multi part header.
463 *
6d60b3a7
PR
464 * \initonly
465 */
ab1200fb 466static void AppLayerHtpNeedMultipartHeader(void)
8f1d7503 467{
6d60b3a7 468 SCEnter();
ef053679
VJ
469 AppLayerHtpEnableRequestBodyCallback();
470
92679442 471 SC_ATOMIC_OR(htp_config_flags, HTP_REQUIRE_REQUEST_MULTIPART);
21acd72a
VJ
472 SCReturn;
473}
474
ef053679
VJ
475/**
476 * \brief Sets a flag that informs the HTP app layer that some module in the
477 * engine needs the http request file.
478 *
479 * \initonly
480 */
481void AppLayerHtpNeedFileInspection(void)
482{
21acd72a 483 SCEnter();
ef053679 484 AppLayerHtpNeedMultipartHeader();
b402d971
VJ
485 AppLayerHtpEnableRequestBodyCallback();
486 AppLayerHtpEnableResponseBodyCallback();
ef053679 487
92679442 488 SC_ATOMIC_OR(htp_config_flags, HTP_REQUIRE_REQUEST_FILE);
6d60b3a7
PR
489 SCReturn;
490}
491
de904db8
GL
492static void AppLayerHtpSetStreamDepthFlag(void *tx, uint8_t flags)
493{
494 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data((htp_tx_t *)tx);
495 if (tx_ud) {
496 if (flags & STREAM_TOCLIENT) {
497 tx_ud->tcflags |= HTP_STREAM_DEPTH_SET;
498 } else {
499 tx_ud->tsflags |= HTP_STREAM_DEPTH_SET;
500 }
501 }
502}
503
504static bool AppLayerHtpCheckStreamDepth(uint64_t content_len_so_far, uint8_t flags)
505{
506 if (flags & HTP_STREAM_DEPTH_SET) {
507 uint32_t stream_depth = FileReassemblyDepth();
508 if (content_len_so_far < (uint64_t)stream_depth || stream_depth == 0) {
509 return true;
510 }
511 }
512
513 return false;
514}
515
516static uint32_t AppLayerHtpComputeChunkLength(uint64_t content_len_so_far, uint32_t body_limit,
517 uint32_t stream_depth, uint8_t flags, uint32_t data_len)
518{
519 uint32_t chunk_len = 0;
520 if (!(flags & HTP_STREAM_DEPTH_SET) && body_limit > 0 &&
521 (content_len_so_far < (uint64_t)body_limit) &&
522 (content_len_so_far + (uint64_t)data_len) > body_limit)
523 {
524 chunk_len = body_limit - content_len_so_far;
525 } else if ((flags & HTP_STREAM_DEPTH_SET) && stream_depth > 0 &&
526 (content_len_so_far < (uint64_t)stream_depth) &&
527 (content_len_so_far + (uint64_t)data_len) > stream_depth)
528 {
529 chunk_len = stream_depth - content_len_so_far;
530 }
531 SCLogDebug("len %u", chunk_len);
532 return (chunk_len == 0 ? data_len : chunk_len);
533}
534
43b39d33 535/* below error messages updated up to libhtp 0.5.7 (git 379632278b38b9a792183694a4febb9e0dbd1e7a) */
f713b653 536struct {
ab1200fb 537 const char *msg;
f713b653
VJ
538 int de;
539} htp_errors[] = {
540 { "GZip decompressor: inflateInit2 failed", HTTP_DECODER_EVENT_GZIP_DECOMPRESSION_FAILED},
541 { "Request field invalid: colon missing", HTTP_DECODER_EVENT_REQUEST_FIELD_MISSING_COLON},
43b39d33 542 { "Response field invalid: missing colon", HTTP_DECODER_EVENT_RESPONSE_FIELD_MISSING_COLON},
f713b653
VJ
543 { "Request chunk encoding: Invalid chunk length", HTTP_DECODER_EVENT_INVALID_REQUEST_CHUNK_LEN},
544 { "Response chunk encoding: Invalid chunk length", HTTP_DECODER_EVENT_INVALID_RESPONSE_CHUNK_LEN},
43b39d33
VJ
545/* { "Invalid T-E value in request", HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_REQUEST}, <- tx flag HTP_REQUEST_INVALID_T_E
546 { "Invalid T-E value in response", HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_RESPONSE}, <- nothing to replace it */
547/* { "Invalid C-L field in request", HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_REQUEST}, <- tx flag HTP_REQUEST_INVALID_C_L */
f713b653
VJ
548 { "Invalid C-L field in response", HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_RESPONSE},
549 { "Already seen 100-Continue", HTTP_DECODER_EVENT_100_CONTINUE_ALREADY_SEEN},
550 { "Unable to match response to request", HTTP_DECODER_EVENT_UNABLE_TO_MATCH_RESPONSE_TO_REQUEST},
551 { "Invalid server port information in request", HTTP_DECODER_EVENT_INVALID_SERVER_PORT_IN_REQUEST},
43b39d33 552/* { "Invalid authority port", HTTP_DECODER_EVENT_INVALID_AUTHORITY_PORT}, htp no longer returns this error */
63679175
VJ
553 { "Request buffer over", HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG},
554 { "Response buffer over", HTTP_DECODER_EVENT_RESPONSE_FIELD_TOO_LONG},
3e120668 555 { "C-T multipart/byteranges in responses not supported", HTTP_DECODER_EVENT_RESPONSE_MULTIPART_BYTERANGES},
f713b653
VJ
556};
557
558struct {
ab1200fb 559 const char *msg;
f713b653
VJ
560 int de;
561} htp_warnings[] = {
562 { "GZip decompressor:", HTTP_DECODER_EVENT_GZIP_DECOMPRESSION_FAILED},
563 { "Request field invalid", HTTP_DECODER_EVENT_REQUEST_HEADER_INVALID},
93d121bf 564 { "Response field invalid", HTTP_DECODER_EVENT_RESPONSE_HEADER_INVALID},
f713b653 565 { "Request header name is not a token", HTTP_DECODER_EVENT_REQUEST_HEADER_INVALID},
93d121bf 566 { "Response header name is not a token", HTTP_DECODER_EVENT_RESPONSE_HEADER_INVALID},
43b39d33
VJ
567/* { "Host information in request headers required by HTTP/1.1", HTTP_DECODER_EVENT_MISSING_HOST_HEADER}, <- tx flag HTP_HOST_MISSING
568 { "Host information ambiguous", HTTP_DECODER_EVENT_HOST_HEADER_AMBIGUOUS}, <- tx flag HTP_HOST_AMBIGUOUS */
f713b653
VJ
569 { "Invalid request field folding", HTTP_DECODER_EVENT_INVALID_REQUEST_FIELD_FOLDING},
570 { "Invalid response field folding", HTTP_DECODER_EVENT_INVALID_RESPONSE_FIELD_FOLDING},
43b39d33
VJ
571 /* line is now: htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Request server port=%d number differs from the actual TCP port=%d", port, connp->conn->server_port);
572 * luckily, "Request server port=" is unique */
573/* { "Request server port number differs from the actual TCP port", HTTP_DECODER_EVENT_REQUEST_SERVER_PORT_TCP_PORT_MISMATCH}, */
574 { "Request server port=", HTTP_DECODER_EVENT_REQUEST_SERVER_PORT_TCP_PORT_MISMATCH},
5ad7198d 575 { "Request line: URI contains non-compliant delimiter", HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT},
e78e33a4 576 { "Request line: non-compliant delimiter between Method and URI", HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT},
52195a41 577 { "Request line: leading whitespace", HTTP_DECODER_EVENT_REQUEST_LINE_LEADING_WHITESPACE},
d0cded25
VJ
578 { "Too many response content encoding layers", HTTP_DECODER_EVENT_TOO_MANY_ENCODING_LAYERS},
579 { "C-E gzip has abnormal value", HTTP_DECODER_EVENT_ABNORMAL_CE_HEADER},
580 { "C-E deflate has abnormal value", HTTP_DECODER_EVENT_ABNORMAL_CE_HEADER},
581 { "C-E unknown setting", HTTP_DECODER_EVENT_ABNORMAL_CE_HEADER},
b6b7778e
PA
582 { "Excessive request header repetitions", HTTP_DECODER_EVENT_REQUEST_HEADER_REPETITION},
583 { "Excessive response header repetitions", HTTP_DECODER_EVENT_RESPONSE_HEADER_REPETITION},
3e120668
PA
584 { "Transfer-encoding has abnormal chunked value", HTTP_DECODER_EVENT_RESPONSE_ABNORMAL_TRANSFER_ENCODING},
585 { "Chunked transfer-encoding on HTTP/0.9 or HTTP/1.0", HTTP_DECODER_EVENT_RESPONSE_CHUNKED_OLD_PROTO},
586 { "Invalid response line: invalid protocol", HTTP_DECODER_EVENT_RESPONSE_INVALID_PROTOCOL},
587 { "Invalid response line: invalid response status", HTTP_DECODER_EVENT_RESPONSE_INVALID_STATUS},
588 { "Request line incomplete", HTTP_DECODER_EVENT_REQUEST_LINE_INCOMPLETE},
b5f3e032 589 { "Unexpected request body", HTTP_DECODER_EVENT_REQUEST_BODY_UNEXPECTED},
c9c23d5c 590 { "LZMA decompressor: memory limit reached", HTTP_DECODER_EVENT_LZMA_MEMLIMIT_REACHED},
f713b653
VJ
591};
592
593#define HTP_ERROR_MAX (sizeof(htp_errors) / sizeof(htp_errors[0]))
594#define HTP_WARNING_MAX (sizeof(htp_warnings) / sizeof(htp_warnings[0]))
595
596/**
597 * \internal
598 *
599 * \brief Get the warning id for the warning msg.
600 *
601 * \param msg warning message
602 *
603 * \retval id the id or 0 in case of not found
604 */
8f1d7503
KS
605static int HTPHandleWarningGetId(const char *msg)
606{
00948c86 607 SCLogDebug("received warning \"%s\"", msg);
f713b653
VJ
608 size_t idx;
609 for (idx = 0; idx < HTP_WARNING_MAX; idx++) {
610 if (strncmp(htp_warnings[idx].msg, msg,
611 strlen(htp_warnings[idx].msg)) == 0)
612 {
613 return htp_warnings[idx].de;
614 }
615 }
616
617 return 0;
618}
619
620/**
621 * \internal
622 *
623 * \brief Get the error id for the error msg.
624 *
625 * \param msg error message
626 *
627 * \retval id the id or 0 in case of not found
628 */
8f1d7503
KS
629static int HTPHandleErrorGetId(const char *msg)
630{
00948c86
VJ
631 SCLogDebug("received error \"%s\"", msg);
632
f713b653
VJ
633 size_t idx;
634 for (idx = 0; idx < HTP_ERROR_MAX; idx++) {
635 if (strncmp(htp_errors[idx].msg, msg,
636 strlen(htp_errors[idx].msg)) == 0)
637 {
638 return htp_errors[idx].de;
639 }
640 }
641
642 return 0;
643}
644
645/**
646 * \internal
647 *
648 * \brief Check state for errors, warnings and add any as events
649 *
650 * \param s state
651 */
8f1d7503
KS
652static void HTPHandleError(HtpState *s)
653{
48cf0585
AS
654 if (s == NULL || s->conn == NULL ||
655 s->conn->messages == NULL) {
f713b653
VJ
656 return;
657 }
658
48cf0585 659 size_t size = htp_list_size(s->conn->messages);
f713b653
VJ
660 size_t msg;
661
3f5acc54 662 for (msg = s->htp_messages_offset; msg < size; msg++) {
48cf0585 663 htp_log_t *log = htp_list_get(s->conn->messages, msg);
f713b653
VJ
664 if (log == NULL)
665 continue;
666
3f5acc54
VJ
667 HtpTxUserData *htud = NULL;
668 htp_tx_t *tx = log->tx; // will be NULL in <=0.5.9
669 if (tx != NULL)
670 htud = (HtpTxUserData *) htp_tx_get_user_data(tx);
671
43544345
VJ
672 SCLogDebug("message %s", log->msg);
673
f713b653 674 int id = HTPHandleErrorGetId(log->msg);
3f5acc54 675 if (id == 0) {
f713b653 676 id = HTPHandleWarningGetId(log->msg);
3f5acc54
VJ
677 if (id == 0)
678 id = HTTP_DECODER_EVENT_UNKNOWN_ERROR;
f713b653 679 }
f713b653 680
f713b653 681 if (id > 0) {
3f5acc54 682 HTPSetEvent(s, htud, id);
f713b653
VJ
683 }
684 }
3f5acc54
VJ
685 s->htp_messages_offset = (uint16_t)msg;
686 SCLogDebug("s->htp_messages_offset %u", s->htp_messages_offset);
f713b653 687}
97d49d8f 688
43b39d33
VJ
689static inline void HTPErrorCheckTxRequestFlags(HtpState *s, htp_tx_t *tx)
690{
691#ifdef DEBUG
692 BUG_ON(s == NULL || tx == NULL);
693#endif
694 if (tx->flags & ( HTP_REQUEST_INVALID_T_E|HTP_REQUEST_INVALID_C_L|
cb150003
VJ
695 HTP_HOST_MISSING|HTP_HOST_AMBIGUOUS|HTP_HOSTU_INVALID|
696 HTP_HOSTH_INVALID))
43b39d33 697 {
3f5acc54
VJ
698 HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx);
699 if (htud == NULL)
700 return;
701
43b39d33 702 if (tx->flags & HTP_REQUEST_INVALID_T_E)
3f5acc54 703 HTPSetEvent(s, htud,
43b39d33
VJ
704 HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_REQUEST);
705 if (tx->flags & HTP_REQUEST_INVALID_C_L)
3f5acc54 706 HTPSetEvent(s, htud,
43b39d33
VJ
707 HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_REQUEST);
708 if (tx->flags & HTP_HOST_MISSING)
3f5acc54 709 HTPSetEvent(s, htud,
43b39d33
VJ
710 HTTP_DECODER_EVENT_MISSING_HOST_HEADER);
711 if (tx->flags & HTP_HOST_AMBIGUOUS)
3f5acc54 712 HTPSetEvent(s, htud,
43b39d33 713 HTTP_DECODER_EVENT_HOST_HEADER_AMBIGUOUS);
cb150003 714 if (tx->flags & HTP_HOSTU_INVALID)
3f5acc54 715 HTPSetEvent(s, htud,
cb150003
VJ
716 HTTP_DECODER_EVENT_URI_HOST_INVALID);
717 if (tx->flags & HTP_HOSTH_INVALID)
3f5acc54 718 HTPSetEvent(s, htud,
cb150003 719 HTTP_DECODER_EVENT_HEADER_HOST_INVALID);
43b39d33 720 }
a1c6e091
PA
721 if (tx->request_auth_type == HTP_AUTH_UNRECOGNIZED) {
722 HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx);
723 if (htud == NULL)
724 return;
a1c6e091
PA
725 HTPSetEvent(s, htud, HTTP_DECODER_EVENT_AUTH_UNRECOGNIZED);
726 }
b5f3e032
PA
727 if (tx->is_protocol_0_9 && tx->request_method_number == HTP_M_UNKNOWN &&
728 (tx->request_protocol_number == HTP_PROTOCOL_INVALID ||
729 tx->request_protocol_number == HTP_PROTOCOL_UNKNOWN)) {
730 HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx);
731 if (htud == NULL)
732 return;
733 HTPSetEvent(s, htud, HTTP_DECODER_EVENT_REQUEST_LINE_INVALID);
734 }
43b39d33
VJ
735}
736
e6494114
VJ
737static int Setup(Flow *f, HtpState *hstate)
738{
739 /* store flow ref in state so callbacks can access it */
740 hstate->f = f;
741
742 HTPCfgRec *htp_cfg_rec = &cfglist;
743 htp_cfg_t *htp = cfglist.cfg; /* Default to the global HTP config */
744 void *user_data = NULL;
745
746 if (FLOW_IS_IPV4(f)) {
747 SCLogDebug("Looking up HTP config for ipv4 %08x", *GET_IPV4_DST_ADDR_PTR(f));
748 (void)SCRadixFindKeyIPV4BestMatch((uint8_t *)GET_IPV4_DST_ADDR_PTR(f), cfgtree, &user_data);
749 }
750 else if (FLOW_IS_IPV6(f)) {
751 SCLogDebug("Looking up HTP config for ipv6");
752 (void)SCRadixFindKeyIPV6BestMatch((uint8_t *)GET_IPV6_DST_ADDR(f), cfgtree, &user_data);
753 }
754 else {
755 SCLogError(SC_ERR_INVALID_ARGUMENT, "unknown address family, bug!");
756 goto error;
757 }
758
759 if (user_data != NULL) {
760 htp_cfg_rec = user_data;
761 htp = htp_cfg_rec->cfg;
762 SCLogDebug("LIBHTP using config: %p", htp);
763 } else {
764 SCLogDebug("Using default HTP config: %p", htp);
765 }
766
767 if (NULL == htp) {
768#ifdef DEBUG_VALIDATION
769 BUG_ON(htp == NULL);
770#endif
771 /* should never happen if HTPConfigure is properly invoked */
772 goto error;
773 }
774
775 hstate->connp = htp_connp_create(htp);
776 if (hstate->connp == NULL) {
777 goto error;
778 }
779
780 hstate->conn = htp_connp_get_connection(hstate->connp);
781
782 htp_connp_set_user_data(hstate->connp, (void *)hstate);
783 hstate->cfg = htp_cfg_rec;
784
785 SCLogDebug("New hstate->connp %p", hstate->connp);
786
787 htp_connp_open(hstate->connp, NULL, f->sp, NULL, f->dp, &f->startts);
788
7186ce7b
VJ
789 StreamTcpReassemblySetMinInspectDepth(f->protoctx, STREAM_TOSERVER,
790 htp_cfg_rec->request.inspect_min_size);
791 StreamTcpReassemblySetMinInspectDepth(f->protoctx, STREAM_TOCLIENT,
792 htp_cfg_rec->response.inspect_min_size);
e6494114
VJ
793 return 0;
794error:
795 return -1;
796}
797
07f7ba55
GS
798/**
799 * \brief Function to handle the reassembled data from client and feed it to
800 * the HTP library to process it.
801 *
92d74fd4 802 * \param flow Pointer to the flow the data belong to
07f7ba55
GS
803 * \param htp_state Pointer the state in which the parsed value to be stored
804 * \param pstate Application layer parser state for this session
805 * \param input Pointer the received HTTP client data
806 * \param input_len Length in bytes of the received data
807 * \param output Pointer to the output (not used in this function)
808 *
48cf0585 809 * \retval On success returns 1 or on failure returns -1.
07f7ba55 810 */
fc2f7f29 811static int HTPHandleRequestData(Flow *f, void *htp_state,
9634e60e 812 AppLayerParserState *pstate,
579cc9f0 813 const uint8_t *input, uint32_t input_len,
7bc3c3ac 814 void *local_data, const uint8_t flags)
07f7ba55 815{
1b39e602 816 SCEnter();
0a85fd67 817 int ret = 1;
07f7ba55 818 HtpState *hstate = (HtpState *)htp_state;
a9cdd2bb
BR
819
820 /* On the first invocation, create the connection parser structure to
821 * be used by HTP library. This is looked up via IP in the radix
822 * tree. Failing that, the default HTP config is used.
823 */
48cf0585 824 if (NULL == hstate->conn) {
e6494114 825 if (Setup(f, hstate) != 0) {
78e15ea7
VJ
826 goto error;
827 }
a9cdd2bb 828 }
e6494114 829 DEBUG_VALIDATE_BUG_ON(hstate->connp == NULL);
4129146a 830
7acea2c6 831 htp_time_t ts = { f->lastts.tv_sec, f->lastts.tv_usec };
70b32f73 832 /* pass the new data to the htp parser */
cf9ff6ad 833 if (input_len > 0) {
07cbbfb0
VJ
834 const int r = htp_connp_req_data(hstate->connp, &ts, input, input_len);
835 switch (r) {
cf9ff6ad 836 case HTP_STREAM_ERROR:
cf9ff6ad
VJ
837 ret = -1;
838 break;
cf9ff6ad 839 default:
daeba48f 840 break;
cf9ff6ad
VJ
841 }
842 HTPHandleError(hstate);
70b32f73 843 }
07f7ba55 844
a9cdd2bb 845 /* if the TCP connection is closed, then close the HTTP connection */
8527b8e0 846 if (AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF) &&
429c6388
AS
847 !(hstate->flags & HTP_FLAG_STATE_CLOSED_TS))
848 {
48cf0585 849 htp_connp_close(hstate->connp, &ts);
64625675
AS
850 hstate->flags |= HTP_FLAG_STATE_CLOSED_TS;
851 SCLogDebug("stream eof encountered, closing htp handle for ts");
fc2f7f29
GS
852 }
853
48248687 854 SCLogDebug("hstate->connp %p", hstate->connp);
0a85fd67 855 SCReturnInt(ret);
a9cdd2bb
BR
856
857error:
858 SCReturnInt(-1);
07f7ba55
GS
859}
860
861/**
862 * \brief Function to handle the reassembled data from server and feed it to
863 * the HTP library to process it.
864 *
92d74fd4 865 * \param flow Pointer to the flow the data belong to
07f7ba55
GS
866 * \param htp_state Pointer the state in which the parsed value to be stored
867 * \param pstate Application layer parser state for this session
868 * \param input Pointer the received HTTP server data
869 * \param input_len Length in bytes of the received data
870 * \param output Pointer to the output (not used in this function)
871 *
2d6cf71d 872 * \retval On success returns 1 or on failure returns -1
07f7ba55 873 */
fc2f7f29 874static int HTPHandleResponseData(Flow *f, void *htp_state,
9634e60e 875 AppLayerParserState *pstate,
579cc9f0 876 const uint8_t *input, uint32_t input_len,
7bc3c3ac 877 void *local_data, const uint8_t flags)
07f7ba55 878{
1b39e602 879 SCEnter();
0a85fd67 880 int ret = 1;
07f7ba55 881 HtpState *hstate = (HtpState *)htp_state;
07cbbfb0 882
e6494114
VJ
883 /* On the first invocation, create the connection parser structure to
884 * be used by HTP library. This is looked up via IP in the radix
885 * tree. Failing that, the default HTP config is used.
886 */
887 if (NULL == hstate->conn) {
888 if (Setup(f, hstate) != 0) {
889 goto error;
890 }
4129146a 891 }
e6494114 892 DEBUG_VALIDATE_BUG_ON(hstate->connp == NULL);
07f7ba55 893
7acea2c6 894 htp_time_t ts = { f->lastts.tv_sec, f->lastts.tv_usec };
cf9ff6ad 895 if (input_len > 0) {
07cbbfb0
VJ
896 const int r = htp_connp_res_data(hstate->connp, &ts, input, input_len);
897 switch (r) {
cf9ff6ad 898 case HTP_STREAM_ERROR:
cf9ff6ad
VJ
899 ret = -1;
900 break;
cf9ff6ad 901 default:
daeba48f 902 break;
cf9ff6ad
VJ
903 }
904 HTPHandleError(hstate);
905 }
07f7ba55 906
fc2f7f29 907 /* if we the TCP connection is closed, then close the HTTP connection */
8527b8e0 908 if (AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF) &&
429c6388
AS
909 !(hstate->flags & HTP_FLAG_STATE_CLOSED_TC))
910 {
48cf0585 911 htp_connp_close(hstate->connp, &ts);
64625675 912 hstate->flags |= HTP_FLAG_STATE_CLOSED_TC;
fc2f7f29
GS
913 }
914
48248687 915 SCLogDebug("hstate->connp %p", hstate->connp);
0a85fd67 916 SCReturnInt(ret);
e6494114
VJ
917error:
918 SCReturnInt(-1);
07f7ba55
GS
919}
920
4537f889
VJ
921/**
922 * \param name /Lowercase/ version of the variable name
923 */
924static int HTTPParseContentDispositionHeader(uint8_t *name, size_t name_len,
925 uint8_t *data, size_t len, uint8_t **retptr, size_t *retlen)
926{
32fb9f37 927#ifdef PRINT
4537f889
VJ
928 printf("DATA START: \n");
929 PrintRawDataFp(stdout, data, len);
930 printf("DATA END: \n");
931#endif
932 size_t x;
933 int quote = 0;
934
935 for (x = 0; x < len; x++) {
936 if (!(isspace(data[x])))
937 break;
938 }
939
940 if (x >= len)
941 return 0;
942
943 uint8_t *line = data+x;
944 size_t line_len = len-x;
945 size_t offset = 0;
32fb9f37 946#ifdef PRINT
4537f889
VJ
947 printf("LINE START: \n");
948 PrintRawDataFp(stdout, line, line_len);
949 printf("LINE END: \n");
950#endif
951 for (x = 0 ; x < line_len; x++) {
952 if (x > 0) {
953 if (line[x - 1] != '\\' && line[x] == '\"') {
954 quote++;
955 }
956
957 if (((line[x - 1] != '\\' && line[x] == ';') || ((x + 1) == line_len)) && (quote == 0 || quote % 2 == 0)) {
958 uint8_t *token = line + offset;
959 size_t token_len = x - offset;
960
961 if ((x + 1) == line_len) {
962 token_len++;
963 }
964
965 offset = x + 1;
966
967 while (offset < line_len && isspace(line[offset])) {
968 x++;
969 offset++;
970 }
32fb9f37 971#ifdef PRINT
4537f889
VJ
972 printf("TOKEN START: \n");
973 PrintRawDataFp(stdout, token, token_len);
974 printf("TOKEN END: \n");
975#endif
976 if (token_len > name_len) {
977 if (name == NULL || SCMemcmpLowercase(name, token, name_len) == 0) {
978 uint8_t *value = token + name_len;
979 size_t value_len = token_len - name_len;
980
981 if (value[0] == '\"') {
982 value++;
983 value_len--;
984 }
985 if (value[value_len-1] == '\"') {
986 value_len--;
987 }
32fb9f37 988#ifdef PRINT
4537f889
VJ
989 printf("VALUE START: \n");
990 PrintRawDataFp(stdout, value, value_len);
991 printf("VALUE END: \n");
992#endif
993 *retptr = value;
994 *retlen = value_len;
995 return 1;
996 }
997 }
998 }
999 }
1000 }
1001
1002 return 0;
1003}
1004
1005/**
1006 * \param name /Lowercase/ version of the variable name
1007 */
1008static int HTTPParseContentTypeHeader(uint8_t *name, size_t name_len,
1009 uint8_t *data, size_t len, uint8_t **retptr, size_t *retlen)
1010{
1011 SCEnter();
32fb9f37 1012#ifdef PRINT
4537f889
VJ
1013 printf("DATA START: \n");
1014 PrintRawDataFp(stdout, data, len);
1015 printf("DATA END: \n");
1016#endif
1017 size_t x;
1018 int quote = 0;
1019
1020 for (x = 0; x < len; x++) {
1021 if (!(isspace(data[x])))
1022 break;
1023 }
1024
a0ee6ade
VJ
1025 if (x >= len) {
1026 SCReturnInt(0);
1027 }
4537f889
VJ
1028
1029 uint8_t *line = data+x;
1030 size_t line_len = len-x;
1031 size_t offset = 0;
32fb9f37 1032#ifdef PRINT
4537f889
VJ
1033 printf("LINE START: \n");
1034 PrintRawDataFp(stdout, line, line_len);
1035 printf("LINE END: \n");
1036#endif
1037 for (x = 0 ; x < line_len; x++) {
1038 if (x > 0) {
1039 if (line[x - 1] != '\\' && line[x] == '\"') {
1040 quote++;
1041 }
1042
1043 if (((line[x - 1] != '\\' && line[x] == ';') || ((x + 1) == line_len)) && (quote == 0 || quote % 2 == 0)) {
1044 uint8_t *token = line + offset;
1045 size_t token_len = x - offset;
1046
1047 if ((x + 1) == line_len) {
1048 token_len++;
1049 }
1050
1051 offset = x + 1;
1052
1053 while (offset < line_len && isspace(line[offset])) {
1054 x++;
1055 offset++;
1056 }
32fb9f37 1057#ifdef PRINT
4537f889
VJ
1058 printf("TOKEN START: \n");
1059 PrintRawDataFp(stdout, token, token_len);
1060 printf("TOKEN END: \n");
1061#endif
1062 if (token_len > name_len) {
1063 if (name == NULL || SCMemcmpLowercase(name, token, name_len) == 0) {
1064 uint8_t *value = token + name_len;
1065 size_t value_len = token_len - name_len;
1066
1067 if (value[0] == '\"') {
1068 value++;
1069 value_len--;
1070 }
1071 if (value[value_len-1] == '\"') {
1072 value_len--;
1073 }
32fb9f37 1074#ifdef PRINT
4537f889
VJ
1075 printf("VALUE START: \n");
1076 PrintRawDataFp(stdout, value, value_len);
1077 printf("VALUE END: \n");
1078#endif
1079 *retptr = value;
1080 *retlen = value_len;
a0ee6ade 1081 SCReturnInt(1);
4537f889
VJ
1082 }
1083 }
1084 }
1085 }
1086 }
1087
a0ee6ade 1088 SCReturnInt(0);
4537f889
VJ
1089}
1090
ef053679
VJ
1091/**
1092 * \brief setup multipart parsing: extract boundary and store it
1093 *
1094 * \param d HTTP transaction
1095 * \param htud transaction userdata
1096 *
3702a33a
VJ
1097 * \retval 1 ok, multipart set up
1098 * \retval 0 ok, not multipart though
ef053679
VJ
1099 * \retval -1 error: problem with the boundary
1100 *
1101 * If the request contains a multipart message, this function will
1102 * set the HTP_BOUNDARY_SET in the transaction.
1103 */
8f1d7503
KS
1104static int HtpRequestBodySetupMultipart(htp_tx_data_t *d, HtpTxUserData *htud)
1105{
48cf0585 1106 htp_header_t *h = (htp_header_t *)htp_table_get_c(d->tx->request_headers,
21acd72a
VJ
1107 "Content-Type");
1108 if (h != NULL && bstr_len(h->value) > 0) {
1109 uint8_t *boundary = NULL;
1110 size_t boundary_len = 0;
1111
1112 int r = HTTPParseContentTypeHeader((uint8_t *)"boundary=", 9,
1113 (uint8_t *) bstr_ptr(h->value), bstr_len(h->value),
1114 &boundary, &boundary_len);
1115 if (r == 1) {
1116#ifdef PRINT
1117 printf("BOUNDARY START: \n");
1118 PrintRawDataFp(stdout, boundary, boundary_len);
1119 printf("BOUNDARY END: \n");
1120#endif
1121 if (boundary_len < HTP_BOUNDARY_MAX) {
ced01da8 1122 htud->boundary = HTPMalloc(boundary_len);
21acd72a
VJ
1123 if (htud->boundary == NULL) {
1124 return -1;
1125 }
1126 htud->boundary_len = (uint8_t)boundary_len;
1127 memcpy(htud->boundary, boundary, boundary_len);
1128
43c7fd75 1129 htud->tsflags |= HTP_BOUNDARY_SET;
21acd72a
VJ
1130 } else {
1131 SCLogDebug("invalid boundary");
1132 return -1;
1133 }
c85674b0 1134 SCReturnInt(1);
21acd72a 1135 }
c85674b0 1136 //SCReturnInt(1);
21acd72a 1137 }
3702a33a 1138 SCReturnInt(0);
21acd72a
VJ
1139}
1140
4537f889
VJ
1141#define C_D_HDR "content-disposition:"
1142#define C_D_HDR_LEN 20
1143#define C_T_HDR "content-type:"
1144#define C_T_HDR_LEN 13
1145
e21d8cdf 1146static void HtpRequestBodyMultipartParseHeader(HtpState *hstate,
3f5acc54 1147 HtpTxUserData *htud,
e21d8cdf 1148 uint8_t *header, uint32_t header_len,
21acd72a
VJ
1149 uint8_t **filename, uint16_t *filename_len,
1150 uint8_t **filetype, uint16_t *filetype_len)
1151{
1152 uint8_t *fn = NULL;
1153 size_t fn_len = 0;
1154 uint8_t *ft = NULL;
1155 size_t ft_len = 0;
1156
1157#ifdef PRINT
1158 printf("HEADER START: \n");
1159 PrintRawDataFp(stdout, header, header_len);
1160 printf("HEADER END: \n");
1161#endif
1162
1163 while (header_len > 0) {
1164 uint8_t *next_line = Bs2bmSearch(header, header_len, (uint8_t *)"\r\n", 2);
1165 uint8_t *line = header;
1166 uint32_t line_len;
1167
1168 if (next_line == NULL) {
1169 line_len = header_len;
1170 } else {
1171 line_len = next_line - header;
1172 }
e21d8cdf
VJ
1173 uint8_t *sc = (uint8_t *)memchr(line, ':', line_len);
1174 if (sc == NULL) {
3f5acc54 1175 HTPSetEvent(hstate, htud,
e21d8cdf 1176 HTTP_DECODER_EVENT_MULTIPART_INVALID_HEADER);
e21d8cdf
VJ
1177 /* if the : we found is the final char, it means we have
1178 * no value */
fcc21ae4 1179 } else if (line_len > 0 && sc == &line[line_len - 1]) {
3f5acc54 1180 HTPSetEvent(hstate, htud,
fcc21ae4
VJ
1181 HTTP_DECODER_EVENT_MULTIPART_INVALID_HEADER);
1182 } else {
21acd72a 1183#ifdef PRINT
fcc21ae4
VJ
1184 printf("LINE START: \n");
1185 PrintRawDataFp(stdout, line, line_len);
1186 printf("LINE END: \n");
21acd72a 1187#endif
fcc21ae4
VJ
1188 if (line_len >= C_D_HDR_LEN &&
1189 SCMemcmpLowercase(C_D_HDR, line, C_D_HDR_LEN) == 0) {
1190 uint8_t *value = line + C_D_HDR_LEN;
1191 uint32_t value_len = line_len - C_D_HDR_LEN;
1192
1193 /* parse content-disposition */
1194 (void)HTTPParseContentDispositionHeader((uint8_t *)"filename=", 9,
1195 value, value_len, &fn, &fn_len);
1196 } else if (line_len >= C_T_HDR_LEN &&
1197 SCMemcmpLowercase(C_T_HDR, line, C_T_HDR_LEN) == 0) {
1198 SCLogDebug("content-type line");
1199 uint8_t *value = line + C_T_HDR_LEN;
1200 uint32_t value_len = line_len - C_T_HDR_LEN;
1201
1202 (void)HTTPParseContentTypeHeader(NULL, 0,
1203 value, value_len, &ft, &ft_len);
1204 }
21acd72a
VJ
1205 }
1206
1207 if (next_line == NULL) {
1208 SCLogDebug("no next_line");
1209 break;
1210 }
21acd72a
VJ
1211 header_len -= ((next_line + 2) - header);
1212 header = next_line + 2;
1213 } /* while (header_len > 0) */
1214
1215 if (fn_len > USHRT_MAX)
1216 fn_len = USHRT_MAX;
1217 if (ft_len > USHRT_MAX)
1218 ft_len = USHRT_MAX;
1219
1220 *filename = fn;
1221 *filename_len = fn_len;
1222 *filetype = ft;
1223 *filetype_len = ft_len;
1224}
1225
ef053679
VJ
1226/**
1227 * \brief Create a single buffer from the HtpBodyChunks in our list
1228 *
1229 * \param htud transaction user data
1230 * \param chunks_buffers pointer to pass back the buffer to the caller
1231 * \param chunks_buffer_len pointer to pass back the buffer length to the caller
1232 */
66a3cd96 1233static void HtpRequestBodyReassemble(HtpTxUserData *htud,
46e55f1e 1234 const uint8_t **chunks_buffer, uint32_t *chunks_buffer_len)
21acd72a 1235{
46e55f1e
VJ
1236 StreamingBufferGetDataAtOffset(htud->request_body.sb,
1237 chunks_buffer, chunks_buffer_len,
1238 htud->request_body.body_parsed);
21acd72a
VJ
1239}
1240
83e0529b
VJ
1241static void FlagDetectStateNewFile(HtpTxUserData *tx, int dir)
1242{
1df00749 1243 SCEnter();
83e0529b
VJ
1244 if (tx && tx->de_state) {
1245 if (dir == STREAM_TOSERVER) {
1df00749
VJ
1246 SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW set");
1247 tx->de_state->dir_state[0].flags |= DETECT_ENGINE_STATE_FLAG_FILE_NEW;
83e0529b 1248 } else if (STREAM_TOCLIENT) {
1df00749
VJ
1249 SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW set");
1250 tx->de_state->dir_state[1].flags |= DETECT_ENGINE_STATE_FLAG_FILE_NEW;
83e0529b
VJ
1251 }
1252 }
1253}
1254
444c4b54
VJ
1255/**
1256 * \brief Setup boundary buffers
1257 */
1258static void HtpRequestBodySetupBoundary(HtpTxUserData *htud,
1259 uint8_t *boundary, uint32_t boundary_len)
1260{
1261 memset(boundary, '-', boundary_len);
1262 memcpy(boundary + 2, htud->boundary, htud->boundary_len);
1263}
1264
ab1200fb 1265static int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, void *tx,
46e55f1e 1266 const uint8_t *chunks_buffer, uint32_t chunks_buffer_len)
403b2788 1267{
23e01d23 1268 int result = 0;
444c4b54
VJ
1269 uint8_t boundary[htud->boundary_len + 4]; /**< size limited to HTP_BOUNDARY_MAX + 4 */
1270 uint8_t expected_boundary_len = htud->boundary_len + 2;
1271 uint8_t expected_boundary_end_len = htud->boundary_len + 4;
94e25276 1272 int tx_progress = 0;
23e01d23 1273
403b2788
VJ
1274#ifdef PRINT
1275 printf("CHUNK START: \n");
1276 PrintRawDataFp(stdout, chunks_buffer, chunks_buffer_len);
1277 printf("CHUNK END: \n");
1278#endif
1279
444c4b54 1280 HtpRequestBodySetupBoundary(htud, boundary, htud->boundary_len + 4);
403b2788
VJ
1281
1282 /* search for the header start, header end and form end */
1283 uint8_t *header_start = Bs2bmSearch(chunks_buffer, chunks_buffer_len,
444c4b54 1284 boundary, expected_boundary_len);
403b2788
VJ
1285 uint8_t *header_end = NULL;
1286 if (header_start != NULL) {
1287 header_end = Bs2bmSearch(header_start, chunks_buffer_len - (header_start - chunks_buffer),
1288 (uint8_t *)"\r\n\r\n", 4);
1289 }
1290 uint8_t *form_end = Bs2bmSearch(chunks_buffer, chunks_buffer_len,
444c4b54 1291 boundary, expected_boundary_end_len);
403b2788 1292
fcc21ae4
VJ
1293 SCLogDebug("header_start %p, header_end %p, form_end %p", header_start,
1294 header_end, form_end);
1295
94e25276
AS
1296 /* we currently only handle multipart for ts. When we support it for tc,
1297 * we will need to supply right direction */
429c6388 1298 tx_progress = AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER);
403b2788 1299 /* if we're in the file storage process, deal with that now */
43c7fd75 1300 if (htud->tsflags & HTP_FILENAME_SET) {
94e25276 1301 if (header_start != NULL || form_end != NULL || (tx_progress > HTP_REQUEST_BODY)) {
403b2788
VJ
1302 SCLogDebug("reached the end of the file");
1303
46e55f1e 1304 const uint8_t *filedata = chunks_buffer;
403b2788
VJ
1305 uint32_t filedata_len = 0;
1306 uint8_t flags = 0;
1307
1308 if (header_start < form_end || (header_start != NULL && form_end == NULL)) {
1309 filedata_len = header_start - filedata - 2; /* 0d 0a */
1310 } else if (form_end != NULL && form_end < header_start) {
1311 filedata_len = form_end - filedata;
1312 } else if (form_end != NULL && form_end == header_start) {
1313 filedata_len = form_end - filedata - 2; /* 0d 0a */
94e25276 1314 } else if (tx_progress > HTP_RESPONSE_BODY) {
403b2788 1315 filedata_len = chunks_buffer_len;
e1022ee5 1316 flags = FILE_TRUNCATED;
403b2788
VJ
1317 }
1318
e21d8cdf 1319 if (filedata_len > chunks_buffer_len) {
3f5acc54 1320 HTPSetEvent(hstate, htud,
e21d8cdf
VJ
1321 HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR);
1322 goto end;
1323 }
403b2788
VJ
1324#ifdef PRINT
1325 printf("FILEDATA (final chunk) START: \n");
1326 PrintRawDataFp(stdout, filedata, filedata_len);
1327 printf("FILEDATA (final chunk) END: \n");
1328#endif
43c7fd75 1329 if (!(htud->tsflags & HTP_DONTSTORE)) {
d59ca75e
VJ
1330 if (HTPFileClose(hstate, filedata, filedata_len, flags,
1331 STREAM_TOSERVER) == -1)
23e01d23
VJ
1332 {
1333 goto end;
1334 }
403b2788
VJ
1335 }
1336
43c7fd75 1337 htud->tsflags &=~ HTP_FILENAME_SET;
403b2788
VJ
1338
1339 /* fall through */
1340 } else {
1341 SCLogDebug("not yet at the end of the file");
1342
1343 if (chunks_buffer_len > expected_boundary_end_len) {
46e55f1e 1344 const uint8_t *filedata = chunks_buffer;
403b2788
VJ
1345 uint32_t filedata_len = chunks_buffer_len - expected_boundary_len;
1346#ifdef PRINT
1347 printf("FILEDATA (part) START: \n");
1348 PrintRawDataFp(stdout, filedata, filedata_len);
1349 printf("FILEDATA (part) END: \n");
1350#endif
23e01d23 1351
43c7fd75 1352 if (!(htud->tsflags & HTP_DONTSTORE)) {
d59ca75e
VJ
1353 result = HTPFileStoreChunk(hstate, filedata,
1354 filedata_len, STREAM_TOSERVER);
23e01d23
VJ
1355 if (result == -1) {
1356 goto end;
1357 } else if (result == -2) {
1358 /* we know for sure we're not storing the file */
43c7fd75 1359 htud->tsflags |= HTP_DONTSTORE;
23e01d23 1360 }
403b2788
VJ
1361 }
1362
b402d971 1363 htud->request_body.body_parsed += filedata_len;
403b2788
VJ
1364 } else {
1365 SCLogDebug("chunk too small to already process in part");
1366 }
1367
1368 goto end;
1369 }
1370 }
1371
1372 while (header_start != NULL && header_end != NULL &&
1373 header_end != form_end &&
1374 header_start < (chunks_buffer + chunks_buffer_len) &&
1375 header_end < (chunks_buffer + chunks_buffer_len) &&
1376 header_start < header_end)
1377 {
1378 uint8_t *filename = NULL;
1379 uint16_t filename_len = 0;
1380 uint8_t *filetype = NULL;
1381 uint16_t filetype_len = 0;
1382
1383 uint32_t header_len = header_end - header_start;
1384 SCLogDebug("header_len %u", header_len);
33848124 1385 uint8_t *header = header_start;
403b2788 1386
18837dce
VJ
1387 /* skip empty records */
1388 if (expected_boundary_len == header_len) {
1389 goto next;
1390 } else if ((uint32_t)(expected_boundary_len + 2) <= header_len) {
33848124
VJ
1391 header_len -= (expected_boundary_len + 2);
1392 header = header_start + (expected_boundary_len + 2); // + for 0d 0a
1393 }
403b2788 1394
3f5acc54 1395 HtpRequestBodyMultipartParseHeader(hstate, htud, header, header_len,
e21d8cdf 1396 &filename, &filename_len, &filetype, &filetype_len);
403b2788
VJ
1397
1398 if (filename != NULL) {
1399 uint8_t *filedata = NULL;
1400 uint32_t filedata_len = 0;
1401
1402 SCLogDebug("we have a filename");
1403
43c7fd75
VJ
1404 htud->tsflags |= HTP_FILENAME_SET;
1405 htud->tsflags &= ~HTP_DONTSTORE;
403b2788
VJ
1406
1407 SCLogDebug("header_end %p", header_end);
1408 SCLogDebug("form_end %p", form_end);
1409
1410 /* everything until the final boundary is the file */
1411 if (form_end != NULL) {
1412 filedata = header_end + 4;
e21d8cdf 1413 if (form_end == filedata) {
3f5acc54 1414 HTPSetEvent(hstate, htud,
e21d8cdf
VJ
1415 HTTP_DECODER_EVENT_MULTIPART_NO_FILEDATA);
1416 goto end;
1417 } else if (form_end < filedata) {
3f5acc54 1418 HTPSetEvent(hstate, htud,
e21d8cdf
VJ
1419 HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR);
1420 goto end;
1421 }
1422
403b2788 1423 filedata_len = form_end - (header_end + 4 + 2);
e21d8cdf 1424 SCLogDebug("filedata_len %"PRIuMAX, (uintmax_t)filedata_len);
403b2788
VJ
1425
1426 /* or is it? */
1427 uint8_t *header_next = Bs2bmSearch(filedata, filedata_len,
444c4b54 1428 boundary, expected_boundary_len);
403b2788
VJ
1429 if (header_next != NULL) {
1430 filedata_len -= (form_end - header_next);
1431 }
1432
e21d8cdf 1433 if (filedata_len > chunks_buffer_len) {
3f5acc54 1434 HTPSetEvent(hstate, htud,
e21d8cdf
VJ
1435 HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR);
1436 goto end;
1437 }
403b2788 1438 SCLogDebug("filedata_len %"PRIuMAX, (uintmax_t)filedata_len);
403b2788
VJ
1439#ifdef PRINT
1440 printf("FILEDATA START: \n");
1441 PrintRawDataFp(stdout, filedata, filedata_len);
1442 printf("FILEDATA END: \n");
1443#endif
1444
e1022ee5 1445 result = HTPFileOpen(hstate, filename, filename_len,
d59ca75e
VJ
1446 filedata, filedata_len, hstate->transaction_cnt,
1447 STREAM_TOSERVER);
23e01d23 1448 if (result == -1) {
403b2788 1449 goto end;
23e01d23 1450 } else if (result == -2) {
43c7fd75 1451 htud->tsflags |= HTP_DONTSTORE;
23e01d23 1452 } else {
d59ca75e 1453 if (HTPFileClose(hstate, NULL, 0, 0, STREAM_TOSERVER) == -1) {
23e01d23
VJ
1454 goto end;
1455 }
403b2788 1456 }
83e0529b 1457 FlagDetectStateNewFile(htud, STREAM_TOSERVER);
a6e75aff
VJ
1458
1459 htud->request_body.body_parsed += (header_end - chunks_buffer);
43c7fd75 1460 htud->tsflags &= ~HTP_FILENAME_SET;
403b2788 1461 } else {
a6e75aff
VJ
1462 SCLogDebug("chunk doesn't contain form end");
1463
1464 filedata = header_end + 4;
1465 filedata_len = chunks_buffer_len - (filedata - chunks_buffer);
1466 SCLogDebug("filedata_len %u (chunks_buffer_len %u)", filedata_len, chunks_buffer_len);
1467
e21d8cdf 1468 if (filedata_len > chunks_buffer_len) {
3f5acc54 1469 HTPSetEvent(hstate, htud,
e21d8cdf
VJ
1470 HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR);
1471 goto end;
1472 }
1473
a6e75aff
VJ
1474#ifdef PRINT
1475 printf("FILEDATA START: \n");
1476 PrintRawDataFp(stdout, filedata, filedata_len);
1477 printf("FILEDATA END: \n");
1478#endif
1479 /* form doesn't end in this chunk, but part might. Lets
1480 * see if have another coming up */
1481 uint8_t *header_next = Bs2bmSearch(filedata, filedata_len,
444c4b54 1482 boundary, expected_boundary_len);
a6e75aff
VJ
1483 SCLogDebug("header_next %p", header_next);
1484 if (header_next == NULL) {
1485 /* no, but we'll handle the file data when we see the
1486 * form_end */
403b2788 1487
a6e75aff 1488 SCLogDebug("more file data to come");
403b2788 1489
a6e75aff
VJ
1490 uint32_t offset = (header_end + 4) - chunks_buffer;
1491 SCLogDebug("offset %u", offset);
1492 htud->request_body.body_parsed += offset;
1c934acc 1493
a6e75aff
VJ
1494 result = HTPFileOpen(hstate, filename, filename_len,
1495 NULL, 0, hstate->transaction_cnt,
1496 STREAM_TOSERVER);
1497 if (result == -1) {
1498 goto end;
1499 } else if (result == -2) {
43c7fd75 1500 htud->tsflags |= HTP_DONTSTORE;
a6e75aff 1501 }
83e0529b
VJ
1502 FlagDetectStateNewFile(htud, STREAM_TOSERVER);
1503
fcc21ae4 1504 } else if (header_next - filedata > 2) {
a6e75aff
VJ
1505 filedata_len = header_next - filedata - 2;
1506 SCLogDebug("filedata_len %u", filedata_len);
1507
1508 result = HTPFileOpen(hstate, filename, filename_len,
d59ca75e
VJ
1509 filedata, filedata_len, hstate->transaction_cnt,
1510 STREAM_TOSERVER);
a6e75aff
VJ
1511 if (result == -1) {
1512 goto end;
1513 } else if (result == -2) {
43c7fd75 1514 htud->tsflags |= HTP_DONTSTORE;
a6e75aff
VJ
1515 } else {
1516 if (HTPFileClose(hstate, NULL, 0, 0, STREAM_TOSERVER) == -1) {
1517 goto end;
1518 }
1519 }
83e0529b 1520 FlagDetectStateNewFile(htud, STREAM_TOSERVER);
a6e75aff 1521
43c7fd75 1522 htud->tsflags &= ~HTP_FILENAME_SET;
a6e75aff 1523 htud->request_body.body_parsed += (header_end - chunks_buffer);
403b2788
VJ
1524 }
1525 }
403b2788 1526 }
18837dce 1527next:
403b2788
VJ
1528 SCLogDebug("header_start %p, header_end %p, form_end %p",
1529 header_start, header_end, form_end);
1530
1531 /* Search next boundary entry after the start of body */
1532 uint32_t cursizeread = header_end - chunks_buffer;
1533 header_start = Bs2bmSearch(header_end + 4,
1534 chunks_buffer_len - (cursizeread + 4),
444c4b54 1535 boundary, expected_boundary_len);
403b2788
VJ
1536 if (header_start != NULL) {
1537 header_end = Bs2bmSearch(header_end + 4,
1538 chunks_buffer_len - (cursizeread + 4),
1539 (uint8_t *) "\r\n\r\n", 4);
1540 }
1541 }
0a22ba7e
VJ
1542
1543 /* if we're parsing the multipart and we're not currently processing a
1544 * file, we move the body pointer forward. */
1545 if (form_end == NULL && !(htud->tsflags & HTP_FILENAME_SET) && header_start == NULL) {
1546 if (chunks_buffer_len > expected_boundary_end_len) {
1547 uint32_t move = chunks_buffer_len - expected_boundary_end_len + 1;
1548
1549 htud->request_body.body_parsed += move;
1550 SCLogDebug("form not ready, file not set, parsing non-file "
1551 "record: moved %u", move);
1552 }
1553 }
1554
403b2788 1555end:
a6e75aff 1556 SCLogDebug("htud->request_body.body_parsed %"PRIu64, htud->request_body.body_parsed);
403b2788
VJ
1557 return 0;
1558}
1559
1560/** \brief setup things for put request
1561 * \todo really needed? */
ab1200fb 1562static int HtpRequestBodySetupPUT(htp_tx_data_t *d, HtpTxUserData *htud)
8f1d7503 1563{
403b2788
VJ
1564// if (d->tx->parsed_uri == NULL || d->tx->parsed_uri->path == NULL) {
1565// return -1;
1566// }
1567
1568 /* filename is d->tx->parsed_uri->path */
1569
1570 return 0;
1571}
1572
3702a33a
VJ
1573/** \internal
1574 * \brief Handle POST, no multipart body data
1575 */
1576static int HtpRequestBodyHandlePOST(HtpState *hstate, HtpTxUserData *htud,
1577 htp_tx_t *tx, uint8_t *data, uint32_t data_len)
1578{
1579 int result = 0;
1580
1581 /* see if we need to open the file */
43c7fd75 1582 if (!(htud->tsflags & HTP_FILENAME_SET))
3702a33a
VJ
1583 {
1584 uint8_t *filename = NULL;
fe9258f0 1585 size_t filename_len = 0;
3702a33a
VJ
1586
1587 /* get the name */
1588 if (tx->parsed_uri != NULL && tx->parsed_uri->path != NULL) {
1589 filename = (uint8_t *)bstr_ptr(tx->parsed_uri->path);
1590 filename_len = bstr_len(tx->parsed_uri->path);
1591 }
1592
e3935a2a 1593 if (filename != NULL) {
fe9258f0 1594 result = HTPFileOpen(hstate, filename, (uint32_t)filename_len, data, data_len,
e3935a2a
VJ
1595 hstate->transaction_cnt, STREAM_TOSERVER);
1596 if (result == -1) {
1597 goto end;
1598 } else if (result == -2) {
43c7fd75 1599 htud->tsflags |= HTP_DONTSTORE;
e3935a2a 1600 } else {
83e0529b 1601 FlagDetectStateNewFile(htud, STREAM_TOSERVER);
43c7fd75
VJ
1602 htud->tsflags |= HTP_FILENAME_SET;
1603 htud->tsflags &= ~HTP_DONTSTORE;
e3935a2a 1604 }
3702a33a
VJ
1605 }
1606 }
1607 else
1608 {
1609 /* otherwise, just store the data */
1610
43c7fd75 1611 if (!(htud->tsflags & HTP_DONTSTORE)) {
3702a33a
VJ
1612 result = HTPFileStoreChunk(hstate, data, data_len, STREAM_TOSERVER);
1613 if (result == -1) {
1614 goto end;
1615 } else if (result == -2) {
1616 /* we know for sure we're not storing the file */
43c7fd75 1617 htud->tsflags |= HTP_DONTSTORE;
3702a33a
VJ
1618 }
1619 }
1620 }
1621
1622 return 0;
1623end:
1624 return -1;
1625}
1626
1627/** \internal
1628 * \brief Handle PUT body data
1629 */
1630static int HtpRequestBodyHandlePUT(HtpState *hstate, HtpTxUserData *htud,
403b2788
VJ
1631 htp_tx_t *tx, uint8_t *data, uint32_t data_len)
1632{
23e01d23
VJ
1633 int result = 0;
1634
403b2788 1635 /* see if we need to open the file */
43c7fd75 1636 if (!(htud->tsflags & HTP_FILENAME_SET))
403b2788
VJ
1637 {
1638 uint8_t *filename = NULL;
fe9258f0 1639 size_t filename_len = 0;
403b2788
VJ
1640
1641 /* get the name */
1642 if (tx->parsed_uri != NULL && tx->parsed_uri->path != NULL) {
1643 filename = (uint8_t *)bstr_ptr(tx->parsed_uri->path);
1644 filename_len = bstr_len(tx->parsed_uri->path);
1645 }
1646
e3935a2a 1647 if (filename != NULL) {
fe9258f0 1648 result = HTPFileOpen(hstate, filename, (uint32_t)filename_len, data, data_len,
e3935a2a
VJ
1649 hstate->transaction_cnt, STREAM_TOSERVER);
1650 if (result == -1) {
1651 goto end;
1652 } else if (result == -2) {
43c7fd75 1653 htud->tsflags |= HTP_DONTSTORE;
e3935a2a 1654 } else {
83e0529b 1655 FlagDetectStateNewFile(htud, STREAM_TOSERVER);
43c7fd75
VJ
1656 htud->tsflags |= HTP_FILENAME_SET;
1657 htud->tsflags &= ~HTP_DONTSTORE;
e3935a2a 1658 }
b402d971
VJ
1659 }
1660 }
1661 else
1662 {
1663 /* otherwise, just store the data */
1664
43c7fd75 1665 if (!(htud->tsflags & HTP_DONTSTORE)) {
d59ca75e 1666 result = HTPFileStoreChunk(hstate, data, data_len, STREAM_TOSERVER);
b402d971
VJ
1667 if (result == -1) {
1668 goto end;
1669 } else if (result == -2) {
1670 /* we know for sure we're not storing the file */
43c7fd75 1671 htud->tsflags |= HTP_DONTSTORE;
b402d971
VJ
1672 }
1673 }
1674 }
1675
1676 return 0;
1677end:
1678 return -1;
1679}
1680
ab1200fb 1681static int HtpResponseBodyHandle(HtpState *hstate, HtpTxUserData *htud,
b402d971
VJ
1682 htp_tx_t *tx, uint8_t *data, uint32_t data_len)
1683{
1684 SCEnter();
1685
1686 int result = 0;
1687
9665ab04
PA
1688 /* see if we need to open the file
1689 * we check for tx->response_line in case of junk
1690 * interpreted as body before response line
1691 */
1692 if (!(htud->tcflags & HTP_FILENAME_SET) &&
1693 (tx->response_line != NULL || tx->is_protocol_0_9))
b402d971
VJ
1694 {
1695 SCLogDebug("setting up file name");
1696
1697 uint8_t *filename = NULL;
fe9258f0 1698 size_t filename_len = 0;
b402d971 1699
64827e38 1700 /* try Content-Disposition header first */
48cf0585 1701 htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->response_headers,
64827e38
VJ
1702 "Content-Disposition");
1703 if (h != NULL && bstr_len(h->value) > 0) {
1704 /* parse content-disposition */
1705 (void)HTTPParseContentDispositionHeader((uint8_t *)"filename=", 9,
fe9258f0 1706 (uint8_t *) bstr_ptr(h->value), bstr_len(h->value), &filename, &filename_len);
64827e38
VJ
1707 }
1708
1709 /* fall back to name from the uri */
1710 if (filename == NULL) {
1711 /* get the name */
1712 if (tx->parsed_uri != NULL && tx->parsed_uri->path != NULL) {
1713 filename = (uint8_t *)bstr_ptr(tx->parsed_uri->path);
1714 filename_len = bstr_len(tx->parsed_uri->path);
1715 }
b402d971
VJ
1716 }
1717
e3935a2a 1718 if (filename != NULL) {
fe9258f0 1719 result = HTPFileOpen(hstate, filename, (uint32_t)filename_len,
d59ca75e 1720 data, data_len, hstate->transaction_cnt, STREAM_TOCLIENT);
e3935a2a
VJ
1721 SCLogDebug("result %d", result);
1722 if (result == -1) {
1723 goto end;
1724 } else if (result == -2) {
43c7fd75 1725 htud->tcflags |= HTP_DONTSTORE;
e3935a2a 1726 } else {
83e0529b 1727 FlagDetectStateNewFile(htud, STREAM_TOCLIENT);
43c7fd75
VJ
1728 htud->tcflags |= HTP_FILENAME_SET;
1729 htud->tcflags &= ~HTP_DONTSTORE;
e3935a2a 1730 }
bef190f7
PA
1731 //set range if present
1732 htp_header_t *h_content_range = htp_table_get_c(tx->response_headers, "content-range");
1733 if (h_content_range != NULL) {
1734 HTPFileSetRange(hstate, h_content_range->value);
1735 }
403b2788 1736 }
403b2788 1737 }
9665ab04 1738 else if (tx->response_line != NULL || tx->is_protocol_0_9)
403b2788
VJ
1739 {
1740 /* otherwise, just store the data */
1741
43c7fd75 1742 if (!(htud->tcflags & HTP_DONTSTORE)) {
d59ca75e 1743 result = HTPFileStoreChunk(hstate, data, data_len, STREAM_TOCLIENT);
b402d971 1744 SCLogDebug("result %d", result);
23e01d23
VJ
1745 if (result == -1) {
1746 goto end;
1747 } else if (result == -2) {
1748 /* we know for sure we're not storing the file */
43c7fd75 1749 htud->tcflags |= HTP_DONTSTORE;
23e01d23 1750 }
403b2788
VJ
1751 }
1752 }
1753
0bbc818b 1754 htud->response_body.body_parsed += data_len;
403b2788
VJ
1755 return 0;
1756end:
1757 return -1;
1758}
1759
0165b3f0 1760/**
a9cdd2bb 1761 * \brief Function callback to append chunks for Requests
0165b3f0 1762 * \param d pointer to the htp_tx_data_t structure (a chunk from htp lib)
48cf0585 1763 * \retval int HTP_OK if all goes well
0165b3f0 1764 */
ab1200fb 1765static int HTPCallbackRequestBodyData(htp_tx_data_t *d)
0165b3f0
PR
1766{
1767 SCEnter();
6d60b3a7 1768
92679442 1769 if (!(SC_ATOMIC_GET(htp_config_flags) & HTP_REQUIRE_REQUEST_BODY))
48cf0585
AS
1770 SCReturnInt(HTP_OK);
1771
1772 if (d->data == NULL || d->len == 0)
1773 SCReturnInt(HTP_OK);
66a083da 1774
a6e75aff
VJ
1775#ifdef PRINT
1776 printf("HTPBODY START: \n");
1777 PrintRawDataFp(stdout, (uint8_t *)d->data, d->len);
1778 printf("HTPBODY END: \n");
1779#endif
1780
48cf0585 1781 HtpState *hstate = htp_connp_get_user_data(d->tx->connp);
4537f889 1782 if (hstate == NULL) {
48cf0585 1783 SCReturnInt(HTP_ERROR);
4537f889
VJ
1784 }
1785
23e01d23 1786 SCLogDebug("New request body data available at %p -> %p -> %p, bodylen "
0165b3f0
PR
1787 "%"PRIu32"", hstate, d, d->data, (uint32_t)d->len);
1788
48cf0585
AS
1789 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(d->tx);
1790 if (tx_ud == NULL) {
ced01da8 1791 tx_ud = HTPMalloc(sizeof(HtpTxUserData));
48cf0585
AS
1792 if (unlikely(tx_ud == NULL)) {
1793 SCReturnInt(HTP_OK);
06a65cb4 1794 }
48cf0585 1795 memset(tx_ud, 0, sizeof(HtpTxUserData));
0165b3f0 1796
48cf0585
AS
1797 /* Set the user data for handling body chunks on this transaction */
1798 htp_tx_set_user_data(d->tx, tx_ud);
1799 }
1800 if (!tx_ud->response_body_init) {
1801 tx_ud->response_body_init = 1;
48cf0585
AS
1802
1803 if (d->tx->request_method_number == HTP_M_POST) {
3702a33a 1804 SCLogDebug("POST");
48cf0585 1805 int r = HtpRequestBodySetupMultipart(d, tx_ud);
3702a33a 1806 if (r == 1) {
48cf0585 1807 tx_ud->request_body_type = HTP_BODY_REQUEST_MULTIPART;
3702a33a 1808 } else if (r == 0) {
48cf0585 1809 tx_ud->request_body_type = HTP_BODY_REQUEST_POST;
3702a33a 1810 SCLogDebug("not multipart");
403b2788 1811 }
48cf0585
AS
1812 } else if (d->tx->request_method_number == HTP_M_PUT) {
1813 if (HtpRequestBodySetupPUT(d, tx_ud) == 0) {
1814 tx_ud->request_body_type = HTP_BODY_REQUEST_PUT;
403b2788
VJ
1815 }
1816 }
0165b3f0 1817 }
0165b3f0 1818
efdd9e08
VJ
1819 /* see if we can get rid of htp body chunks */
1820 HtpBodyPrune(hstate, &tx_ud->request_body, STREAM_TOSERVER);
1821
48cf0585 1822 SCLogDebug("tx_ud->request_body.content_len_so_far %"PRIu64, tx_ud->request_body.content_len_so_far);
24a2f515 1823 SCLogDebug("hstate->cfg->request.body_limit %u", hstate->cfg->request.body_limit);
6ebe7b7c
VJ
1824
1825 /* within limits, add the body chunk to the state. */
de904db8
GL
1826 if ((!(tx_ud->tsflags & HTP_STREAM_DEPTH_SET) &&
1827 (hstate->cfg->request.body_limit == 0 || tx_ud->request_body.content_len_so_far < hstate->cfg->request.body_limit)) ||
1828 AppLayerHtpCheckStreamDepth(tx_ud->request_body.content_len_so_far, tx_ud->tsflags))
6ebe7b7c 1829 {
de904db8
GL
1830 uint32_t stream_depth = FileReassemblyDepth();
1831 uint32_t len = AppLayerHtpComputeChunkLength(tx_ud->request_body.content_len_so_far,
1832 hstate->cfg->request.body_limit,
1833 stream_depth,
1834 tx_ud->tsflags,
1835 (uint32_t)d->len);
1836 BUG_ON(len > (uint32_t)d->len);
6ebe7b7c 1837
6fb808fc 1838 HtpBodyAppendChunk(&hstate->cfg->request, &tx_ud->request_body, d->data, len);
6ebe7b7c 1839
46e55f1e 1840 const uint8_t *chunks_buffer = NULL;
403b2788 1841 uint32_t chunks_buffer_len = 0;
a0ee6ade 1842
48cf0585 1843 if (tx_ud->request_body_type == HTP_BODY_REQUEST_MULTIPART) {
403b2788 1844 /* multi-part body handling starts here */
48cf0585 1845 if (!(tx_ud->tsflags & HTP_BOUNDARY_SET)) {
a0ee6ade
VJ
1846 goto end;
1847 }
4723f072 1848
48cf0585 1849 HtpRequestBodyReassemble(tx_ud, &chunks_buffer, &chunks_buffer_len);
403b2788
VJ
1850 if (chunks_buffer == NULL) {
1851 goto end;
6d60b3a7 1852 }
a6e75aff 1853#ifdef PRINT
3702a33a
VJ
1854 printf("REASSCHUNK START: \n");
1855 PrintRawDataFp(stdout, chunks_buffer, chunks_buffer_len);
1856 printf("REASSCHUNK END: \n");
a6e75aff 1857#endif
a0ee6ade 1858
94e25276 1859 HtpRequestBodyHandleMultipart(hstate, tx_ud, d->tx, chunks_buffer, chunks_buffer_len);
a0ee6ade 1860
48cf0585
AS
1861 } else if (tx_ud->request_body_type == HTP_BODY_REQUEST_POST) {
1862 HtpRequestBodyHandlePOST(hstate, tx_ud, d->tx, (uint8_t *)d->data, (uint32_t)d->len);
1863 } else if (tx_ud->request_body_type == HTP_BODY_REQUEST_PUT) {
1864 HtpRequestBodyHandlePUT(hstate, tx_ud, d->tx, (uint8_t *)d->data, (uint32_t)d->len);
6d60b3a7
PR
1865 }
1866
fc380139
GL
1867 } else {
1868 if (tx_ud->tsflags & HTP_FILENAME_SET) {
1869 SCLogDebug("closing file that was being stored");
1870 (void)HTPFileClose(hstate, NULL, 0, FILE_TRUNCATED, STREAM_TOSERVER);
1871 tx_ud->tsflags &= ~HTP_FILENAME_SET;
1872 }
a0ee6ade
VJ
1873 }
1874
6d60b3a7 1875end:
e02b74de
VJ
1876 if (hstate->conn != NULL) {
1877 SCLogDebug("checking body size %"PRIu64" against inspect limit %u (cur %"PRIu64", last %"PRIu64")",
1878 tx_ud->request_body.content_len_so_far,
1879 hstate->cfg->request.inspect_min_size,
1880 (uint64_t)hstate->conn->in_data_counter, hstate->last_request_data_stamp);
1881
1882 /* if we reach the inspect_min_size we'll trigger inspection,
1883 * so make sure that raw stream is also inspected. Set the
13ea30ef 1884 * data to be used to the amount of raw bytes we've seen to
e02b74de
VJ
1885 * get here. */
1886 if (tx_ud->request_body.body_inspected == 0 &&
1887 tx_ud->request_body.content_len_so_far >= hstate->cfg->request.inspect_min_size) {
1888 if ((uint64_t)hstate->conn->in_data_counter > hstate->last_request_data_stamp &&
1889 (uint64_t)hstate->conn->in_data_counter - hstate->last_request_data_stamp < (uint64_t)UINT_MAX)
1890 {
1891 uint32_t x = (uint32_t)((uint64_t)hstate->conn->in_data_counter - hstate->last_request_data_stamp);
1892
1893 /* body still in progress, but due to min inspect size we need to inspect now */
1894 StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOSERVER, x);
1895 AppLayerParserTriggerRawStreamReassembly(hstate->f, STREAM_TOSERVER);
1896 }
1897 /* after the start of the body, disable the depth logic */
1898 } else if (tx_ud->request_body.body_inspected > 0) {
1899 StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOSERVER, 0);
1900 }
1901 }
48cf0585 1902 SCReturnInt(HTP_OK);
b402d971
VJ
1903}
1904
1905/**
1906 * \brief Function callback to append chunks for Responses
1907 * \param d pointer to the htp_tx_data_t structure (a chunk from htp lib)
48cf0585 1908 * \retval int HTP_OK if all goes well
b402d971 1909 */
ab1200fb 1910static int HTPCallbackResponseBodyData(htp_tx_data_t *d)
b402d971
VJ
1911{
1912 SCEnter();
1913
92679442 1914 if (!(SC_ATOMIC_GET(htp_config_flags) & HTP_REQUIRE_RESPONSE_BODY))
48cf0585 1915 SCReturnInt(HTP_OK);
66a083da 1916
48cf0585
AS
1917 if (d->data == NULL || d->len == 0)
1918 SCReturnInt(HTP_OK);
1919
1920 HtpState *hstate = htp_connp_get_user_data(d->tx->connp);
b402d971 1921 if (hstate == NULL) {
48cf0585 1922 SCReturnInt(HTP_ERROR);
b402d971
VJ
1923 }
1924
1925 SCLogDebug("New response body data available at %p -> %p -> %p, bodylen "
1926 "%"PRIu32"", hstate, d, d->data, (uint32_t)d->len);
1927
48cf0585
AS
1928 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(d->tx);
1929 if (tx_ud == NULL) {
ced01da8 1930 tx_ud = HTPMalloc(sizeof(HtpTxUserData));
48cf0585
AS
1931 if (unlikely(tx_ud == NULL)) {
1932 SCReturnInt(HTP_OK);
b402d971 1933 }
48cf0585
AS
1934 memset(tx_ud, 0, sizeof(HtpTxUserData));
1935
1936 /* Set the user data for handling body chunks on this transaction */
1937 htp_tx_set_user_data(d->tx, tx_ud);
1938 }
1939 if (!tx_ud->request_body_init) {
1940 tx_ud->request_body_init = 1;
b402d971
VJ
1941 }
1942
efdd9e08
VJ
1943 /* see if we can get rid of htp body chunks */
1944 HtpBodyPrune(hstate, &tx_ud->response_body, STREAM_TOCLIENT);
1945
48cf0585 1946 SCLogDebug("tx_ud->response_body.content_len_so_far %"PRIu64, tx_ud->response_body.content_len_so_far);
24a2f515 1947 SCLogDebug("hstate->cfg->response.body_limit %u", hstate->cfg->response.body_limit);
b402d971
VJ
1948
1949 /* within limits, add the body chunk to the state. */
de904db8
GL
1950 if ((!(tx_ud->tcflags & HTP_STREAM_DEPTH_SET) &&
1951 (hstate->cfg->response.body_limit == 0 || tx_ud->response_body.content_len_so_far < hstate->cfg->response.body_limit)) ||
1952 AppLayerHtpCheckStreamDepth(tx_ud->response_body.content_len_so_far, tx_ud->tcflags))
b402d971 1953 {
de904db8
GL
1954 uint32_t stream_depth = FileReassemblyDepth();
1955 uint32_t len = AppLayerHtpComputeChunkLength(tx_ud->response_body.content_len_so_far,
1956 hstate->cfg->response.body_limit,
1957 stream_depth,
1958 tx_ud->tcflags,
1959 (uint32_t)d->len);
1960 BUG_ON(len > (uint32_t)d->len);
b402d971 1961
6fb808fc 1962 HtpBodyAppendChunk(&hstate->cfg->response, &tx_ud->response_body, d->data, len);
b402d971 1963
48cf0585 1964 HtpResponseBodyHandle(hstate, tx_ud, d->tx, (uint8_t *)d->data, (uint32_t)d->len);
7a29aa11
GL
1965 } else {
1966 if (tx_ud->tcflags & HTP_FILENAME_SET) {
1967 SCLogDebug("closing file that was being stored");
1968 (void)HTPFileClose(hstate, NULL, 0, FILE_TRUNCATED, STREAM_TOCLIENT);
1969 tx_ud->tcflags &= ~HTP_FILENAME_SET;
1970 }
b402d971
VJ
1971 }
1972
e02b74de
VJ
1973 if (hstate->conn != NULL) {
1974 SCLogDebug("checking body size %"PRIu64" against inspect limit %u (cur %"PRIu64", last %"PRIu64")",
1975 tx_ud->response_body.content_len_so_far,
1976 hstate->cfg->response.inspect_min_size,
1977 (uint64_t)hstate->conn->in_data_counter, hstate->last_response_data_stamp);
1978 /* if we reach the inspect_min_size we'll trigger inspection,
1979 * so make sure that raw stream is also inspected. Set the
13ea30ef 1980 * data to be used to the amount of raw bytes we've seen to
e02b74de
VJ
1981 * get here. */
1982 if (tx_ud->response_body.body_inspected == 0 &&
1983 tx_ud->response_body.content_len_so_far >= hstate->cfg->response.inspect_min_size) {
1984 if ((uint64_t)hstate->conn->out_data_counter > hstate->last_response_data_stamp &&
1985 (uint64_t)hstate->conn->out_data_counter - hstate->last_response_data_stamp < (uint64_t)UINT_MAX)
1986 {
1987 uint32_t x = (uint32_t)((uint64_t)hstate->conn->out_data_counter - hstate->last_response_data_stamp);
1988
1989 /* body still in progress, but due to min inspect size we need to inspect now */
1990 StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOCLIENT, x);
1991 AppLayerParserTriggerRawStreamReassembly(hstate->f, STREAM_TOCLIENT);
1992 }
1993 /* after the start of the body, disable the depth logic */
1994 } else if (tx_ud->response_body.body_inspected > 0) {
1995 StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOCLIENT, 0);
1996 }
1997 }
48cf0585 1998 SCReturnInt(HTP_OK);
0165b3f0
PR
1999}
2000
fc2f7f29
GS
2001/**
2002 * \brief Print the stats of the HTTP requests
2003 */
2004void HTPAtExitPrintStats(void)
2005{
2006#ifdef DEBUG
a9cdd2bb 2007 SCEnter();
fc2f7f29
GS
2008 SCMutexLock(&htp_state_mem_lock);
2009 SCLogDebug("http_state_memcnt %"PRIu64", http_state_memuse %"PRIu64"",
2010 htp_state_memcnt, htp_state_memuse);
2011 SCMutexUnlock(&htp_state_mem_lock);
a9cdd2bb 2012 SCReturn;
fc2f7f29
GS
2013#endif
2014}
2015
2016/** \brief Clears the HTTP server configuration memory used by HTP library */
2017void HTPFreeConfig(void)
2018{
a9cdd2bb
BR
2019 SCEnter();
2020
429c6388
AS
2021 if (!AppLayerProtoDetectConfProtoDetectionEnabled("tcp", "http") ||
2022 !AppLayerParserConfParserEnabled("tcp", "http"))
2023 {
ddde572f 2024 SCReturn;
429c6388 2025 }
ddde572f 2026
a9cdd2bb
BR
2027 HTPCfgRec *nextrec = cfglist.next;
2028 SCRadixReleaseRadixTree(cfgtree);
7f8d256e 2029 cfgtree = NULL;
a0fa924c 2030 htp_config_destroy(cfglist.cfg);
a9cdd2bb
BR
2031 while (nextrec != NULL) {
2032 HTPCfgRec *htprec = nextrec;
47a47e8a 2033 nextrec = nextrec->next;
a9cdd2bb 2034
a0fa924c 2035 htp_config_destroy(htprec->cfg);
a9cdd2bb 2036 SCFree(htprec);
a9cdd2bb 2037 }
7addc245 2038 HTPDestroyMemcap();
a9cdd2bb 2039 SCReturn;
fc2f7f29
GS
2040}
2041
44022743
VJ
2042static int HTPCallbackRequestHasTrailer(htp_tx_t *tx)
2043{
2044 HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx);
2045 if (htud != NULL) {
2046 htud->request_has_trailers = 1;
2047 }
2048 return HTP_OK;
2049}
2050
2051static int HTPCallbackResponseHasTrailer(htp_tx_t *tx)
2052{
2053 HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx);
2054 if (htud != NULL) {
2055 htud->response_has_trailers = 1;
2056 }
2057 return HTP_OK;
2058}
2059
e02b74de
VJ
2060/**\internal
2061 * \brief called at start of request
2062 * Set min inspect size.
2063 */
2064static int HTPCallbackRequestStart(htp_tx_t *tx)
2065{
2066 HtpState *hstate = htp_connp_get_user_data(tx->connp);
2067 if (hstate == NULL) {
2068 SCReturnInt(HTP_ERROR);
2069 }
2070
2071 if (hstate->cfg)
2072 StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOSERVER,
2073 hstate->cfg->request.inspect_min_size);
2074 SCReturnInt(HTP_OK);
2075}
2076
2077/**\internal
2078 * \brief called at start of response
2079 * Set min inspect size.
2080 */
2081static int HTPCallbackResponseStart(htp_tx_t *tx)
2082{
2083 HtpState *hstate = htp_connp_get_user_data(tx->connp);
2084 if (hstate == NULL) {
2085 SCReturnInt(HTP_ERROR);
2086 }
2087
2088 if (hstate->cfg)
2089 StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOCLIENT,
2090 hstate->cfg->response.inspect_min_size);
2091 SCReturnInt(HTP_OK);
2092}
2093
2094
356a8bf3
GS
2095/**
2096 * \brief callback for request to store the recent incoming request
2097 in to the recent_in_tx for the given htp state
2098 * \param connp pointer to the current connection parser which has the htp
2099 * state in it as user data
2100 */
8f1d7503
KS
2101static int HTPCallbackRequest(htp_tx_t *tx)
2102{
356a8bf3 2103 SCEnter();
187949b9 2104
2b734b8d
VJ
2105 if (tx == NULL) {
2106 SCReturnInt(HTP_ERROR);
2107 }
2108
48cf0585 2109 HtpState *hstate = htp_connp_get_user_data(tx->connp);
187949b9 2110 if (hstate == NULL) {
48cf0585 2111 SCReturnInt(HTP_ERROR);
187949b9 2112 }
70b32f73 2113
d4d18e31
AS
2114 SCLogDebug("transaction_cnt %"PRIu64", list_size %"PRIu64,
2115 hstate->transaction_cnt, HTPStateGetTxCnt(hstate));
70b32f73
VJ
2116
2117 SCLogDebug("HTTP request completed");
2118
2b734b8d 2119 HTPErrorCheckTxRequestFlags(hstate, tx);
43b39d33 2120
2b734b8d
VJ
2121 HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx);
2122 if (htud != NULL) {
2123 if (htud->tsflags & HTP_FILENAME_SET) {
2124 SCLogDebug("closing file that was being stored");
2125 (void)HTPFileClose(hstate, NULL, 0, 0, STREAM_TOSERVER);
2126 htud->tsflags &= ~HTP_FILENAME_SET;
e02b74de
VJ
2127 StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOSERVER,
2128 (uint32_t)hstate->conn->in_data_counter);
403b2788
VJ
2129 }
2130 }
2131
e02b74de 2132 hstate->last_request_data_stamp = (uint64_t)hstate->conn->in_data_counter;
16cfae2f
VJ
2133 /* request done, do raw reassembly now to inspect state and stream
2134 * at the same time. */
2d223b69 2135 AppLayerParserTriggerRawStreamReassembly(hstate->f, STREAM_TOSERVER);
48cf0585 2136 SCReturnInt(HTP_OK);
356a8bf3
GS
2137}
2138
2139/**
2140 * \brief callback for response to remove the recent received requests
2141 from the recent_in_tx for the given htp state
2142 * \param connp pointer to the current connection parser which has the htp
2143 * state in it as user data
2144 */
8f1d7503
KS
2145static int HTPCallbackResponse(htp_tx_t *tx)
2146{
356a8bf3 2147 SCEnter();
187949b9 2148
48cf0585 2149 HtpState *hstate = htp_connp_get_user_data(tx->connp);
187949b9 2150 if (hstate == NULL) {
48cf0585 2151 SCReturnInt(HTP_ERROR);
187949b9 2152 }
356a8bf3 2153
b406af45
AS
2154 /* we have one whole transaction now */
2155 hstate->transaction_cnt++;
2156
76d3cb55
VJ
2157 HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx);
2158 if (htud != NULL) {
2159 if (htud->tcflags & HTP_FILENAME_SET) {
2160 SCLogDebug("closing file that was being stored");
2161 (void)HTPFileClose(hstate, NULL, 0, 0, STREAM_TOCLIENT);
2162 htud->tcflags &= ~HTP_FILENAME_SET;
b402d971
VJ
2163 }
2164 }
2165
16cfae2f
VJ
2166 /* response done, do raw reassembly now to inspect state and stream
2167 * at the same time. */
2d223b69 2168 AppLayerParserTriggerRawStreamReassembly(hstate->f, STREAM_TOCLIENT);
b6c2b705
MK
2169
2170 /* handle HTTP CONNECT */
2171 if (tx->request_method_number == HTP_M_CONNECT) {
2172 /* any 2XX status response implies that the connection will become
2173 a tunnel immediately after this packet (RFC 7230, 3.3.3). */
2174 if ((tx->response_status_number >= 200) &&
2175 (tx->response_status_number < 300) &&
2176 (hstate->transaction_cnt == 1)) {
6f42ae91
VJ
2177 uint16_t dp = 0;
2178 if (tx->request_port_number != -1) {
2179 dp = (uint16_t)tx->request_port_number;
2180 }
2181 // both ALPROTO_HTTP and ALPROTO_TLS are normal options
2182 AppLayerRequestProtocolChange(hstate->f, dp, ALPROTO_UNKNOWN);
b6c2b705
MK
2183 tx->request_progress = HTP_REQUEST_COMPLETE;
2184 tx->response_progress = HTP_RESPONSE_COMPLETE;
2185 }
2186 }
2187
e02b74de 2188 hstate->last_response_data_stamp = (uint64_t)hstate->conn->out_data_counter;
48cf0585 2189 SCReturnInt(HTP_OK);
356a8bf3
GS
2190}
2191
48cf0585
AS
2192static int HTPCallbackRequestLine(htp_tx_t *tx)
2193{
2194 HtpTxUserData *tx_ud;
2195 bstr *request_uri_normalized;
a8b971c7 2196 HtpState *hstate = htp_connp_get_user_data(tx->connp);
feafc838 2197 const HTPCfgRec *cfg = hstate->cfg;
48cf0585 2198
a8b971c7 2199 request_uri_normalized = SCHTPGenerateNormalizedUri(tx, tx->parsed_uri, cfg->uri_include_all);
48cf0585
AS
2200 if (request_uri_normalized == NULL)
2201 return HTP_OK;
2202
0416a842
VJ
2203 tx_ud = htp_tx_get_user_data(tx);
2204 if (likely(tx_ud == NULL)) {
2205 tx_ud = HTPMalloc(sizeof(*tx_ud));
2206 if (unlikely(tx_ud == NULL)) {
2207 bstr_free(request_uri_normalized);
2208 return HTP_OK;
2209 }
2210 memset(tx_ud, 0, sizeof(*tx_ud));
2211 htp_tx_set_user_data(tx, tx_ud);
67c12c61 2212 }
0416a842
VJ
2213 if (unlikely(tx_ud->request_uri_normalized != NULL))
2214 bstr_free(tx_ud->request_uri_normalized);
48cf0585 2215 tx_ud->request_uri_normalized = request_uri_normalized;
48cf0585 2216
afaa10b3 2217 if (tx->flags) {
43b39d33
VJ
2218 HTPErrorCheckTxRequestFlags(hstate, tx);
2219 }
48cf0585
AS
2220 return HTP_OK;
2221}
2222
8a339e73 2223static int HTPCallbackDoubleDecodeUriPart(htp_tx_t *tx, bstr *part)
48cf0585 2224{
8a339e73 2225 if (part == NULL)
48cf0585
AS
2226 return HTP_OK;
2227
2228 uint64_t flags = 0;
8a339e73
PA
2229 size_t prevlen = bstr_len(part);
2230 htp_status_t res = htp_urldecode_inplace(tx->cfg, HTP_DECODER_URLENCODED, part, &flags);
2231 // shorter string means that uri was encoded
2232 if (res == HTP_OK && prevlen > bstr_len(part)) {
2233 HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx);
2234 if (likely(htud == NULL)) {
2235 htud = HTPCalloc(1, sizeof(*htud));
2236 if (unlikely(htud == NULL))
2237 return HTP_OK;
2238 htp_tx_set_user_data(tx, htud);
2239 }
2240 HtpState *s = htp_connp_get_user_data(tx->connp);
2241 if (s == NULL)
2242 return HTP_OK;
2243 HTPSetEvent(s, htud, HTTP_DECODER_EVENT_DOUBLE_ENCODED_URI);
2244 }
48cf0585
AS
2245
2246 return HTP_OK;
2247}
2248
8a339e73 2249static int HTPCallbackDoubleDecodeQuery(htp_tx_t *tx)
48cf0585 2250{
8a339e73 2251 if (tx->parsed_uri == NULL)
48cf0585
AS
2252 return HTP_OK;
2253
8a339e73
PA
2254 return HTPCallbackDoubleDecodeUriPart(tx, tx->parsed_uri->query);
2255}
48cf0585 2256
8a339e73
PA
2257static int HTPCallbackDoubleDecodePath(htp_tx_t *tx)
2258{
2259 if (tx->parsed_uri == NULL)
2260 return HTP_OK;
2261
2262 return HTPCallbackDoubleDecodeUriPart(tx, tx->parsed_uri->path);
48cf0585
AS
2263}
2264
2265static int HTPCallbackRequestHeaderData(htp_tx_data_t *tx_data)
2266{
1f07d152 2267 void *ptmp;
b25bd2e1 2268 if (tx_data->len == 0 || tx_data->tx == NULL)
48cf0585
AS
2269 return HTP_OK;
2270
2271 HtpTxUserData *tx_ud = htp_tx_get_user_data(tx_data->tx);
2272 if (tx_ud == NULL) {
ced01da8 2273 tx_ud = HTPMalloc(sizeof(*tx_ud));
79fcf137 2274 if (unlikely(tx_ud == NULL))
48cf0585
AS
2275 return HTP_OK;
2276 memset(tx_ud, 0, sizeof(*tx_ud));
2277 htp_tx_set_user_data(tx_data->tx, tx_ud);
2278 }
ced01da8
EL
2279 ptmp = HTPRealloc(tx_ud->request_headers_raw,
2280 tx_ud->request_headers_raw_len,
1f07d152
EL
2281 tx_ud->request_headers_raw_len + tx_data->len);
2282 if (ptmp == NULL) {
f536099a
VJ
2283 /* error: we're freeing the entire user data */
2284 HtpState *hstate = htp_connp_get_user_data(tx_data->tx->connp);
2285 HtpTxUserDataFree(hstate, tx_ud);
48cf0585 2286 htp_tx_set_user_data(tx_data->tx, NULL);
48cf0585
AS
2287 return HTP_OK;
2288 }
1f07d152
EL
2289 tx_ud->request_headers_raw = ptmp;
2290
48cf0585
AS
2291 memcpy(tx_ud->request_headers_raw + tx_ud->request_headers_raw_len,
2292 tx_data->data, tx_data->len);
2293 tx_ud->request_headers_raw_len += tx_data->len;
2294
43b39d33
VJ
2295 if (tx_data->tx && tx_data->tx->flags) {
2296 HtpState *hstate = htp_connp_get_user_data(tx_data->tx->connp);
2297 HTPErrorCheckTxRequestFlags(hstate, tx_data->tx);
2298 }
48cf0585
AS
2299 return HTP_OK;
2300}
2301
2302static int HTPCallbackResponseHeaderData(htp_tx_data_t *tx_data)
2303{
1f07d152 2304 void *ptmp;
b25bd2e1 2305 if (tx_data->len == 0 || tx_data->tx == NULL)
48cf0585
AS
2306 return HTP_OK;
2307
2308 HtpTxUserData *tx_ud = htp_tx_get_user_data(tx_data->tx);
2309 if (tx_ud == NULL) {
ced01da8 2310 tx_ud = HTPMalloc(sizeof(*tx_ud));
79fcf137 2311 if (unlikely(tx_ud == NULL))
48cf0585
AS
2312 return HTP_OK;
2313 memset(tx_ud, 0, sizeof(*tx_ud));
2314 htp_tx_set_user_data(tx_data->tx, tx_ud);
2315 }
ced01da8
EL
2316 ptmp = HTPRealloc(tx_ud->response_headers_raw,
2317 tx_ud->response_headers_raw_len,
1f07d152
EL
2318 tx_ud->response_headers_raw_len + tx_data->len);
2319 if (ptmp == NULL) {
f536099a
VJ
2320 /* error: we're freeing the entire user data */
2321 HtpState *hstate = htp_connp_get_user_data(tx_data->tx->connp);
2322 HtpTxUserDataFree(hstate, tx_ud);
48cf0585 2323 htp_tx_set_user_data(tx_data->tx, NULL);
48cf0585
AS
2324 return HTP_OK;
2325 }
1f07d152
EL
2326 tx_ud->response_headers_raw = ptmp;
2327
48cf0585
AS
2328 memcpy(tx_ud->response_headers_raw + tx_ud->response_headers_raw_len,
2329 tx_data->data, tx_data->len);
2330 tx_ud->response_headers_raw_len += tx_data->len;
2331
2332 return HTP_OK;
2333}
2334
2335/*
2336 * We have a similar set function called HTPConfigSetDefaultsPhase1.
2337 */
2338static void HTPConfigSetDefaultsPhase1(HTPCfgRec *cfg_prec)
a9cdd2bb 2339{
a8b971c7 2340 cfg_prec->uri_include_all = FALSE;
24a2f515
VJ
2341 cfg_prec->request.body_limit = HTP_CONFIG_DEFAULT_REQUEST_BODY_LIMIT;
2342 cfg_prec->response.body_limit = HTP_CONFIG_DEFAULT_RESPONSE_BODY_LIMIT;
2343 cfg_prec->request.inspect_min_size = HTP_CONFIG_DEFAULT_REQUEST_INSPECT_MIN_SIZE;
2344 cfg_prec->request.inspect_window = HTP_CONFIG_DEFAULT_REQUEST_INSPECT_WINDOW;
2345 cfg_prec->response.inspect_min_size = HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_MIN_SIZE;
2346 cfg_prec->response.inspect_window = HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_WINDOW;
c3b4dd5a
VJ
2347
2348 if (!g_disable_randomness) {
2349 cfg_prec->randomize = HTP_CONFIG_DEFAULT_RANDOMIZE;
2350 } else {
2351 cfg_prec->randomize = 0;
2352 }
ff784075 2353 cfg_prec->randomize_range = HTP_CONFIG_DEFAULT_RANDOMIZE_RANGE;
48cf0585
AS
2354
2355 htp_config_register_request_header_data(cfg_prec->cfg, HTPCallbackRequestHeaderData);
2356 htp_config_register_request_trailer_data(cfg_prec->cfg, HTPCallbackRequestHeaderData);
2357 htp_config_register_response_header_data(cfg_prec->cfg, HTPCallbackResponseHeaderData);
2358 htp_config_register_response_trailer_data(cfg_prec->cfg, HTPCallbackResponseHeaderData);
2359
44022743
VJ
2360 htp_config_register_request_trailer(cfg_prec->cfg, HTPCallbackRequestHasTrailer);
2361 htp_config_register_response_trailer(cfg_prec->cfg, HTPCallbackResponseHasTrailer);
2362
340542c4
AS
2363 htp_config_register_request_body_data(cfg_prec->cfg, HTPCallbackRequestBodyData);
2364 htp_config_register_response_body_data(cfg_prec->cfg, HTPCallbackResponseBodyData);
a9cdd2bb 2365
e02b74de 2366 htp_config_register_request_start(cfg_prec->cfg, HTPCallbackRequestStart);
48cf0585 2367 htp_config_register_request_complete(cfg_prec->cfg, HTPCallbackRequest);
e02b74de
VJ
2368
2369 htp_config_register_response_start(cfg_prec->cfg, HTPCallbackResponseStart);
48cf0585
AS
2370 htp_config_register_response_complete(cfg_prec->cfg, HTPCallbackResponse);
2371
2372 htp_config_set_parse_request_cookies(cfg_prec->cfg, 0);
48cf0585 2373
9a7353e1
VJ
2374 /* don't convert + to space by default */
2375 htp_config_set_plusspace_decode(cfg_prec->cfg, HTP_DECODER_URLENCODED, 0);
61a6eaf3
JI
2376#ifdef HAVE_HTP_CONFIG_SET_LZMA_MEMLIMIT
2377 htp_config_set_lzma_memlimit(cfg_prec->cfg,
2378 HTP_CONFIG_DEFAULT_LZMA_MEMLIMIT);
2379#endif
fb496791
VJ
2380 /* libhtp <= 0.5.9 doesn't use soft limit, but it's impossible to set
2381 * only the hard limit. So we set both here to the (current) htp defaults.
2382 * The reason we do this is that if the user sets the hard limit in the
2383 * config, we have to set the soft limit as well. If libhtp starts using
2384 * the soft limit in the future, we at least make sure we control what
2385 * it's value is. */
2386 htp_config_set_field_limits(cfg_prec->cfg,
2387 (size_t)HTP_CONFIG_DEFAULT_FIELD_LIMIT_SOFT,
2388 (size_t)HTP_CONFIG_DEFAULT_FIELD_LIMIT_HARD);
48cf0585
AS
2389 return;
2390}
2391
7fb58e67
VJ
2392/* hack: htp random range code expects random values in range of 0-RAND_MAX,
2393 * but we can get both <0 and >RAND_MAX values from RandomGet
2394 */
2395static int RandomGetWrap(void)
2396{
18f64e0d
MN
2397 unsigned long r;
2398
2399 do {
2400 r = RandomGet();
2401 } while(r >= ULONG_MAX - (ULONG_MAX % RAND_MAX));
2402
2403 return r % RAND_MAX;
7fb58e67
VJ
2404}
2405
48cf0585
AS
2406/*
2407 * We have this splitup so that in case double decoding has been enabled
2408 * for query and path, they would be called first on the callback queue,
2409 * before the callback set by Phase2() is called. We need this, since
2410 * the callback in Phase2() generates the normalized uri which utilizes
2411 * the query and path. */
ab1200fb 2412static void HTPConfigSetDefaultsPhase2(const char *name, HTPCfgRec *cfg_prec)
48cf0585 2413{
ff784075
EL
2414 /* randomize inspection size if needed */
2415 if (cfg_prec->randomize) {
2416 int rdrange = cfg_prec->randomize_range;
2417
7fb58e67 2418 long int r = RandomGetWrap();
24a2f515
VJ
2419 cfg_prec->request.inspect_min_size +=
2420 (int) (cfg_prec->request.inspect_min_size *
535d9e35
VJ
2421 (r * 1.0 / RAND_MAX - 0.5) * rdrange / 100);
2422
7fb58e67 2423 r = RandomGetWrap();
24a2f515
VJ
2424 cfg_prec->request.inspect_window +=
2425 (int) (cfg_prec->request.inspect_window *
535d9e35 2426 (r * 1.0 / RAND_MAX - 0.5) * rdrange / 100);
b3bf7a57 2427 SCLogConfig("'%s' server has 'request-body-minimal-inspect-size' set to"
72954067
EL
2428 " %d and 'request-body-inspect-window' set to %d after"
2429 " randomization.",
2430 name,
24a2f515
VJ
2431 cfg_prec->request.inspect_min_size,
2432 cfg_prec->request.inspect_window);
72954067 2433
ff784075 2434
7fb58e67 2435 r = RandomGetWrap();
24a2f515
VJ
2436 cfg_prec->response.inspect_min_size +=
2437 (int) (cfg_prec->response.inspect_min_size *
535d9e35
VJ
2438 (r * 1.0 / RAND_MAX - 0.5) * rdrange / 100);
2439
7fb58e67 2440 r = RandomGetWrap();
24a2f515
VJ
2441 cfg_prec->response.inspect_window +=
2442 (int) (cfg_prec->response.inspect_window *
535d9e35 2443 (r * 1.0 / RAND_MAX - 0.5) * rdrange / 100);
72954067 2444
b3bf7a57 2445 SCLogConfig("'%s' server has 'response-body-minimal-inspect-size' set to"
72954067
EL
2446 " %d and 'response-body-inspect-window' set to %d after"
2447 " randomization.",
2448 name,
24a2f515
VJ
2449 cfg_prec->response.inspect_min_size,
2450 cfg_prec->response.inspect_window);
ff784075
EL
2451 }
2452
48cf0585
AS
2453 htp_config_register_request_line(cfg_prec->cfg, HTPCallbackRequestLine);
2454
6fb808fc 2455 cfg_prec->request.sbcfg.flags = 0;
24a2f515
VJ
2456 cfg_prec->request.sbcfg.buf_size = cfg_prec->request.inspect_window ?
2457 cfg_prec->request.inspect_window : 256;
6fb808fc
VJ
2458 cfg_prec->request.sbcfg.buf_slide = 0;
2459 cfg_prec->request.sbcfg.Malloc = HTPMalloc;
2460 cfg_prec->request.sbcfg.Calloc = HTPCalloc;
2461 cfg_prec->request.sbcfg.Realloc = HTPRealloc;
2462 cfg_prec->request.sbcfg.Free = HTPFree;
2463
2464 cfg_prec->response.sbcfg.flags = 0;
24a2f515
VJ
2465 cfg_prec->response.sbcfg.buf_size = cfg_prec->response.inspect_window ?
2466 cfg_prec->response.inspect_window : 256;
6fb808fc
VJ
2467 cfg_prec->response.sbcfg.buf_slide = 0;
2468 cfg_prec->response.sbcfg.Malloc = HTPMalloc;
2469 cfg_prec->response.sbcfg.Calloc = HTPCalloc;
2470 cfg_prec->response.sbcfg.Realloc = HTPRealloc;
2471 cfg_prec->response.sbcfg.Free = HTPFree;
340542c4
AS
2472 return;
2473}
a9cdd2bb 2474
028c6c17 2475static void HTPConfigParseParameters(HTPCfgRec *cfg_prec, ConfNode *s,
340542c4
AS
2476 SCRadixTree *tree)
2477{
028c6c17 2478 if (cfg_prec == NULL || s == NULL || tree == NULL)
340542c4 2479 return;
a9cdd2bb 2480
340542c4
AS
2481 ConfNode *p = NULL;
2482
2483 /* Default Parameters */
028c6c17 2484 TAILQ_FOREACH(p, &s->head, next) {
340542c4
AS
2485
2486 if (strcasecmp("address", p->name) == 0) {
2487 ConfNode *pval;
2488 /* Addresses */
2489 TAILQ_FOREACH(pval, &p->head, next) {
2490 SCLogDebug("LIBHTP server %s: %s=%s", s->name, p->name,
2491 pval->val);
2492
2493 /* IPV6 or IPV4? */
2494 if (strchr(pval->val, ':') != NULL) {
2495 SCLogDebug("LIBHTP adding ipv6 server %s at %s: %p",
028c6c17 2496 s->name, pval->val, cfg_prec->cfg);
340542c4
AS
2497 if (SCRadixAddKeyIPV6String(pval->val, tree, cfg_prec) == NULL) {
2498 SCLogWarning(SC_ERR_INVALID_VALUE, "LIBHTP failed to "
2499 "add ipv6 server %s, ignoring", pval->val);
2500 }
2501 } else {
2502 SCLogDebug("LIBHTP adding ipv4 server %s at %s: %p",
028c6c17 2503 s->name, pval->val, cfg_prec->cfg);
340542c4
AS
2504 if (SCRadixAddKeyIPV4String(pval->val, tree, cfg_prec) == NULL) {
2505 SCLogWarning(SC_ERR_INVALID_VALUE, "LIBHTP failed "
2506 "to add ipv4 server %s, ignoring",
2507 pval->val);
2508 }
2509 } /* else - if (strchr(pval->val, ':') != NULL) */
2510 } /* TAILQ_FOREACH(pval, &p->head, next) */
2511
2512 } else if (strcasecmp("personality", p->name) == 0) {
2513 /* Personalities */
2514 int personality = HTPLookupPersonality(p->val);
2515 SCLogDebug("LIBHTP default: %s = %s", p->name, p->val);
2516 SCLogDebug("LIBHTP default: %s = %s", p->name, p->val);
2517
2518 if (personality >= 0) {
2519 SCLogDebug("LIBHTP default: %s=%s (%d)", p->name, p->val,
2520 personality);
2521 if (htp_config_set_server_personality(cfg_prec->cfg, personality) == HTP_ERROR){
2522 SCLogWarning(SC_ERR_INVALID_VALUE, "LIBHTP Failed adding "
2523 "personality \"%s\", ignoring", p->val);
2524 } else {
2525 SCLogDebug("LIBHTP personality set to %s",
2526 HTPLookupPersonalityString(personality));
2527 }
a9cdd2bb 2528
340542c4
AS
2529 /* The IDS personality by default converts the path (and due to
2530 * our query string callback also the query string) to lowercase.
2531 * Signatures do not expect this, so override it. */
48cf0585 2532 htp_config_set_convert_lowercase(cfg_prec->cfg, HTP_DECODER_URL_PATH, 0);
340542c4
AS
2533 } else {
2534 SCLogWarning(SC_ERR_UNKNOWN_VALUE, "LIBHTP Unknown personality "
2535 "\"%s\", ignoring", p->val);
2536 continue;
2537 }
a9cdd2bb 2538
340542c4
AS
2539 } else if (strcasecmp("request-body-limit", p->name) == 0 ||
2540 strcasecmp("request_body_limit", p->name) == 0) {
24a2f515 2541 if (ParseSizeStringU32(p->val, &cfg_prec->request.body_limit) < 0) {
340542c4
AS
2542 SCLogError(SC_ERR_SIZE_PARSE, "Error parsing request-body-limit "
2543 "from conf file - %s. Killing engine", p->val);
2544 exit(EXIT_FAILURE);
2545 }
a9cdd2bb 2546
340542c4 2547 } else if (strcasecmp("response-body-limit", p->name) == 0) {
24a2f515 2548 if (ParseSizeStringU32(p->val, &cfg_prec->response.body_limit) < 0) {
340542c4
AS
2549 SCLogError(SC_ERR_SIZE_PARSE, "Error parsing response-body-limit "
2550 "from conf file - %s. Killing engine", p->val);
2551 exit(EXIT_FAILURE);
2552 }
48cf0585 2553
2763a612 2554 } else if (strcasecmp("request-body-minimal-inspect-size", p->name) == 0) {
24a2f515 2555 if (ParseSizeStringU32(p->val, &cfg_prec->request.inspect_min_size) < 0) {
2763a612
VJ
2556 SCLogError(SC_ERR_SIZE_PARSE, "Error parsing request-body-minimal-inspect-size "
2557 "from conf file - %s. Killing engine", p->val);
2558 exit(EXIT_FAILURE);
2559 }
2560
2561 } else if (strcasecmp("request-body-inspect-window", p->name) == 0) {
24a2f515 2562 if (ParseSizeStringU32(p->val, &cfg_prec->request.inspect_window) < 0) {
2763a612
VJ
2563 SCLogError(SC_ERR_SIZE_PARSE, "Error parsing request-body-inspect-window "
2564 "from conf file - %s. Killing engine", p->val);
2565 exit(EXIT_FAILURE);
2566 }
2567
e5879650 2568 } else if (strcasecmp("double-decode-query", p->name) == 0) {
48cf0585
AS
2569 if (ConfValIsTrue(p->val)) {
2570 htp_config_register_request_line(cfg_prec->cfg,
2571 HTPCallbackDoubleDecodeQuery);
2572 }
2573
e5879650 2574 } else if (strcasecmp("double-decode-path", p->name) == 0) {
48cf0585
AS
2575 if (ConfValIsTrue(p->val)) {
2576 htp_config_register_request_line(cfg_prec->cfg,
2577 HTPCallbackDoubleDecodePath);
2578 }
2579
2763a612 2580 } else if (strcasecmp("response-body-minimal-inspect-size", p->name) == 0) {
24a2f515 2581 if (ParseSizeStringU32(p->val, &cfg_prec->response.inspect_min_size) < 0) {
2763a612
VJ
2582 SCLogError(SC_ERR_SIZE_PARSE, "Error parsing response-body-minimal-inspect-size "
2583 "from conf file - %s. Killing engine", p->val);
2584 exit(EXIT_FAILURE);
2585 }
2586
2587 } else if (strcasecmp("response-body-inspect-window", p->name) == 0) {
24a2f515 2588 if (ParseSizeStringU32(p->val, &cfg_prec->response.inspect_window) < 0) {
2763a612
VJ
2589 SCLogError(SC_ERR_SIZE_PARSE, "Error parsing response-body-inspect-window "
2590 "from conf file - %s. Killing engine", p->val);
2591 exit(EXIT_FAILURE);
2592 }
bde55578 2593
5ec885e4
VJ
2594 } else if (strcasecmp("response-body-decompress-layer-limit", p->name) == 0) {
2595 uint32_t value = 2;
2596 if (ParseSizeStringU32(p->val, &value) < 0) {
2597 SCLogError(SC_ERR_SIZE_PARSE, "Error parsing response-body-inspect-window "
2598 "from conf file - %s. Killing engine", p->val);
2599 exit(EXIT_FAILURE);
2600 }
2601#ifdef HAVE_HTP_CONFIG_SET_RESPONSE_DECOMPRESSION_LAYER_LIMIT
2602 htp_config_set_response_decompression_layer_limit(cfg_prec->cfg, value);
2603#else
2604 SCLogWarning(SC_WARN_OUTDATED_LIBHTP, "can't set response-body-decompress-layer-limit "
2605 "to %u, libhtp version too old", value);
2606#endif
48cf0585
AS
2607 } else if (strcasecmp("path-convert-backslash-separators", p->name) == 0) {
2608 htp_config_set_backslash_convert_slashes(cfg_prec->cfg,
2609 HTP_DECODER_URL_PATH,
2610 ConfValIsTrue(p->val));
2611 } else if (strcasecmp("path-bestfit-replacement-char", p->name) == 0) {
2612 if (strlen(p->val) == 1) {
2613 htp_config_set_bestfit_replacement_byte(cfg_prec->cfg,
2614 HTP_DECODER_URL_PATH,
2615 p->val[0]);
028c6c17
AS
2616 } else {
2617 SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry "
48cf0585 2618 "for libhtp param path-bestfit-replacement-char");
028c6c17 2619 }
48cf0585
AS
2620 } else if (strcasecmp("path-convert-lowercase", p->name) == 0) {
2621 htp_config_set_convert_lowercase(cfg_prec->cfg,
2622 HTP_DECODER_URL_PATH,
2623 ConfValIsTrue(p->val));
2624 } else if (strcasecmp("path-nul-encoded-terminates", p->name) == 0) {
2625 htp_config_set_nul_encoded_terminates(cfg_prec->cfg,
2626 HTP_DECODER_URL_PATH,
2627 ConfValIsTrue(p->val));
2628 } else if (strcasecmp("path-nul-raw-terminates", p->name) == 0) {
2629 htp_config_set_nul_raw_terminates(cfg_prec->cfg,
2630 HTP_DECODER_URL_PATH,
2631 ConfValIsTrue(p->val));
2632 } else if (strcasecmp("path-separators-compress", p->name) == 0) {
2633 htp_config_set_path_separators_compress(cfg_prec->cfg,
2634 HTP_DECODER_URL_PATH,
2635 ConfValIsTrue(p->val));
2636 } else if (strcasecmp("path-separators-decode", p->name) == 0) {
2637 htp_config_set_path_separators_decode(cfg_prec->cfg,
2638 HTP_DECODER_URL_PATH,
2639 ConfValIsTrue(p->val));
2640 } else if (strcasecmp("path-u-encoding-decode", p->name) == 0) {
2641 htp_config_set_u_encoding_decode(cfg_prec->cfg,
2642 HTP_DECODER_URL_PATH,
2643 ConfValIsTrue(p->val));
2644 } else if (strcasecmp("path-url-encoding-invalid-handling", p->name) == 0) {
2645 enum htp_url_encoding_handling_t handling;
028c6c17 2646 if (strcasecmp(p->val, "preserve_percent") == 0) {
48cf0585 2647 handling = HTP_URL_DECODE_PRESERVE_PERCENT;
028c6c17 2648 } else if (strcasecmp(p->val, "remove_percent") == 0) {
48cf0585 2649 handling = HTP_URL_DECODE_REMOVE_PERCENT;
028c6c17 2650 } else if (strcasecmp(p->val, "decode_invalid") == 0) {
48cf0585 2651 handling = HTP_URL_DECODE_PROCESS_INVALID;
028c6c17
AS
2652 } else {
2653 SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry "
48cf0585
AS
2654 "for libhtp param path-url-encoding-invalid-handling");
2655 return;
028c6c17 2656 }
48cf0585
AS
2657 htp_config_set_url_encoding_invalid_handling(cfg_prec->cfg,
2658 HTP_DECODER_URL_PATH,
2659 handling);
2660 } else if (strcasecmp("path-utf8-convert-bestfit", p->name) == 0) {
2661 htp_config_set_utf8_convert_bestfit(cfg_prec->cfg,
2662 HTP_DECODER_URL_PATH,
2663 ConfValIsTrue(p->val));
a8b971c7
VJ
2664 } else if (strcasecmp("uri-include-all", p->name) == 0) {
2665 cfg_prec->uri_include_all = ConfValIsTrue(p->val);
2666 SCLogDebug("uri-include-all %s",
2667 cfg_prec->uri_include_all ? "enabled" : "disabled");
9a7353e1
VJ
2668 } else if (strcasecmp("query-plusspace-decode", p->name) == 0) {
2669 htp_config_set_plusspace_decode(cfg_prec->cfg,
2670 HTP_DECODER_URLENCODED,
2671 ConfValIsTrue(p->val));
fb496791
VJ
2672 } else if (strcasecmp("meta-field-limit", p->name) == 0) {
2673 uint32_t limit = 0;
2674 if (ParseSizeStringU32(p->val, &limit) < 0) {
2675 SCLogError(SC_ERR_SIZE_PARSE, "Error meta-field-limit "
2676 "from conf file - %s. Killing engine", p->val);
2677 exit(EXIT_FAILURE);
2678 }
2679 if (limit == 0) {
2680 SCLogError(SC_ERR_SIZE_PARSE, "Error meta-field-limit "
2681 "from conf file cannot be 0. Killing engine");
2682 exit(EXIT_FAILURE);
2683 }
2684 /* set default soft-limit with our new hard limit */
2685 htp_config_set_field_limits(cfg_prec->cfg,
2686 (size_t)HTP_CONFIG_DEFAULT_FIELD_LIMIT_SOFT,
2687 (size_t)limit);
c9c23d5c
VJ
2688#ifdef HAVE_HTP_CONFIG_SET_LZMA_MEMLIMIT
2689 } else if (strcasecmp("lzma-memlimit", p->name) == 0) {
2690 uint32_t limit = 0;
2691 if (ParseSizeStringU32(p->val, &limit) < 0) {
2692 FatalError(SC_ERR_SIZE_PARSE, "failed to parse 'lzma-memlimit' "
2693 "from conf file - %s.", p->val);
2694 }
2695 if (limit == 0) {
2696 FatalError(SC_ERR_SIZE_PARSE, "'lzma-memlimit' "
2697 "from conf file cannot be 0.");
2698 }
2699 /* set default soft-limit with our new hard limit */
61a6eaf3
JI
2700 SCLogConfig("Setting HTTP LZMA memory limit to %"PRIu32" bytes", limit);
2701 htp_config_set_lzma_memlimit(cfg_prec->cfg, (size_t)limit);
c9c23d5c 2702#endif
ff784075 2703 } else if (strcasecmp("randomize-inspection-sizes", p->name) == 0) {
c3b4dd5a
VJ
2704 if (!g_disable_randomness) {
2705 cfg_prec->randomize = ConfValIsTrue(p->val);
2706 }
ff784075
EL
2707 } else if (strcasecmp("randomize-inspection-range", p->name) == 0) {
2708 uint32_t range = atoi(p->val);
2709 if (range > 100) {
2710 SCLogError(SC_ERR_SIZE_PARSE, "Invalid value for randomize"
2711 " inspection range setting from conf file - %s."
2712 " It should be inferior to 100."
2713 " Killing engine",
2714 p->val);
2715 exit(EXIT_FAILURE);
2716 }
2717 cfg_prec->randomize_range = range;
a459376d
GL
2718 } else if (strcasecmp("http-body-inline", p->name) == 0) {
2719 if (ConfValIsTrue(p->val)) {
2720 cfg_prec->http_body_inline = 1;
2721 } else if (ConfValIsFalse(p->val)) {
2722 cfg_prec->http_body_inline = 0;
2723 } else {
2724 if (strcmp("auto", p->val) != 0) {
2725 WarnInvalidConfEntry("http_body_inline", "%s", "auto");
2726 }
2727 if (EngineModeIsIPS()) {
2728 cfg_prec->http_body_inline = 1;
2729 } else {
2730 cfg_prec->http_body_inline = 0;
2731 }
2732 }
d0f92e2a
GL
2733 } else if (strcasecmp("swf-decompression", p->name) == 0) {
2734 ConfNode *pval;
2735
2736 TAILQ_FOREACH(pval, &p->head, next) {
2737 if (strcasecmp("enabled", pval->name) == 0) {
2738 if (ConfValIsTrue(pval->val)) {
2739 cfg_prec->swf_decompression_enabled = 1;
2740 } else if (ConfValIsFalse(pval->val)) {
2741 cfg_prec->swf_decompression_enabled = 0;
2742 } else {
2743 WarnInvalidConfEntry("swf-decompression.enabled", "%s", "no");
2744 }
2745 } else if (strcasecmp("type", pval->name) == 0) {
2746 if (strcasecmp("no", pval->val) == 0) {
2747 cfg_prec->swf_compression_type = HTTP_SWF_COMPRESSION_NONE;
2748 } else if (strcasecmp("deflate", pval->val) == 0) {
2749 cfg_prec->swf_compression_type = HTTP_SWF_COMPRESSION_ZLIB;
2750 } else if (strcasecmp("lzma", pval->val) == 0) {
2751 cfg_prec->swf_compression_type = HTTP_SWF_COMPRESSION_LZMA;
2752 } else if (strcasecmp("both", pval->val) == 0) {
2753 cfg_prec->swf_compression_type = HTTP_SWF_COMPRESSION_BOTH;
2754 } else {
2755 SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY,
2756 "Invalid entry for "
2757 "swf-decompression.type: %s - "
2758 "Killing engine", pval->val);
2759 exit(EXIT_FAILURE);
2760 }
2761 } else if (strcasecmp("compress-depth", pval->name) == 0) {
2762 if (ParseSizeStringU32(pval->val, &cfg_prec->swf_compress_depth) < 0) {
2763 SCLogError(SC_ERR_SIZE_PARSE,
2764 "Error parsing swf-decompression.compression-depth "
2765 "from conf file - %s. Killing engine", p->val);
2766 exit(EXIT_FAILURE);
2767 }
2768 } else if (strcasecmp("decompress-depth", pval->name) == 0) {
2769 if (ParseSizeStringU32(pval->val, &cfg_prec->swf_decompress_depth) < 0) {
2770 SCLogError(SC_ERR_SIZE_PARSE,
2771 "Error parsing swf-decompression.decompression-depth "
2772 "from conf file - %s. Killing engine", p->val);
2773 exit(EXIT_FAILURE);
2774 }
2775 } else {
2776 SCLogWarning(SC_ERR_UNKNOWN_VALUE, "Ignoring unknown param %s", pval->name);
2777 }
2778 }
340542c4
AS
2779 } else {
2780 SCLogWarning(SC_ERR_UNKNOWN_VALUE, "LIBHTP Ignoring unknown "
2781 "default config: %s", p->name);
a9cdd2bb 2782 }
340542c4
AS
2783 } /* TAILQ_FOREACH(p, &default_config->head, next) */
2784
2785 return;
2786}
2787
ab4b15c2 2788void HTPConfigure(void)
340542c4
AS
2789{
2790 SCEnter();
2791
2792 cfglist.next = NULL;
2793
2794 cfgtree = SCRadixCreateRadixTree(NULL, NULL);
2795 if (NULL == cfgtree)
2796 exit(EXIT_FAILURE);
2797
2798 /* Default Config */
2799 cfglist.cfg = htp_config_create();
2800 if (NULL == cfglist.cfg) {
2801 SCLogError(SC_ERR_MEM_ALLOC, "Failed to create HTP default config");
2802 exit(EXIT_FAILURE);
a9cdd2bb 2803 }
340542c4 2804 SCLogDebug("LIBHTP default config: %p", cfglist.cfg);
48cf0585 2805 HTPConfigSetDefaultsPhase1(&cfglist);
ddde572f
AS
2806 if (ConfGetNode("app-layer.protocols.http.libhtp") == NULL) {
2807 HTPConfigParseParameters(&cfglist, ConfGetNode("libhtp.default-config"),
2808 cfgtree);
2809 } else {
2810 HTPConfigParseParameters(&cfglist, ConfGetNode("app-layer.protocols.http.libhtp.default-config"), cfgtree);
2811 }
72954067 2812 HTPConfigSetDefaultsPhase2("default", &cfglist);
a9cdd2bb 2813
ced01da8
EL
2814 HTPParseMemcap();
2815
a9cdd2bb 2816 /* Read server config and create a parser for each IP in radix tree */
ddde572f
AS
2817 ConfNode *server_config = ConfGetNode("app-layer.protocols.http.libhtp.server-config");
2818 if (server_config == NULL) {
2819 server_config = ConfGetNode("libhtp.server-config");
2820 if (server_config == NULL) {
2821 SCLogDebug("LIBHTP Configuring %p", server_config);
2822 SCReturn;
2823 }
2824 }
a9cdd2bb 2825 SCLogDebug("LIBHTP Configuring %p", server_config);
a9cdd2bb 2826
340542c4
AS
2827 ConfNode *si;
2828 /* Server Nodes */
2829 TAILQ_FOREACH(si, &server_config->head, next) {
2830 /* Need the named node, not the index */
2831 ConfNode *s = TAILQ_FIRST(&si->head);
2832 if (NULL == s) {
2833 SCLogDebug("LIBHTP s NULL");
2834 continue;
2835 }
a9cdd2bb 2836
340542c4 2837 SCLogDebug("LIBHTP server %s", s->name);
a9cdd2bb 2838
340542c4 2839 HTPCfgRec *nextrec = cfglist.next;
28c5c681 2840 HTPCfgRec *htprec = SCMalloc(sizeof(HTPCfgRec));
340542c4
AS
2841 if (NULL == htprec)
2842 exit(EXIT_FAILURE);
a8b971c7
VJ
2843 memset(htprec, 0x00, sizeof(*htprec));
2844
28c5c681
EL
2845 cfglist.next = htprec;
2846
340542c4
AS
2847 cfglist.next->next = nextrec;
2848 cfglist.next->cfg = htp_config_create();
2849 if (NULL == cfglist.next->cfg) {
2850 SCLogError(SC_ERR_MEM_ALLOC, "Failed to create HTP server config");
2851 exit(EXIT_FAILURE);
2852 }
bde55578 2853
48cf0585 2854 HTPConfigSetDefaultsPhase1(htprec);
340542c4 2855 HTPConfigParseParameters(htprec, s, cfgtree);
72954067 2856 HTPConfigSetDefaultsPhase2(s->name, htprec);
a9cdd2bb
BR
2857 }
2858
2859 SCReturn;
2860}
2861
8f1d7503
KS
2862void AppLayerHtpPrintStats(void)
2863{
6fca55e0
VJ
2864#ifdef DEBUG
2865 SCMutexLock(&htp_state_mem_lock);
b3bf7a57 2866 SCLogPerf("htp memory %"PRIu64" (%"PRIu64")", htp_state_memuse, htp_state_memcnt);
6fca55e0
VJ
2867 SCMutexUnlock(&htp_state_mem_lock);
2868#endif
2869}
2870
d59ca75e
VJ
2871/** \internal
2872 * \brief get files callback
2873 * \param state state ptr
2874 * \param direction flow direction
2875 * \retval files files ptr
2876 */
8f1d7503
KS
2877static FileContainer *HTPStateGetFiles(void *state, uint8_t direction)
2878{
e1022ee5
VJ
2879 if (state == NULL)
2880 return NULL;
2881
2882 HtpState *http_state = (HtpState *)state;
d59ca75e
VJ
2883
2884 if (direction & STREAM_TOCLIENT) {
2885 SCReturnPtr(http_state->files_tc, "FileContainer");
2886 } else {
2887 SCReturnPtr(http_state->files_ts, "FileContainer");
2888 }
e1022ee5
VJ
2889}
2890
d4d18e31
AS
2891static int HTPStateGetAlstateProgress(void *tx, uint8_t direction)
2892{
429c6388 2893 if (direction & STREAM_TOSERVER)
080c15b3
VJ
2894 return ((htp_tx_t *)tx)->request_progress;
2895 else
2896 return ((htp_tx_t *)tx)->response_progress;
d4d18e31
AS
2897}
2898
2899static uint64_t HTPStateGetTxCnt(void *alstate)
2900{
896b6145
VJ
2901 HtpState *http_state = (HtpState *)alstate;
2902
6f339abd
VJ
2903 if (http_state != NULL && http_state->conn != NULL) {
2904 const uint64_t size = (uint64_t)htp_list_size(http_state->conn->transactions);
2905 SCLogDebug("size %"PRIu64, size);
2906 return size;
2907 } else {
896b6145 2908 return 0ULL;
6f339abd 2909 }
d4d18e31
AS
2910}
2911
2912static void *HTPStateGetTx(void *alstate, uint64_t tx_id)
2913{
896b6145
VJ
2914 HtpState *http_state = (HtpState *)alstate;
2915
2916 if (http_state != NULL && http_state->conn != NULL)
2917 return htp_list_get(http_state->conn->transactions, tx_id);
2918 else
2919 return NULL;
d4d18e31
AS
2920}
2921
bca0cd71 2922static void HTPStateSetTxLogged(void *alstate, void *vtx, LoggerId bits)
c52fe9a5
MK
2923{
2924 htp_tx_t *tx = (htp_tx_t *)vtx;
2925 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
2926 if (tx_ud)
bca0cd71 2927 tx_ud->logged = bits;
c52fe9a5
MK
2928}
2929
bca0cd71 2930static LoggerId HTPStateGetTxLogged(void *alstate, void *vtx)
c52fe9a5
MK
2931{
2932 htp_tx_t *tx = (htp_tx_t *)vtx;
2933 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
bca0cd71
VJ
2934 if (tx_ud != NULL)
2935 return tx_ud->logged;
c52fe9a5
MK
2936
2937 return 0;
2938}
2939
d4d18e31
AS
2940static int HTPStateGetAlstateProgressCompletionStatus(uint8_t direction)
2941{
429c6388 2942 return (direction & STREAM_TOSERVER) ? HTP_REQUEST_COMPLETE : HTP_RESPONSE_COMPLETE;
d4d18e31
AS
2943}
2944
ab1200fb 2945static int HTPStateGetEventInfo(const char *event_name,
5e2d9dbd
AS
2946 int *event_id, AppLayerEventType *event_type)
2947{
2948 *event_id = SCMapEnumNameToValue(event_name, http_decoder_event_table);
2949 if (*event_id == -1) {
2950 SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%s\" not present in "
2951 "http's enum map table.", event_name);
2952 /* this should be treated as fatal */
2953 return -1;
2954 }
2955
3f5acc54 2956 *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
5e2d9dbd
AS
2957
2958 return 0;
2959}
2960
f7b934f8
JL
2961static int HTPStateGetEventInfoById(int event_id, const char **event_name,
2962 AppLayerEventType *event_type)
2963{
2964 *event_name = SCMapEnumValueToName(event_id, http_decoder_event_table);
2965 if (*event_name == NULL) {
2966 SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%d\" not present in "
2967 "http's enum map table.", event_id);
2968 /* this should be treated as fatal */
2969 return -1;
2970 }
2971
2972 *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
2973
2974 return 0;
2975}
2976
429c6388
AS
2977static void HTPStateTruncate(void *state, uint8_t direction)
2978{
2979 FileContainer *fc = HTPStateGetFiles(state, direction);
869109a6
VJ
2980 if (fc != NULL) {
2981 FileTruncateAllOpenFiles(fc);
2982 }
2983}
2984
6279da0f
VJ
2985static DetectEngineState *HTPGetTxDetectState(void *vtx)
2986{
2987 htp_tx_t *tx = (htp_tx_t *)vtx;
2988 HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
2989 return tx_ud ? tx_ud->de_state : NULL;
2990}
2991
7548944b 2992static int HTPSetTxDetectState(void *vtx, DetectEngineState *s)
6279da0f
VJ
2993{
2994 htp_tx_t *tx = (htp_tx_t *)vtx;
2995 HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
2996 if (tx_ud == NULL) {
2997 tx_ud = HTPMalloc(sizeof(*tx_ud));
2998 if (unlikely(tx_ud == NULL))
2999 return -ENOMEM;
3000 memset(tx_ud, 0, sizeof(*tx_ud));
3001 htp_tx_set_user_data(tx, tx_ud);
3002 }
3003 tx_ud->de_state = s;
3004 return 0;
3005}
3006
00b0a41b 3007static uint64_t HTPGetTxDetectFlags(void *vtx, uint8_t dir)
a0fad6bb
VJ
3008{
3009 htp_tx_t *tx = (htp_tx_t *)vtx;
3010 HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
00b0a41b
VJ
3011 if (tx_ud) {
3012 if (dir & STREAM_TOSERVER) {
3013 return tx_ud->detect_flags_ts;
3014 } else {
3015 return tx_ud->detect_flags_tc;
3016 }
3017 }
3018 return 0;
a0fad6bb
VJ
3019}
3020
00b0a41b 3021static void HTPSetTxDetectFlags(void *vtx, uint8_t dir, uint64_t detect_flags)
a0fad6bb
VJ
3022{
3023 htp_tx_t *tx = (htp_tx_t *)vtx;
3024 HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
3025 if (tx_ud == NULL) {
3026 tx_ud = HTPMalloc(sizeof(*tx_ud));
3027 if (unlikely(tx_ud == NULL))
00b0a41b 3028 return;
a0fad6bb
VJ
3029 memset(tx_ud, 0, sizeof(*tx_ud));
3030 htp_tx_set_user_data(tx, tx_ud);
3031 }
00b0a41b
VJ
3032 if (dir & STREAM_TOSERVER) {
3033 tx_ud->detect_flags_ts = detect_flags;
3034 } else {
3035 tx_ud->detect_flags_tc = detect_flags;
3036 }
3037 return;
a0fad6bb
VJ
3038}
3039
429c6388
AS
3040static int HTPRegisterPatternsForProtocolDetection(void)
3041{
ab1200fb 3042 const char *methods[] = { "GET", "PUT", "POST", "HEAD", "TRACE", "OPTIONS",
3b26b079 3043 "CONNECT", "DELETE", "PATCH", "PROPFIND", "PROPPATCH", "MKCOL",
e7658fd4 3044 "COPY", "MOVE", "LOCK", "UNLOCK", "CHECKOUT", "UNCHECKOUT", "CHECKIN",
3045 "UPDATE", "LABEL", "REPORT", "MKWORKSPACE", "MKACTIVITY", "MERGE",
3046 "INVALID", "VERSION-CONTROL", "BASELINE-CONTROL", NULL};
ab1200fb
VJ
3047 const char *spacings[] = { "|20|", "|09|", NULL };
3048 const char *versions[] = { "HTTP/0.9", "HTTP/1.0", "HTTP/1.1", NULL };
3b26b079 3049
ec964ebf
VJ
3050 int methods_pos;
3051 int spacings_pos;
3052 int versions_pos;
3b26b079 3053 int register_result;
3054 char method_buffer[32] = "";
3055
e7658fd4 3056 /* Loop through all the methods ands spacings and register the patterns */
3b26b079 3057 for (methods_pos = 0; methods[methods_pos]; methods_pos++) {
3058 for (spacings_pos = 0; spacings[spacings_pos]; spacings_pos++) {
3059
e7658fd4 3060 /* Combine the method name and the spacing */
3b26b079 3061 snprintf(method_buffer, sizeof(method_buffer), "%s%s", methods[methods_pos], spacings[spacings_pos]);
3062
e7658fd4 3063 /* Register the new method+spacing pattern
3064 * 3 is subtracted from the length since the spacing is hex typed as |xx|
3065 * but the pattern matching should only be one char
3066 */
579d6d3f 3067 register_result = AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP,
3b26b079 3068 ALPROTO_HTTP, method_buffer, strlen(method_buffer)-3, 0, STREAM_TOSERVER);
3069 if (register_result < 0) {
3070 return -1;
3071 }
3072 }
7a9e9636 3073 }
3074
e7658fd4 3075 /* Loop through all the http verions patterns that are TO_CLIENT */
3b26b079 3076 for (versions_pos = 0; versions[versions_pos]; versions_pos++) {
579d6d3f 3077 register_result = AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP,
3b26b079 3078 ALPROTO_HTTP, versions[versions_pos], strlen(versions[versions_pos]),
3079 0, STREAM_TOCLIENT);
3080 if (register_result < 0) {
3081 return -1;
3082 }
429c6388 3083 }
ec964ebf 3084
429c6388
AS
3085 return 0;
3086}
3087
07f7ba55
GS
3088/**
3089 * \brief Register the HTTP protocol and state handling functions to APP layer
3090 * of the engine.
3091 */
3092void RegisterHTPParsers(void)
3093{
a9cdd2bb 3094 SCEnter();
000ce98c 3095
ab1200fb 3096 const char *proto_name = "http";
10966245 3097
000ce98c 3098 /** HTTP */
429c6388
AS
3099 if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
3100 AppLayerProtoDetectRegisterProtocol(ALPROTO_HTTP, proto_name);
3101 if (HTPRegisterPatternsForProtocolDetection() < 0)
3102 return;
ddde572f
AS
3103 } else {
3104 SCLogInfo("Protocol detection and parser disabled for %s protocol",
3105 proto_name);
3106 return;
3107 }
3108
429c6388
AS
3109 if (AppLayerParserConfParserEnabled("tcp", proto_name)) {
3110 AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_HTTP, HTPStateAlloc, HTPStateFree);
3111 AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_HTTP, HTPStateTransactionFree);
3112 AppLayerParserRegisterGetFilesFunc(IPPROTO_TCP, ALPROTO_HTTP, HTPStateGetFiles);
3113 AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_HTTP, HTPStateGetAlstateProgress);
3114 AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_HTTP, HTPStateGetTxCnt);
3115 AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_HTTP, HTPStateGetTx);
c52fe9a5
MK
3116 AppLayerParserRegisterLoggerFuncs(IPPROTO_TCP, ALPROTO_HTTP, HTPStateGetTxLogged,
3117 HTPStateSetTxLogged);
c4b918b6 3118 AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_HTTP,
429c6388 3119 HTPStateGetAlstateProgressCompletionStatus);
3f5acc54 3120 AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_HTTP, HTPGetEvents);
429c6388 3121 AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_HTTP, HTPStateGetEventInfo);
f7b934f8 3122 AppLayerParserRegisterGetEventInfoById(IPPROTO_TCP, ALPROTO_HTTP, HTPStateGetEventInfoById);
ddde572f 3123
429c6388 3124 AppLayerParserRegisterTruncateFunc(IPPROTO_TCP, ALPROTO_HTTP, HTPStateTruncate);
6279da0f
VJ
3125 AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_HTTP,
3126 HTPGetTxDetectState, HTPSetTxDetectState);
00b0a41b
VJ
3127 AppLayerParserRegisterDetectFlagsFuncs(IPPROTO_TCP, ALPROTO_HTTP,
3128 HTPGetTxDetectFlags, HTPSetTxDetectFlags);
ddde572f 3129
de904db8
GL
3130 AppLayerParserRegisterSetStreamDepthFlag(IPPROTO_TCP, ALPROTO_HTTP,
3131 AppLayerHtpSetStreamDepthFlag);
3132
429c6388
AS
3133 AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_HTTP, STREAM_TOSERVER,
3134 HTPHandleRequestData);
3135 AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_HTTP, STREAM_TOCLIENT,
3136 HTPHandleResponseData);
ddde572f 3137 SC_ATOMIC_INIT(htp_config_flags);
e6494114
VJ
3138 AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP,
3139 ALPROTO_HTTP, STREAM_TOSERVER|STREAM_TOCLIENT);
ddde572f
AS
3140 HTPConfigure();
3141 } else {
3142 SCLogInfo("Parsed disabled for %s protocol. Protocol detection"
3143 "still on.", proto_name);
3144 }
9faa4b74 3145#ifdef UNITTESTS
429c6388 3146 AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_HTTP, HTPParserRegisterTests);
9faa4b74 3147#endif
07f7ba55 3148
a9cdd2bb 3149 SCReturn;
07f7ba55
GS
3150}
3151
c352bff6 3152#ifdef UNITTESTS
99fca038
VJ
3153static HTPCfgRec cfglist_backup;
3154
ab4b15c2 3155void HtpConfigCreateBackup(void)
99fca038 3156{
dcdcbd97 3157 cfglist_backup = cfglist;
99fca038
VJ
3158
3159 return;
3160}
3161
ab4b15c2 3162void HtpConfigRestoreBackup(void)
99fca038 3163{
dcdcbd97 3164 cfglist = cfglist_backup;
99fca038
VJ
3165
3166 return;
3167}
a9cdd2bb 3168
07f7ba55
GS
3169/** \test Test case where chunks are sent in smaller chunks and check the
3170 * response of the parser from HTP library. */
ab1200fb 3171static int HTPParserTest01(void)
8f1d7503 3172{
fc2f7f29 3173 uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost"
07f7ba55
GS
3174 " Data is c0oL!";
3175 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
262a7300 3176
953dceec 3177 TcpSession ssn;
07f7ba55 3178 memset(&ssn, 0, sizeof(ssn));
262a7300 3179
953dceec
VJ
3180 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
3181 FAIL_IF_NULL(alp_tctx);
3182
3183 Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3184 FAIL_IF_NULL(f);
262a7300 3185 f->protoctx = &ssn;
429c6388 3186 f->proto = IPPROTO_TCP;
5c01b409 3187 f->alproto = ALPROTO_HTTP;
07f7ba55 3188
6a53ab9c 3189 StreamTcpInitConfig(TRUE);
6a53ab9c 3190
07f7ba55
GS
3191 uint32_t u;
3192 for (u = 0; u < httplen1; u++) {
3193 uint8_t flags = 0;
3194
59cda9a3
VJ
3195 if (u == 0)
3196 flags = STREAM_TOSERVER|STREAM_START;
3197 else if (u == (httplen1 - 1))
3198 flags = STREAM_TOSERVER|STREAM_EOF;
3199 else
3200 flags = STREAM_TOSERVER;
07f7ba55 3201
953dceec 3202 int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags,
675fa564 3203 &httpbuf1[u], 1);
953dceec 3204 FAIL_IF(r != 0);
07f7ba55
GS
3205 }
3206
953dceec
VJ
3207 HtpState *htp_state = f->alstate;
3208 FAIL_IF_NULL(htp_state);
07f7ba55 3209
d4d18e31 3210 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
953dceec
VJ
3211 FAIL_IF_NULL(tx);
3212
48cf0585 3213 htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
953dceec 3214 FAIL_IF_NULL(h);
07f7ba55 3215
953dceec
VJ
3216 FAIL_IF(strcmp(bstr_util_strdup_to_c(h->value), "Victor/1.0"));
3217 FAIL_IF(tx->request_method_number != HTP_M_POST);
3218 FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_0);
3219
3220 AppLayerParserThreadCtxFree(alp_tctx);
6a53ab9c 3221 StreamTcpFreeConfig(TRUE);
262a7300 3222 UTHFreeFlow(f);
953dceec 3223 PASS;
07f7ba55
GS
3224}
3225
08af5ddd
VJ
3226/** \test Test folding in 1 read case */
3227static int HTPParserTest01b(void)
3228{
3229 uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent:\r\n Victor/1.0\r\n\r\nPost"
3230 " Data is c0oL!";
3231 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3232
3233 TcpSession ssn;
3234 memset(&ssn, 0, sizeof(ssn));
3235
3236 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
3237 FAIL_IF_NULL(alp_tctx);
3238
3239 Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3240 FAIL_IF_NULL(f);
3241 f->protoctx = &ssn;
3242 f->proto = IPPROTO_TCP;
3243 f->alproto = ALPROTO_HTTP;
3244
3245 StreamTcpInitConfig(TRUE);
3246
3247 uint8_t flags =STREAM_TOSERVER|STREAM_START|STREAM_EOF;
3248 int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags,
3249 httpbuf1, httplen1);
3250 FAIL_IF(r != 0);
3251
3252 HtpState *htp_state = f->alstate;
3253 FAIL_IF_NULL(htp_state);
3254
3255 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3256 FAIL_IF_NULL(tx);
3257
3258 htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
3259 FAIL_IF_NULL(h);
3260
3261 FAIL_IF(strcmp(bstr_util_strdup_to_c(h->value), "Victor/1.0"));
3262 FAIL_IF(tx->request_method_number != HTP_M_POST);
3263 FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_0);
3264
3265 AppLayerParserThreadCtxFree(alp_tctx);
3266 StreamTcpFreeConfig(TRUE);
3267 UTHFreeFlow(f);
3268 PASS;
3269}
3270
3271/** \test Test folding in 1byte per read case */
3272static int HTPParserTest01c(void)
3273{
3274 uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent:\r\n Victor/1.0\r\n\r\nPost"
3275 " Data is c0oL!";
3276 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3277
3278 TcpSession ssn;
3279 memset(&ssn, 0, sizeof(ssn));
3280
3281 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
3282 FAIL_IF_NULL(alp_tctx);
3283
3284 Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3285 FAIL_IF_NULL(f);
3286 f->protoctx = &ssn;
3287 f->proto = IPPROTO_TCP;
3288 f->alproto = ALPROTO_HTTP;
3289
3290 StreamTcpInitConfig(TRUE);
3291
3292 uint32_t u;
3293 for (u = 0; u < httplen1; u++) {
3294 uint8_t flags = 0;
3295
3296 if (u == 0)
3297 flags = STREAM_TOSERVER|STREAM_START;
3298 else if (u == (httplen1 - 1))
3299 flags = STREAM_TOSERVER|STREAM_EOF;
3300 else
3301 flags = STREAM_TOSERVER;
3302
3303 int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags,
3304 &httpbuf1[u], 1);
3305 FAIL_IF(r != 0);
3306 }
3307
3308 HtpState *htp_state = f->alstate;
3309 FAIL_IF_NULL(htp_state);
3310
3311 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3312 FAIL_IF_NULL(tx);
3313
3314 htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
3315 FAIL_IF_NULL(h);
3316
3317 FAIL_IF(strcmp(bstr_util_strdup_to_c(h->value), "Victor/1.0"));
3318 FAIL_IF(tx->request_method_number != HTP_M_POST);
3319 FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_0);
3320
3321 AppLayerParserThreadCtxFree(alp_tctx);
3322 StreamTcpFreeConfig(TRUE);
3323 UTHFreeFlow(f);
3324 PASS;
3325}
3326
52195a41
VJ
3327/** \test Test case where chunks are sent in smaller chunks and check the
3328 * response of the parser from HTP library. */
3329static int HTPParserTest01a(void)
3330{
e86e27ba 3331 int result = 0;
52195a41
VJ
3332 Flow *f = NULL;
3333 uint8_t httpbuf1[] = " POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost"
3334 " Data is c0oL!";
3335 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3336 TcpSession ssn;
3337 HtpState *htp_state = NULL;
3338 int r = 0;
3339 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
3340
3341 memset(&ssn, 0, sizeof(ssn));
3342
3343 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3344 if (f == NULL)
3345 goto end;
3346 f->protoctx = &ssn;
3347 f->proto = IPPROTO_TCP;
5c01b409 3348 f->alproto = ALPROTO_HTTP;
52195a41
VJ
3349
3350 StreamTcpInitConfig(TRUE);
3351
3352 uint32_t u;
3353 for (u = 0; u < httplen1; u++) {
3354 uint8_t flags = 0;
3355
3356 if (u == 0)
3357 flags = STREAM_TOSERVER|STREAM_START;
3358 else if (u == (httplen1 - 1))
3359 flags = STREAM_TOSERVER|STREAM_EOF;
3360 else
3361 flags = STREAM_TOSERVER;
3362
6530c3d0 3363 FLOWLOCK_WRLOCK(f);
675fa564
GL
3364 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags,
3365 &httpbuf1[u], 1);
52195a41
VJ
3366 if (r != 0) {
3367 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
3368 " 0: ", u, r);
6530c3d0 3369 FLOWLOCK_UNLOCK(f);
52195a41
VJ
3370 goto end;
3371 }
6530c3d0 3372 FLOWLOCK_UNLOCK(f);
52195a41
VJ
3373 }
3374
3375 htp_state = f->alstate;
3376 if (htp_state == NULL) {
3377 printf("no http state: ");
52195a41
VJ
3378 goto end;
3379 }
3380
3381 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3382 htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
3383 if (strcmp(bstr_util_strdup_to_c(h->value), "Victor/1.0")
3384 || tx->request_method_number != HTP_M_POST ||
3385 tx->request_protocol_number != HTP_PROTOCOL_1_0)
3386 {
3387 printf("expected header value: Victor/1.0 and got %s: and expected"
3388 " method: POST and got %s, expected protocol number HTTP/1.0"
3389 " and got: %s \n", bstr_util_strdup_to_c(h->value),
3390 bstr_util_strdup_to_c(tx->request_method),
3391 bstr_util_strdup_to_c(tx->request_protocol));
52195a41
VJ
3392 goto end;
3393 }
e86e27ba 3394 result = 1;
52195a41
VJ
3395end:
3396 if (alp_tctx != NULL)
3397 AppLayerParserThreadCtxFree(alp_tctx);
3398 StreamTcpFreeConfig(TRUE);
52195a41
VJ
3399 UTHFreeFlow(f);
3400 return result;
3401}
3402
2d6cf71d 3403/** \test See how it deals with an incomplete request. */
ab1200fb 3404static int HTPParserTest02(void)
8f1d7503 3405{
e86e27ba 3406 int result = 0;
262a7300 3407 Flow *f = NULL;
2d6cf71d
GS
3408 uint8_t httpbuf1[] = "POST";
3409 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3410 TcpSession ssn;
25a3a5c6 3411 HtpState *http_state = NULL;
8dbf7a0d 3412 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
2d6cf71d 3413
2d6cf71d 3414 memset(&ssn, 0, sizeof(ssn));
262a7300
VJ
3415
3416 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3417 if (f == NULL)
3418 goto end;
3419 f->protoctx = &ssn;
429c6388 3420 f->proto = IPPROTO_TCP;
5c01b409 3421 f->alproto = ALPROTO_HTTP;
2d6cf71d 3422
6a53ab9c 3423 StreamTcpInitConfig(TRUE);
6a53ab9c 3424
6530c3d0 3425 FLOWLOCK_WRLOCK(f);
675fa564
GL
3426 int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
3427 STREAM_TOSERVER | STREAM_START | STREAM_EOF,
3428 httpbuf1,
3429 httplen1);
2d6cf71d
GS
3430 if (r != 0) {
3431 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
6530c3d0 3432 FLOWLOCK_UNLOCK(f);
2d6cf71d
GS
3433 goto end;
3434 }
6530c3d0 3435 FLOWLOCK_UNLOCK(f);
2d6cf71d 3436
262a7300 3437 http_state = f->alstate;
2d6cf71d
GS
3438 if (http_state == NULL) {
3439 printf("no http state: ");
2d6cf71d
GS
3440 goto end;
3441 }
3442
d4d18e31 3443 htp_tx_t *tx = HTPStateGetTx(http_state, 0);
48cf0585 3444 htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
2d6cf71d
GS
3445 if ((tx->request_method) != NULL || h != NULL)
3446 {
48cf0585 3447 printf("expected method NULL, got %s \n", bstr_util_strdup_to_c(tx->request_method));
2d6cf71d
GS
3448 goto end;
3449 }
e86e27ba 3450 result = 1;
2d6cf71d 3451end:
429c6388 3452 if (alp_tctx != NULL)
fdefb65b 3453 AppLayerParserThreadCtxFree(alp_tctx);
6a53ab9c 3454 StreamTcpFreeConfig(TRUE);
262a7300 3455 UTHFreeFlow(f);
2d6cf71d
GS
3456 return result;
3457}
3458
3459/** \test Test case where method is invalid and data is sent in smaller chunks
3460 * and check the response of the parser from HTP library. */
ab1200fb 3461static int HTPParserTest03(void)
8f1d7503 3462{
e86e27ba 3463 int result = 0;
262a7300 3464 Flow *f = NULL;
2d6cf71d
GS
3465 uint8_t httpbuf1[] = "HELLO / HTTP/1.0\r\n";
3466 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3467 TcpSession ssn;
25a3a5c6 3468 HtpState *htp_state = NULL;
2d6cf71d 3469 int r = 0;
8dbf7a0d 3470 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
429c6388 3471
2d6cf71d 3472 memset(&ssn, 0, sizeof(ssn));
262a7300
VJ
3473
3474 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3475 if (f == NULL)
3476 goto end;
3477 f->protoctx = &ssn;
429c6388 3478 f->proto = IPPROTO_TCP;
5c01b409 3479 f->alproto = ALPROTO_HTTP;
2d6cf71d 3480
6a53ab9c 3481 StreamTcpInitConfig(TRUE);
6a53ab9c 3482
2d6cf71d
GS
3483 uint32_t u;
3484 for (u = 0; u < httplen1; u++) {
3485 uint8_t flags = 0;
3486
3487 if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
3488 else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
3489 else flags = STREAM_TOSERVER;
3490
6530c3d0 3491 FLOWLOCK_WRLOCK(f);
675fa564
GL
3492 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags,
3493 &httpbuf1[u], 1);
2d6cf71d
GS
3494 if (r != 0) {
3495 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
3496 " 0: ", u, r);
6530c3d0 3497 FLOWLOCK_UNLOCK(f);
2d6cf71d
GS
3498 goto end;
3499 }
6530c3d0 3500 FLOWLOCK_UNLOCK(f);
2d6cf71d 3501 }
262a7300 3502 htp_state = f->alstate;
2d6cf71d
GS
3503 if (htp_state == NULL) {
3504 printf("no http state: ");
2d6cf71d
GS
3505 goto end;
3506 }
3507
d4d18e31 3508 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
2d6cf71d 3509
48cf0585
AS
3510 htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
3511 if (tx->request_method_number != HTP_M_UNKNOWN ||
3512 h != NULL || tx->request_protocol_number != HTP_PROTOCOL_1_0)
2d6cf71d
GS
3513 {
3514 printf("expected method M_UNKNOWN and got %s: , expected protocol "
48cf0585
AS
3515 "HTTP/1.0 and got %s \n", bstr_util_strdup_to_c(tx->request_method),
3516 bstr_util_strdup_to_c(tx->request_protocol));
2d6cf71d
GS
3517 goto end;
3518 }
e86e27ba 3519 result = 1;
2d6cf71d 3520end:
429c6388 3521 if (alp_tctx != NULL)
fdefb65b 3522 AppLayerParserThreadCtxFree(alp_tctx);
6a53ab9c 3523 StreamTcpFreeConfig(TRUE);
262a7300 3524 UTHFreeFlow(f);
2d6cf71d
GS
3525 return result;
3526}
3527
3528/** \test Test case where invalid data is sent and check the response of the
3529 * parser from HTP library. */
ab1200fb 3530static int HTPParserTest04(void)
8f1d7503 3531{
e86e27ba 3532 int result = 0;
262a7300 3533 Flow *f = NULL;
25a3a5c6 3534 HtpState *htp_state = NULL;
2d6cf71d
GS
3535 uint8_t httpbuf1[] = "World!\r\n";
3536 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3537 TcpSession ssn;
3538 int r = 0;
8dbf7a0d 3539 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
262a7300 3540
2d6cf71d 3541 memset(&ssn, 0, sizeof(ssn));
262a7300
VJ
3542
3543 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3544 if (f == NULL)
3545 goto end;
3546 f->protoctx = &ssn;
429c6388 3547 f->proto = IPPROTO_TCP;
5c01b409 3548 f->alproto = ALPROTO_HTTP;
2d6cf71d 3549
6a53ab9c 3550 StreamTcpInitConfig(TRUE);
6a53ab9c 3551
6530c3d0 3552 FLOWLOCK_WRLOCK(f);
675fa564
GL
3553 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
3554 STREAM_TOSERVER | STREAM_START | STREAM_EOF,
3555 httpbuf1,
3556 httplen1);
2d16abcf 3557 if (r != 0) {
6530c3d0 3558 FLOWLOCK_UNLOCK(f);
2d16abcf
VJ
3559 goto end;
3560 }
6530c3d0 3561 FLOWLOCK_UNLOCK(f);
2d6cf71d 3562
262a7300 3563 htp_state = f->alstate;
2d6cf71d
GS
3564 if (htp_state == NULL) {
3565 printf("no http state: ");
2d6cf71d
GS
3566 goto end;
3567 }
3568
d4d18e31 3569 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
48cf0585
AS
3570 htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
3571 if (tx->request_method_number != HTP_M_UNKNOWN ||
3572 h != NULL || tx->request_protocol_number != HTP_PROTOCOL_0_9)
2d6cf71d
GS
3573 {
3574 printf("expected method M_UNKNOWN and got %s: , expected protocol "
48cf0585
AS
3575 "NULL and got %s \n", bstr_util_strdup_to_c(tx->request_method),
3576 bstr_util_strdup_to_c(tx->request_protocol));
2d6cf71d
GS
3577 goto end;
3578 }
e86e27ba 3579 result = 1;
2d6cf71d 3580end:
429c6388 3581 if (alp_tctx != NULL)
fdefb65b 3582 AppLayerParserThreadCtxFree(alp_tctx);
6a53ab9c 3583 StreamTcpFreeConfig(TRUE);
262a7300 3584 UTHFreeFlow(f);
2d6cf71d
GS
3585 return result;
3586}
3587
3588/** \test Test both sides of a http stream mixed up to see if the HTP parser
3589 * properly parsed them and also keeps them separated. */
ab1200fb 3590static int HTPParserTest05(void)
8f1d7503 3591{
56b1df1b 3592 uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\nContent-Length: 17\r\n\r\n";
2d6cf71d
GS
3593 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3594 uint8_t httpbuf2[] = "Post D";
3595 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
3596 uint8_t httpbuf3[] = "ata is c0oL!";
3597 uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
3598
fc2f7f29 3599 uint8_t httpbuf4[] = "HTTP/1.0 200 OK\r\nServer: VictorServer/1.0\r\n\r\n";
2d6cf71d
GS
3600 uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
3601 uint8_t httpbuf5[] = "post R";
3602 uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
3603 uint8_t httpbuf6[] = "esults are tha bomb!";
3604 uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
2d6cf71d 3605
56b1df1b 3606 TcpSession ssn;
2d6cf71d 3607 memset(&ssn, 0, sizeof(ssn));
262a7300 3608
56b1df1b
VJ
3609 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
3610 FAIL_IF_NULL(alp_tctx);
3611
3612 Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3613 FAIL_IF_NULL(f);
262a7300 3614 f->protoctx = &ssn;
429c6388 3615 f->proto = IPPROTO_TCP;
5c01b409 3616 f->alproto = ALPROTO_HTTP;
2d6cf71d 3617
6a53ab9c 3618 StreamTcpInitConfig(TRUE);
6a53ab9c 3619
675fa564
GL
3620 int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
3621 STREAM_TOSERVER | STREAM_START, httpbuf1,
3622 httplen1);
56b1df1b 3623 FAIL_IF(r != 0);
2d6cf71d 3624
675fa564
GL
3625 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
3626 STREAM_TOCLIENT | STREAM_START, httpbuf4,
429c6388 3627 httplen4);
56b1df1b 3628 FAIL_IF(r != 0);
2d6cf71d 3629
675fa564
GL
3630 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT,
3631 httpbuf5, httplen5);
56b1df1b 3632 FAIL_IF(r != 0);
2d6cf71d 3633
675fa564
GL
3634 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER,
3635 httpbuf2, httplen2);
56b1df1b 3636 FAIL_IF(r != 0);
2d6cf71d 3637
675fa564
GL
3638 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
3639 STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
56b1df1b 3640 FAIL_IF(r != 0);
2d6cf71d 3641
675fa564
GL
3642 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
3643 STREAM_TOCLIENT | STREAM_EOF, httpbuf6, httplen6);
56b1df1b 3644 FAIL_IF(r != 0);
2d6cf71d 3645
56b1df1b
VJ
3646 HtpState *http_state = f->alstate;
3647 FAIL_IF_NULL(http_state);
2d6cf71d 3648
d4d18e31 3649 htp_tx_t *tx = HTPStateGetTx(http_state, 0);
56b1df1b
VJ
3650 FAIL_IF_NULL(tx);
3651 FAIL_IF_NOT(tx->request_method_number == HTP_M_POST);
3652 FAIL_IF_NOT(tx->request_protocol_number == HTP_PROTOCOL_1_0);
3653
48cf0585 3654 htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
56b1df1b 3655 FAIL_IF_NULL(h);
2d6cf71d 3656
56b1df1b
VJ
3657 FAIL_IF_NOT(tx->response_status_number == 200);
3658
3659 AppLayerParserThreadCtxFree(alp_tctx);
6a53ab9c 3660 StreamTcpFreeConfig(TRUE);
262a7300 3661 UTHFreeFlow(f);
56b1df1b 3662 PASS;
2d6cf71d
GS
3663}
3664
fc2f7f29
GS
3665/** \test Test proper chunked encoded response body
3666 */
ab1200fb 3667static int HTPParserTest06(void)
8f1d7503 3668{
fc2f7f29
GS
3669 uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
3670 "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
3671 "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
3672 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3673 uint8_t httpbuf2[] = "HTTP/1.1 200 OK\r\nDate: Sat, 03 Oct 2009 10:16:02 "
3674 "GMT\r\n"
3675 "Server: Apache/1.3.37 (Unix) mod_ssl/2.8.28 "
3676 "OpenSSL/0.9.7a PHP/4.4.7 mod_perl/1.29 "
3677 "FrontPage/5.0.2.2510\r\n"
3678 "X-Powered-By: PHP/4.4.7\r\nTransfer-Encoding: "
3679 "chunked\r\n"
3680 "Content-Type: text/html\r\n\r\n"
56143131 3681 "580\r\n"
fc2f7f29
GS
3682 "W2dyb3VwMV0NCnBob25lMT1wMDB3ODgyMTMxMzAyMTINCmxvZ2lu"
3683 "MT0NCnBhc3N3b3JkMT0NCnBob25lMj1wMDB3ODgyMTMxMzAyMTIN"
3684 "CmxvZ2luMj0NCnBhc3N3b3JkMj0NCnBob25lMz0NCmxvZ2luMz0N"
3685 "CnBhc3N3b3JkMz0NCnBob25lND0NCmxvZ2luND0NCnBhc3N3b3Jk"
3686 "ND0NCnBob25lNT0NCmxvZ2luNT0NCnBhc3N3b3JkNT0NCnBob25l"
3687 "Nj0NCmxvZ2luNj0NCnBhc3N3b3JkNj0NCmNhbGxfdGltZTE9MzIN"
3688 "CmNhbGxfdGltZTI9MjMyDQpkYXlfbGltaXQ9NQ0KbW9udGhfbGlt"
3689 "aXQ9MTUNCltncm91cDJdDQpwaG9uZTE9DQpsb2dpbjE9DQpwYXNz"
3690 "d29yZDE9DQpwaG9uZTI9DQpsb2dpbjI9DQpwYXNzd29yZDI9DQpw"
3691 "aG9uZTM9DQpsb2dpbjM9DQpwYXNzd29yZDM9DQpwaG9uZTQ9DQps"
3692 "b2dpbjQ9DQpwYXNzd29yZDQ9DQpwaG9uZTU9DQpsb2dpbjU9DQpw"
3693 "YXNzd29yZDU9DQpwaG9uZTY9DQpsb2dpbjY9DQpwYXNzd29yZDY9"
3694 "DQpjYWxsX3RpbWUxPQ0KY2FsbF90aW1lMj0NCmRheV9saW1pdD0N"
3695 "Cm1vbnRoX2xpbWl0PQ0KW2dyb3VwM10NCnBob25lMT0NCmxvZ2lu"
3696 "MT0NCnBhc3N3b3JkMT0NCnBob25lMj0NCmxvZ2luMj0NCnBhc3N3"
3697 "b3JkMj0NCnBob25lMz0NCmxvZ2luMz0NCnBhc3N3b3JkMz0NCnBo"
3698 "b25lND0NCmxvZ2luND0NCnBhc3N3b3JkND0NCnBob25lNT0NCmxv"
3699 "Z2luNT0NCnBhc3N3b3JkNT0NCnBob25lNj0NCmxvZ2luNj0NCnBh"
3700 "c3N3b3JkNj0NCmNhbGxfdGltZTE9DQpjYWxsX3RpbWUyPQ0KZGF5"
3701 "X2xpbWl0PQ0KbW9udGhfbGltaXQ9DQpbZ3JvdXA0XQ0KcGhvbmUx"
3702 "PQ0KbG9naW4xPQ0KcGFzc3dvcmQxPQ0KcGhvbmUyPQ0KbG9naW4y"
3703 "PQ0KcGFzc3dvcmQyPQ0KcGhvbmUzPQ0KbG9naW4zPQ0KcGFzc3dv"
3704 "cmQzPQ0KcGhvbmU0PQ0KbG9naW40PQ0KcGFzc3dvcmQ0PQ0KcGhv"
3705 "bmU1PQ0KbG9naW41PQ0KcGFzc3dvcmQ1PQ0KcGhvbmU2PQ0KbG9n"
3706 "aW42PQ0KcGFzc3dvcmQ2PQ0KY2FsbF90aW1lMT0NCmNhbGxfdGlt"
3707 "ZTI9DQpkYXlfbGltaXQ9DQptb250aF9saW1pdD0NCltmaWxlc10N"
3708 "Cmxpbms9aHR0cDovLzIwOS4yMDUuMTk2LjE2L2xkL2dldGJvdC5w"
56143131 3709 "aHA=\r\n0\r\n\r\n";
fc2f7f29
GS
3710 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
3711 TcpSession ssn;
56b1df1b 3712
8dbf7a0d 3713 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
56b1df1b 3714 FAIL_IF_NULL(alp_tctx);
fc2f7f29 3715
fc2f7f29 3716 memset(&ssn, 0, sizeof(ssn));
78e15ea7 3717
56b1df1b
VJ
3718 Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3719 FAIL_IF_NULL(f);
262a7300 3720 f->protoctx = &ssn;
429c6388 3721 f->proto = IPPROTO_TCP;
5c01b409 3722 f->alproto = ALPROTO_HTTP;
fc2f7f29 3723
6a53ab9c 3724 StreamTcpInitConfig(TRUE);
6a53ab9c 3725
675fa564
GL
3726 int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
3727 STREAM_TOSERVER | STREAM_START, httpbuf1,
3728 httplen1);
56b1df1b 3729 FAIL_IF(r != 0);
675fa564
GL
3730 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
3731 STREAM_TOCLIENT | STREAM_START, httpbuf2,
429c6388 3732 httplen2);
56b1df1b 3733 FAIL_IF(r != 0);
fc2f7f29 3734
56b1df1b
VJ
3735 HtpState *http_state = f->alstate;
3736 FAIL_IF_NULL(http_state);
fc2f7f29 3737
d4d18e31 3738 htp_tx_t *tx = HTPStateGetTx(http_state, 0);
56b1df1b
VJ
3739 FAIL_IF_NULL(tx);
3740
3741 FAIL_IF(tx->request_method_number != HTP_M_GET);
3742 FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1);
3743
3744 FAIL_IF(tx->response_status_number != 200);
3745 FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1);
3746
48cf0585 3747 htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
56b1df1b 3748 FAIL_IF_NULL(h);
fc2f7f29 3749
56b1df1b 3750 AppLayerParserThreadCtxFree(alp_tctx);
6a53ab9c 3751 StreamTcpFreeConfig(TRUE);
262a7300 3752 UTHFreeFlow(f);
56b1df1b 3753 PASS;
fc2f7f29 3754}
a9cdd2bb 3755
15ce8503
VJ
3756/** \test
3757 */
ab1200fb 3758static int HTPParserTest07(void)
8f1d7503 3759{
36917c7d 3760 int result = 0;
262a7300 3761 Flow *f = NULL;
15ce8503
VJ
3762 uint8_t httpbuf1[] = "GET /awstats.pl?/migratemigrate%20=%20| HTTP/1.0\r\n\r\n";
3763 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3764 TcpSession ssn;
15ce8503
VJ
3765 HtpState *htp_state = NULL;
3766 int r = 0;
8dbf7a0d 3767 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
262a7300 3768
15ce8503 3769 memset(&ssn, 0, sizeof(ssn));
262a7300
VJ
3770
3771 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3772 if (f == NULL)
3773 goto end;
3774 f->protoctx = &ssn;
429c6388 3775 f->proto = IPPROTO_TCP;
5c01b409 3776 f->alproto = ALPROTO_HTTP;
15ce8503
VJ
3777
3778 StreamTcpInitConfig(TRUE);
15ce8503
VJ
3779
3780 uint32_t u;
3781 for (u = 0; u < httplen1; u++) {
3782 uint8_t flags = 0;
3783
36917c7d
VJ
3784 if (u == 0)
3785 flags = STREAM_TOSERVER|STREAM_START;
3786 else if (u == (httplen1 - 1))
3787 flags = STREAM_TOSERVER|STREAM_EOF;
3788 else
3789 flags = STREAM_TOSERVER;
15ce8503 3790
6530c3d0 3791 FLOWLOCK_WRLOCK(f);
675fa564
GL
3792 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags,
3793 &httpbuf1[u], 1);
15ce8503
VJ
3794 if (r != 0) {
3795 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
3796 " 0: ", u, r);
6530c3d0 3797 FLOWLOCK_UNLOCK(f);
15ce8503
VJ
3798 goto end;
3799 }
6530c3d0 3800 FLOWLOCK_UNLOCK(f);
15ce8503
VJ
3801 }
3802
262a7300 3803 htp_state = f->alstate;
15ce8503
VJ
3804 if (htp_state == NULL) {
3805 printf("no http state: ");
15ce8503
VJ
3806 goto end;
3807 }
3808
36917c7d
VJ
3809 uint8_t ref[] = "/awstats.pl?/migratemigrate = |";
3810 size_t reflen = sizeof(ref) - 1;
3811
d4d18e31 3812 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
48cf0585
AS
3813 if (tx == NULL)
3814 goto end;
3815 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
3816 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
3817 if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
0625d542 3818 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
48cf0585 3819 (uintmax_t)reflen,
d5fdfa4b 3820 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
36917c7d
VJ
3821 goto end;
3822 }
3823
48cf0585
AS
3824 if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref,
3825 bstr_len(tx_ud->request_uri_normalized)) != 0)
36917c7d 3826 {
0625d542 3827 printf("normalized uri \"");
48cf0585 3828 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
0625d542
VJ
3829 printf("\" != \"");
3830 PrintRawUriFp(stdout, ref, reflen);
3831 printf("\": ");
36917c7d
VJ
3832 goto end;
3833 }
15ce8503
VJ
3834 }
3835
36917c7d 3836 result = 1;
15ce8503 3837end:
429c6388 3838 if (alp_tctx != NULL)
fdefb65b 3839 AppLayerParserThreadCtxFree(alp_tctx);
15ce8503 3840 StreamTcpFreeConfig(TRUE);
262a7300 3841 UTHFreeFlow(f);
15ce8503
VJ
3842 return result;
3843}
3844
a9cdd2bb
BR
3845#include "conf-yaml-loader.h"
3846
326047ee
VJ
3847/** \test Abort
3848 */
ab1200fb 3849static int HTPParserTest08(void)
8f1d7503 3850{
326047ee 3851 int result = 0;
262a7300 3852 Flow *f = NULL;
326047ee
VJ
3853 uint8_t httpbuf1[] = "GET /secondhouse/image/js/\%ce\%de\%ce\%fd_RentCity.js?v=2011.05.02 HTTP/1.0\r\n\r\n";
3854 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3855 TcpSession ssn;
8dbf7a0d 3856 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
326047ee
VJ
3857
3858 char input[] = "\
3859%YAML 1.1\n\
3860---\n\
3861libhtp:\n\
3862\n\
3863 default-config:\n\
3864 personality: IDS\n\
3865";
3866
3867 ConfCreateContextBackup();
3868 ConfInit();
63f6de58
VJ
3869 HtpConfigCreateBackup();
3870
326047ee
VJ
3871 ConfYamlLoadString(input, strlen(input));
3872 HTPConfigure();
3873
3874 HtpState *htp_state = NULL;
3875 int r = 0;
326047ee 3876 memset(&ssn, 0, sizeof(ssn));
262a7300
VJ
3877
3878 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3879 if (f == NULL)
3880 goto end;
3881 f->protoctx = &ssn;
429c6388 3882 f->proto = IPPROTO_TCP;
5c01b409 3883 f->alproto = ALPROTO_HTTP;
326047ee
VJ
3884
3885 StreamTcpInitConfig(TRUE);
326047ee
VJ
3886
3887 uint8_t flags = 0;
3888 flags = STREAM_TOSERVER|STREAM_START|STREAM_EOF;
3889
6530c3d0 3890 FLOWLOCK_WRLOCK(f);
675fa564
GL
3891 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, httpbuf1,
3892 httplen1);
326047ee
VJ
3893 if (r != 0) {
3894 printf("toserver chunk returned %" PRId32 ", expected"
3895 " 0: ", r);
3896 result = 0;
6530c3d0 3897 FLOWLOCK_UNLOCK(f);
326047ee
VJ
3898 goto end;
3899 }
6530c3d0 3900 FLOWLOCK_UNLOCK(f);
326047ee 3901
262a7300 3902 htp_state = f->alstate;
326047ee
VJ
3903 if (htp_state == NULL) {
3904 printf("no http state: ");
3905 result = 0;
3906 goto end;
3907 }
3908
d4d18e31 3909 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
48cf0585
AS
3910 if (tx == NULL)
3911 goto end;
3912 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
3913 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
3914 //printf("uri %s\n", bstr_util_strdup_to_c(tx->request_uri_normalized));
3915 PrintRawDataFp(stdout, bstr_ptr(tx_ud->request_uri_normalized),
3916 bstr_len(tx_ud->request_uri_normalized));
326047ee
VJ
3917 }
3918
3919 result = 1;
3920end:
429c6388 3921 if (alp_tctx != NULL)
fdefb65b 3922 AppLayerParserThreadCtxFree(alp_tctx);
326047ee 3923 StreamTcpFreeConfig(TRUE);
63f6de58 3924 HTPFreeConfig();
326047ee
VJ
3925 ConfDeInit();
3926 ConfRestoreContextBackup();
63f6de58 3927 HtpConfigRestoreBackup();
262a7300 3928 UTHFreeFlow(f);
326047ee
VJ
3929 return result;
3930}
3931
3932/** \test Abort
3933 */
ab1200fb 3934static int HTPParserTest09(void)
8f1d7503 3935{
326047ee 3936 int result = 0;
262a7300 3937 Flow *f = NULL;
326047ee
VJ
3938 uint8_t httpbuf1[] = "GET /secondhouse/image/js/\%ce\%de\%ce\%fd_RentCity.js?v=2011.05.02 HTTP/1.0\r\n\r\n";
3939 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3940 TcpSession ssn;
8dbf7a0d 3941 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
326047ee
VJ
3942
3943 char input[] = "\
3944%YAML 1.1\n\
3945---\n\
3946libhtp:\n\
3947\n\
3948 default-config:\n\
3949 personality: Apache_2_2\n\
3950";
3951
3952 ConfCreateContextBackup();
3953 ConfInit();
63f6de58
VJ
3954 HtpConfigCreateBackup();
3955
326047ee
VJ
3956 ConfYamlLoadString(input, strlen(input));
3957 HTPConfigure();
3958
3959 HtpState *htp_state = NULL;
3960 int r = 0;
262a7300 3961
326047ee 3962 memset(&ssn, 0, sizeof(ssn));
262a7300
VJ
3963
3964 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3965 if (f == NULL)
3966 goto end;
3967 f->protoctx = &ssn;
429c6388 3968 f->proto = IPPROTO_TCP;
5c01b409 3969 f->alproto = ALPROTO_HTTP;
326047ee
VJ
3970
3971 StreamTcpInitConfig(TRUE);
326047ee
VJ
3972
3973 uint8_t flags = 0;
3974 flags = STREAM_TOSERVER|STREAM_START|STREAM_EOF;
3975
6530c3d0 3976 FLOWLOCK_WRLOCK(f);
675fa564
GL
3977 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, httpbuf1,
3978 httplen1);
326047ee
VJ
3979 if (r != 0) {
3980 printf("toserver chunk returned %" PRId32 ", expected"
3981 " 0: ", r);
6530c3d0 3982 FLOWLOCK_UNLOCK(f);
326047ee
VJ
3983 goto end;
3984 }
6530c3d0 3985 FLOWLOCK_UNLOCK(f);
326047ee 3986
262a7300 3987 htp_state = f->alstate;
326047ee
VJ
3988 if (htp_state == NULL) {
3989 printf("no http state: ");
326047ee
VJ
3990 goto end;
3991 }
3992
d4d18e31 3993 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
48cf0585
AS
3994 if (tx == NULL)
3995 goto end;
3996 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
3997 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
3998 //printf("uri %s\n", bstr_util_strdup_to_c(tx->request_uri_normalized));
3999 PrintRawDataFp(stdout, bstr_ptr(tx_ud->request_uri_normalized),
4000 bstr_len(tx_ud->request_uri_normalized));
326047ee
VJ
4001 }
4002
4003 result = 1;
4004end:
429c6388 4005 if (alp_tctx != NULL)
fdefb65b 4006 AppLayerParserThreadCtxFree(alp_tctx);
326047ee 4007 StreamTcpFreeConfig(TRUE);
63f6de58 4008 HTPFreeConfig();
326047ee
VJ
4009 ConfDeInit();
4010 ConfRestoreContextBackup();
63f6de58 4011 HtpConfigRestoreBackup();
262a7300 4012 UTHFreeFlow(f);
326047ee
VJ
4013 return result;
4014}
4015
f2f8dfd8
VJ
4016/** \test Host:www.google.com <- missing space between name:value (rfc violation)
4017 */
ab1200fb 4018static int HTPParserTest10(void)
8f1d7503 4019{
f2f8dfd8
VJ
4020 int result = 0;
4021 Flow *f = NULL;
4022 uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nHost:www.google.com\r\n\r\n";
4023 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4024 TcpSession ssn;
4025 HtpState *htp_state = NULL;
4026 int r = 0;
8dbf7a0d 4027 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
f2f8dfd8
VJ
4028
4029 memset(&ssn, 0, sizeof(ssn));
4030
4031 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
4032 if (f == NULL)
4033 goto end;
4034 f->protoctx = &ssn;
429c6388 4035 f->proto = IPPROTO_TCP;
5c01b409 4036 f->alproto = ALPROTO_HTTP;
f2f8dfd8
VJ
4037
4038 StreamTcpInitConfig(TRUE);
4039
4040 uint32_t u;
4041 for (u = 0; u < httplen1; u++) {
4042 uint8_t flags = 0;
4043
4044 if (u == 0)
4045 flags = STREAM_TOSERVER|STREAM_START;
4046 else if (u == (httplen1 - 1))
4047 flags = STREAM_TOSERVER|STREAM_EOF;
4048 else
4049 flags = STREAM_TOSERVER;
4050
6530c3d0 4051 FLOWLOCK_WRLOCK(f);
675fa564
GL
4052 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags,
4053 &httpbuf1[u], 1);
f2f8dfd8
VJ
4054 if (r != 0) {
4055 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
4056 " 0: ", u, r);
6530c3d0 4057 FLOWLOCK_UNLOCK(f);
f2f8dfd8
VJ
4058 goto end;
4059 }
6530c3d0 4060 FLOWLOCK_UNLOCK(f);
f2f8dfd8
VJ
4061 }
4062
4063 htp_state = f->alstate;
4064 if (htp_state == NULL) {
4065 printf("no http state: ");
4066 goto end;
4067 }
4068
d4d18e31 4069 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
48cf0585 4070 htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
f2f8dfd8
VJ
4071 if (h == NULL) {
4072 goto end;
4073 }
4074
48cf0585 4075 char *name = bstr_util_strdup_to_c(h->name);
f2f8dfd8
VJ
4076 if (name == NULL) {
4077 goto end;
4078 }
4079
4080 if (strcmp(name, "Host") != 0) {
4081 printf("header name not \"Host\", instead \"%s\": ", name);
4082 free(name);
4083 goto end;
4084 }
4085 free(name);
4086
48cf0585 4087 char *value = bstr_util_strdup_to_c(h->value);
f2f8dfd8
VJ
4088 if (value == NULL) {
4089 goto end;
4090 }
4091
4092 if (strcmp(value, "www.google.com") != 0) {
4093 printf("header value not \"www.google.com\", instead \"%s\": ", value);
4094 free(value);
4095 goto end;
4096 }
4097 free(value);
4098
4099 result = 1;
4100end:
429c6388 4101 if (alp_tctx != NULL)
fdefb65b 4102 AppLayerParserThreadCtxFree(alp_tctx);
f2f8dfd8 4103 StreamTcpFreeConfig(TRUE);
f2f8dfd8
VJ
4104 UTHFreeFlow(f);
4105 return result;
4106}
4107
ab3fcb01
VJ
4108/** \test double encoding in path
4109 */
8f1d7503
KS
4110static int HTPParserTest11(void)
4111{
ab3fcb01
VJ
4112 int result = 0;
4113 Flow *f = NULL;
4114 uint8_t httpbuf1[] = "GET /%2500 HTTP/1.0\r\n\r\n";
4115 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4116 TcpSession ssn;
4117 HtpState *htp_state = NULL;
4118 int r = 0;
8dbf7a0d 4119 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
ab3fcb01
VJ
4120
4121 memset(&ssn, 0, sizeof(ssn));
4122
4123 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
4124 if (f == NULL)
4125 goto end;
4126 f->protoctx = &ssn;
429c6388 4127 f->proto = IPPROTO_TCP;
5c01b409 4128 f->alproto = ALPROTO_HTTP;
ab3fcb01
VJ
4129
4130 StreamTcpInitConfig(TRUE);
4131
4132 uint32_t u;
4133 for (u = 0; u < httplen1; u++) {
4134 uint8_t flags = 0;
4135
4136 if (u == 0)
4137 flags = STREAM_TOSERVER|STREAM_START;
4138 else if (u == (httplen1 - 1))
4139 flags = STREAM_TOSERVER|STREAM_EOF;
4140 else
4141 flags = STREAM_TOSERVER;
4142
6530c3d0 4143 FLOWLOCK_WRLOCK(f);
675fa564
GL
4144 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags,
4145 &httpbuf1[u], 1);
ab3fcb01
VJ
4146 if (r != 0) {
4147 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
4148 " 0: ", u, r);
6530c3d0 4149 FLOWLOCK_UNLOCK(f);
ab3fcb01
VJ
4150 goto end;
4151 }
6530c3d0 4152 FLOWLOCK_UNLOCK(f);
ab3fcb01
VJ
4153 }
4154
4155 htp_state = f->alstate;
4156 if (htp_state == NULL) {
4157 printf("no http state: ");
4158 goto end;
4159 }
4160
d4d18e31 4161 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
48cf0585
AS
4162 if (tx == NULL)
4163 goto end;
4164 HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
4165 if (tx != NULL && tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
4166 if (4 != bstr_len(tx_ud->request_uri_normalized)) {
ab3fcb01 4167 printf("normalized uri len should be 2, is %"PRIuMAX,
d5fdfa4b 4168 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
ab3fcb01
VJ
4169 goto end;
4170 }
4171
48cf0585
AS
4172 if (bstr_ptr(tx_ud->request_uri_normalized)[0] != '/' ||
4173 bstr_ptr(tx_ud->request_uri_normalized)[1] != '%' ||
4174 bstr_ptr(tx_ud->request_uri_normalized)[2] != '0' ||
4175 bstr_ptr(tx_ud->request_uri_normalized)[3] != '0')
ab3fcb01
VJ
4176 {
4177 printf("normalized uri \"");
48cf0585 4178 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
ab3fcb01
VJ
4179 printf("\": ");
4180 goto end;
4181 }
4182 }
4183
4184 result = 1;
4185end:
429c6388 4186 if (alp_tctx != NULL)
fdefb65b 4187 AppLayerParserThreadCtxFree(alp_tctx);
ab3fcb01 4188 StreamTcpFreeConfig(TRUE);
ab3fcb01
VJ
4189 UTHFreeFlow(f);
4190 return result;
4191}
4192
4193/** \test double encoding in query
4194 */
8f1d7503
KS
4195static int HTPParserTest12(void)
4196{
ab3fcb01
VJ
4197 int result = 0;
4198 Flow *f = NULL;
4199 uint8_t httpbuf1[] = "GET /?a=%2500 HTTP/1.0\r\n\r\n";
4200 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4201 TcpSession ssn;
4202 HtpState *htp_state = NULL;
4203 int r = 0;
8dbf7a0d 4204 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
ab3fcb01
VJ
4205
4206 memset(&ssn, 0, sizeof(ssn));
4207
4208 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
4209 if (f == NULL)
4210 goto end;
4211 f->protoctx = &ssn;
429c6388 4212 f->proto = IPPROTO_TCP;
5c01b409 4213 f->alproto = ALPROTO_HTTP;
ab3fcb01
VJ
4214
4215 StreamTcpInitConfig(TRUE);
4216
4217 uint32_t u;
4218 for (u = 0; u < httplen1; u++) {
4219 uint8_t flags = 0;
4220
4221 if (u == 0)
4222 flags = STREAM_TOSERVER|STREAM_START;
4223 else if (u == (httplen1 - 1))
4224 flags = STREAM_TOSERVER|STREAM_EOF;
4225 else
4226 flags = STREAM_TOSERVER;
4227
6530c3d0 4228 FLOWLOCK_WRLOCK(f);
675fa564
GL
4229 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags,
4230 &httpbuf1[u], 1);
ab3fcb01
VJ
4231 if (r != 0) {
4232 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
4233 " 0: ", u, r);
6530c3d0 4234 FLOWLOCK_UNLOCK(f);
ab3fcb01
VJ
4235 goto end;
4236 }
6530c3d0 4237 FLOWLOCK_UNLOCK(f);
ab3fcb01
VJ
4238 }
4239
4240 htp_state = f->alstate;
4241 if (htp_state == NULL) {
4242 printf("no http state: ");
4243 goto end;
4244 }
4245
d4d18e31 4246 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
48cf0585
AS
4247 if (tx == NULL)
4248 goto end;
4249 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
4250 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
4251 if (7 != bstr_len(tx_ud->request_uri_normalized)) {
ab3fcb01 4252 printf("normalized uri len should be 5, is %"PRIuMAX,
d5fdfa4b 4253 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
ab3fcb01
VJ
4254 goto end;
4255 }
4256
48cf0585
AS
4257 if (bstr_ptr(tx_ud->request_uri_normalized)[0] != '/' ||
4258 bstr_ptr(tx_ud->request_uri_normalized)[1] != '?' ||
4259 bstr_ptr(tx_ud->request_uri_normalized)[2] != 'a' ||
4260 bstr_ptr(tx_ud->request_uri_normalized)[3] != '=' ||
4261 bstr_ptr(tx_ud->request_uri_normalized)[4] != '%' ||
4262 bstr_ptr(tx_ud->request_uri_normalized)[5] != '0' ||
4263 bstr_ptr(tx_ud->request_uri_normalized)[6] != '0')
ab3fcb01
VJ
4264 {
4265 printf("normalized uri \"");
48cf0585 4266 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
ab3fcb01
VJ
4267 printf("\": ");
4268 goto end;
4269 }
4270 }
4271
4272 result = 1;
429c6388
AS
4273 end:
4274 if (alp_tctx != NULL)
fdefb65b 4275 AppLayerParserThreadCtxFree(alp_tctx);
ab3fcb01 4276 StreamTcpFreeConfig(TRUE);
ab3fcb01
VJ
4277 UTHFreeFlow(f);
4278 return result;
4279}
4280
0c98980e
VJ
4281/** \test Host:www.google.com0dName: Value0d0a <- missing space between name:value (rfc violation)
4282 */
ab1200fb 4283static int HTPParserTest13(void)
8f1d7503 4284{
0c98980e
VJ
4285 int result = 0;
4286 Flow *f = NULL;
4287 uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nHost:www.google.com\rName: Value\r\n\r\n";
4288 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4289 TcpSession ssn;
4290 HtpState *htp_state = NULL;
4291 int r = 0;
8dbf7a0d 4292 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
0c98980e
VJ
4293
4294 memset(&ssn, 0, sizeof(ssn));
4295
4296 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
4297 if (f == NULL)
4298 goto end;
4299 f->protoctx = &ssn;
429c6388 4300 f->proto = IPPROTO_TCP;
5c01b409 4301 f->alproto = ALPROTO_HTTP;
0c98980e
VJ
4302
4303 StreamTcpInitConfig(TRUE);
4304
4305 uint32_t u;
4306 for (u = 0; u < httplen1; u++) {
4307 uint8_t flags = 0;
4308
4309 if (u == 0)
4310 flags = STREAM_TOSERVER|STREAM_START;
4311 else if (u == (httplen1 - 1))
4312 flags = STREAM_TOSERVER|STREAM_EOF;
4313 else
4314 flags = STREAM_TOSERVER;
4315
6530c3d0 4316 FLOWLOCK_WRLOCK(f);
675fa564
GL
4317 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags,
4318 &httpbuf1[u], 1);
0c98980e
VJ
4319 if (r != 0) {
4320 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
4321 " 0: ", u, r);
6530c3d0 4322 FLOWLOCK_UNLOCK(f);
0c98980e
VJ
4323 goto end;
4324 }
6530c3d0 4325 FLOWLOCK_UNLOCK(f);
0c98980e
VJ
4326 }
4327
4328 htp_state = f->alstate;
4329 if (htp_state == NULL) {
4330 printf("no http state: ");
4331 goto end;
4332 }
4333
d4d18e31 4334 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
48cf0585 4335 htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
0c98980e
VJ
4336 if (h == NULL) {
4337 goto end;
4338 }
4339
48cf0585 4340 char *name = bstr_util_strdup_to_c(h->name);
0c98980e
VJ
4341 if (name == NULL) {
4342 goto end;
4343 }
4344
4345 if (strcmp(name, "Host") != 0) {
4346 printf("header name not \"Host\", instead \"%s\": ", name);
4347 free(name);
4348 goto end;
4349 }
4350 free(name);
4351
48cf0585 4352 char *value = bstr_util_strdup_to_c(h->value);
0c98980e
VJ
4353 if (value == NULL) {
4354 goto end;
4355 }
4356
4357 if (strcmp(value, "www.google.com\rName: Value") != 0) {
4358 printf("header value not \"www.google.com\", instead \"");
4359 PrintRawUriFp(stdout, (uint8_t *)value, strlen(value));
4360 printf("\": ");
4361 free(value);
4362 goto end;
4363 }
4364 free(value);
4365
4366 result = 1;
4367end:
429c6388 4368 if (alp_tctx != NULL)
fdefb65b 4369 AppLayerParserThreadCtxFree(alp_tctx);
0c98980e 4370 StreamTcpFreeConfig(TRUE);
0c98980e
VJ
4371 UTHFreeFlow(f);
4372 return result;
4373}
4374
a9cdd2bb 4375/** \test Test basic config */
ab1200fb 4376static int HTPParserConfigTest01(void)
a9cdd2bb
BR
4377{
4378 int ret = 0;
4379 char input[] = "\
4380%YAML 1.1\n\
4381---\n\
4382libhtp:\n\
4383\n\
4384 default-config:\n\
4385 personality: IDS\n\
4386\n\
4387 server-config:\n\
4388\n\
4389 - apache-tomcat:\n\
4390 address: [192.168.1.0/24, 127.0.0.0/8, \"::1\"]\n\
4391 personality: Tomcat_6_0\n\
4392\n\
4393 - iis7:\n\
4394 address: \n\
4395 - 192.168.0.0/24\n\
4396 - 192.168.10.0/24\n\
4397 personality: IIS_7_0\n\
4398";
4399
4400 ConfCreateContextBackup();
4401 ConfInit();
4402
4403 ConfYamlLoadString(input, strlen(input));
4404
4405 ConfNode *outputs;
4406 outputs = ConfGetNode("libhtp.default-config.personality");
4407 if (outputs == NULL) {
4408 goto end;
4409 }
4410
4411 outputs = ConfGetNode("libhtp.server-config");
4412 if (outputs == NULL) {
4413 goto end;
4414 }
4415
4416 ConfNode *node = TAILQ_FIRST(&outputs->head);
4417 if (node == NULL) {
4418 goto end;
4419 }
4420 if (strcmp(node->name, "0") != 0) {
4421 goto end;
4422 }
4423 node = TAILQ_FIRST(&node->head);
4424 if (node == NULL) {
4425 goto end;
4426 }
4427 if (strcmp(node->name, "apache-tomcat") != 0) {
4428 goto end;
4429 }
4430
4431 int i = 0;
4432 ConfNode *n;
4433
4434 ConfNode *node2 = ConfNodeLookupChild(node, "personality");
4435 if (node2 == NULL) {
4436 goto end;
4437 }
4438 if (strcmp(node2->val, "Tomcat_6_0") != 0) {
4439 goto end;
4440 }
4441
4442 node = ConfNodeLookupChild(node, "address");
4443 if (node == NULL) {
4444 goto end;
4445 }
4446 TAILQ_FOREACH(n, &node->head, next) {
4447 if (n == NULL) {
4448 goto end;
4449 }
4450
4451 switch(i) {
4452 case 0:
4453 if (strcmp(n->name, "0") != 0) {
4454 goto end;
4455 }
4456 if (strcmp(n->val, "192.168.1.0/24") != 0) {
4457 goto end;
4458 }
4459 break;
4460 case 1:
4461 if (strcmp(n->name, "1") != 0) {
4462 goto end;
4463 }
4464 if (strcmp(n->val, "127.0.0.0/8") != 0) {
4465 goto end;
4466 }
4467 break;
4468 case 2:
4469 if (strcmp(n->name, "2") != 0) {
4470 goto end;
4471 }
4472 if (strcmp(n->val, "::1") != 0) {
4473 goto end;
4474 }
4475 break;
4476 default:
4477 goto end;
4478 }
4479 i++;
4480 }
4481
4482 outputs = ConfGetNode("libhtp.server-config");
4483 if (outputs == NULL) {
4484 goto end;
4485 }
4486
4487 node = TAILQ_FIRST(&outputs->head);
4488 node = TAILQ_NEXT(node, next);
4489 if (node == NULL) {
4490 goto end;
4491 }
4492 if (strcmp(node->name, "1") != 0) {
4493 goto end;
4494 }
4495 node = TAILQ_FIRST(&node->head);
4496 if (node == NULL) {
4497 goto end;
4498 }
4499 if (strcmp(node->name, "iis7") != 0) {
4500 goto end;
4501 }
4502
4503 node2 = ConfNodeLookupChild(node, "personality");
4504 if (node2 == NULL) {
4505 goto end;
4506 }
4507 if (strcmp(node2->val, "IIS_7_0") != 0) {
4508 goto end;
4509 }
4510
4511 node = ConfNodeLookupChild(node, "address");
4512 if (node == NULL) {
4513 goto end;
4514 }
4515
4516 i = 0;
4517 TAILQ_FOREACH(n, &node->head, next) {
4518 if (n == NULL) {
4519 goto end;
4520 }
4521
4522 switch(i) {
4523 case 0:
4524 if (strcmp(n->name, "0") != 0) {
4525 goto end;
4526 }
4527 if (strcmp(n->val, "192.168.0.0/24") != 0) {
4528 goto end;
4529 }
4530 break;
4531 case 1:
4532 if (strcmp(n->name, "1") != 0) {
4533 goto end;
4534 }
4535 if (strcmp(n->val, "192.168.10.0/24") != 0) {
4536 goto end;
4537 }
4538 break;
4539 default:
4540 goto end;
4541 }
4542 i++;
4543 }
4544
4545 ret = 1;
4546
4547end:
4548 ConfDeInit();
4549 ConfRestoreContextBackup();
4550
4551 return ret;
4552}
4553
4554/** \test Test config builds radix correctly */
ab1200fb 4555static int HTPParserConfigTest02(void)
a9cdd2bb
BR
4556{
4557 int ret = 0;
4558 char input[] = "\
4559%YAML 1.1\n\
4560---\n\
4561libhtp:\n\
4562\n\
4563 default-config:\n\
4564 personality: IDS\n\
4565\n\
4566 server-config:\n\
4567\n\
4568 - apache-tomcat:\n\
4569 address: [192.168.1.0/24, 127.0.0.0/8, \"::1\"]\n\
4570 personality: Tomcat_6_0\n\
4571\n\
4572 - iis7:\n\
4573 address: \n\
4574 - 192.168.0.0/24\n\
4575 - 192.168.10.0/24\n\
4576 personality: IIS_7_0\n\
4577";
4578
4579 ConfCreateContextBackup();
4580 ConfInit();
5c6a65dc 4581 HtpConfigCreateBackup();
a9cdd2bb
BR
4582
4583 ConfYamlLoadString(input, strlen(input));
4584
4585 HTPConfigure();
4586
4587 if (cfglist.cfg == NULL) {
4588 printf("No default config created.\n");
4589 goto end;
4590 }
4591
4592 if (cfgtree == NULL) {
4593 printf("No config tree created.\n");
4594 goto end;
4595 }
4596
a9cdd2bb
BR
4597 htp_cfg_t *htp = cfglist.cfg;
4598 uint8_t buf[128];
4599 const char *addr;
d0a26c6a 4600 void *user_data = NULL;
a9cdd2bb
BR
4601
4602 addr = "192.168.10.42";
4603 if (inet_pton(AF_INET, addr, buf) == 1) {
d0a26c6a
VJ
4604 (void)SCRadixFindKeyIPV4BestMatch(buf, cfgtree, &user_data);
4605 if (user_data != NULL) {
4606 HTPCfgRec *htp_cfg_rec = user_data;
4607 htp = htp_cfg_rec->cfg;
4608 SCLogDebug("LIBHTP using config: %p", htp);
69a4fee7 4609 }
a9cdd2bb
BR
4610 if (htp == NULL) {
4611 printf("Could not get config for: %s\n", addr);
4612 goto end;
4613 }
4614 }
4615 else {
4616 printf("Failed to parse address: %s\n", addr);
4617 goto end;
4618 }
4619
d0a26c6a 4620 user_data = NULL;
a9cdd2bb
BR
4621 addr = "::1";
4622 if (inet_pton(AF_INET6, addr, buf) == 1) {
d0a26c6a
VJ
4623 (void)SCRadixFindKeyIPV6BestMatch(buf, cfgtree, &user_data);
4624 if (user_data != NULL) {
4625 HTPCfgRec *htp_cfg_rec = user_data;
4626 htp = htp_cfg_rec->cfg;
4627 SCLogDebug("LIBHTP using config: %p", htp);
69a4fee7 4628 }
a9cdd2bb
BR
4629 if (htp == NULL) {
4630 printf("Could not get config for: %s\n", addr);
4631 goto end;
4632 }
4633 }
4634 else {
4635 printf("Failed to parse address: %s\n", addr);
4636 goto end;
4637 }
4638
4639 ret = 1;
4640
4641end:
5c6a65dc 4642 HTPFreeConfig();
a9cdd2bb
BR
4643 ConfDeInit();
4644 ConfRestoreContextBackup();
5c6a65dc 4645 HtpConfigRestoreBackup();
a9cdd2bb
BR
4646
4647 return ret;
4648}
4649
4650/** \test Test traffic is handled by the correct htp config */
ab1200fb 4651static int HTPParserConfigTest03(void)
a9cdd2bb
BR
4652{
4653 int result = 1;
262a7300 4654 Flow *f = NULL;
a9cdd2bb
BR
4655 uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost"
4656 " Data is c0oL!";
4657 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4658 TcpSession ssn;
8dbf7a0d 4659 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
a9cdd2bb
BR
4660
4661 HtpState *htp_state = NULL;
4662 int r = 0;
4663 char input[] = "\
4664%YAML 1.1\n\
4665---\n\
4666libhtp:\n\
4667\n\
4668 default-config:\n\
4669 personality: IDS\n\
4670\n\
4671 server-config:\n\
4672\n\
4673 - apache-tomcat:\n\
4674 address: [192.168.1.0/24, 127.0.0.0/8, \"::1\"]\n\
4675 personality: Tomcat_6_0\n\
4676\n\
4677 - iis7:\n\
4678 address: \n\
4679 - 192.168.0.0/24\n\
4680 - 192.168.10.0/24\n\
4681 personality: IIS_7_0\n\
4682";
4683
4684 ConfCreateContextBackup();
4685 ConfInit();
5c6a65dc 4686 HtpConfigCreateBackup();
a9cdd2bb
BR
4687
4688 ConfYamlLoadString(input, strlen(input));
4689
4690 HTPConfigure();
4691
ab1200fb 4692 const char *addr = "192.168.10.42";
a9cdd2bb 4693
a9cdd2bb 4694 memset(&ssn, 0, sizeof(ssn));
262a7300
VJ
4695
4696 f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4697 if (f == NULL)
4698 goto end;
4699 f->protoctx = &ssn;
429c6388 4700 f->proto = IPPROTO_TCP;
5c01b409 4701 f->alproto = ALPROTO_HTTP;
a9cdd2bb 4702
a9cdd2bb 4703 htp_cfg_t *htp = cfglist.cfg;
262a7300 4704
d0a26c6a
VJ
4705 void *user_data = NULL;
4706 (void)SCRadixFindKeyIPV4BestMatch((uint8_t *)f->dst.addr_data32, cfgtree, &user_data);
4707 if (user_data != NULL) {
4708 HTPCfgRec *htp_cfg_rec = user_data;
4709 htp = htp_cfg_rec->cfg;
4710 SCLogDebug("LIBHTP using config: %p", htp);
69a4fee7 4711 }
a9cdd2bb
BR
4712 if (htp == NULL) {
4713 printf("Could not get config for: %s\n", addr);
4714 goto end;
4715 }
4716
4717 StreamTcpInitConfig(TRUE);
a9cdd2bb
BR
4718
4719 uint32_t u;
4720 for (u = 0; u < httplen1; u++) {
4721 uint8_t flags = 0;
4722
4723 if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4724 else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4725 else flags = STREAM_TOSERVER;
4726
6530c3d0 4727 FLOWLOCK_WRLOCK(f);
675fa564
GL
4728 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags,
4729 &httpbuf1[u], 1);
a9cdd2bb
BR
4730 if (r != 0) {
4731 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
4732 " 0: ", u, r);
4733 result = 0;
6530c3d0 4734 FLOWLOCK_UNLOCK(f);
a9cdd2bb
BR
4735 goto end;
4736 }
6530c3d0 4737 FLOWLOCK_UNLOCK(f);
a9cdd2bb
BR
4738 }
4739
262a7300 4740 htp_state = f->alstate;
a9cdd2bb
BR
4741 if (htp_state == NULL) {
4742 printf("no http state: ");
4743 result = 0;
4744 goto end;
4745 }
4746
48cf0585
AS
4747 if (HTPStateGetTxCnt(htp_state) != 2) {
4748 printf("HTPStateGetTxCnt(htp_state) failure\n");
4749 goto end;
4750 }
4751
4752 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4753 if (tx == NULL)
4754 goto end;
4755 if (tx->cfg != htp) {
a9cdd2bb 4756 printf("wrong HTP config (%p instead of %p - default=%p): ",
48cf0585
AS
4757 tx->cfg, htp, cfglist.cfg);
4758 goto end;
4759 }
4760 tx = HTPStateGetTx(htp_state, 1);
4761 if (tx == NULL)
4762 goto end;
4763 if (tx->cfg != htp) {
4764 printf("wrong HTP config (%p instead of %p - default=%p): ",
4765 tx->cfg, htp, cfglist.cfg);
a9cdd2bb
BR
4766 goto end;
4767 }
4768
4769end:
429c6388 4770 if (alp_tctx != NULL)
fdefb65b 4771 AppLayerParserThreadCtxFree(alp_tctx);
5c6a65dc 4772 HTPFreeConfig();
a9cdd2bb
BR
4773 ConfDeInit();
4774 ConfRestoreContextBackup();
5c6a65dc 4775 HtpConfigRestoreBackup();
a9cdd2bb 4776
a9cdd2bb 4777 StreamTcpFreeConfig(TRUE);
262a7300 4778 UTHFreeFlow(f);
a9cdd2bb
BR
4779 return result;
4780}
06a65cb4 4781
48cf0585
AS
4782/* disabled when we upgraded to libhtp 0.5.x */
4783#if 0
ab1200fb 4784static int HTPParserConfigTest04(void)
028c6c17
AS
4785{
4786 int result = 0;
4787
4788 char input[] = "\
4789%YAML 1.1\n\
4790---\n\
4791libhtp:\n\
4792\n\
4793 default-config:\n\
4794 personality: IDS\n\
4795 path-control-char-handling: status_400\n\
4796 path-convert-utf8: yes\n\
4797 path-invalid-encoding-handling: remove_percent\n\
4798\n\
4799 server-config:\n\
4800\n\
4801 - apache-tomcat:\n\
4802 personality: Tomcat_6_0\n\
4803 path-invalid-utf8-handling: none\n\
4804 path-nul-encoded-handling: status_404\n\
4805 path-nul-raw-handling: status_400\n\
4806\n\
4807 - iis7:\n\
4808 personality: IIS_7_0\n\
4809 path-replacement-char: o\n\
4810 path-unicode-mapping: status_400\n\
4811";
4812
4813 ConfCreateContextBackup();
4814 ConfInit();
4815 HtpConfigCreateBackup();
4816
4817 ConfYamlLoadString(input, strlen(input));
4818
4819 HTPConfigure();
4820
4821 HTPCfgRec *cfg_rec = &cfglist;
4822 if (cfg_rec->cfg->path_control_char_handling != STATUS_400 ||
4823 cfg_rec->cfg->path_convert_utf8 != 1 ||
4824 cfg_rec->cfg->path_invalid_encoding_handling != URL_DECODER_REMOVE_PERCENT) {
4825 printf("failed 1\n");
4826 goto end;
4827 }
4828
4829 cfg_rec = cfg_rec->next;
080c15b3 4830 if (cfg_rec->cfg->bestfit_replacement_char != 'o' ||
028c6c17
AS
4831 cfg_rec->cfg->path_unicode_mapping != STATUS_400) {
4832 printf("failed 2\n");
4833 goto end;
4834 }
4835
4836 cfg_rec = cfg_rec->next;
4837 if (cfg_rec->cfg->path_invalid_utf8_handling != NONE ||
4838 cfg_rec->cfg->path_nul_encoded_handling != STATUS_404 ||
4839 cfg_rec->cfg->path_nul_raw_handling != STATUS_400) {
4840 printf("failed 3\n");
4841 goto end;
4842 }
4843
4844 result = 1;
4845
4846end:
4847 HTPFreeConfig();
4848 ConfDeInit();
4849 ConfRestoreContextBackup();
4850 HtpConfigRestoreBackup();
4851
4852 return result;
4853}
48cf0585 4854#endif
028c6c17 4855
ad827ad0
VJ
4856/** \test Test %2f decoding in profile Apache_2_2
4857 *
4858 * %2f in path is left untouched
4859 * %2f in query string is normalized to %2F
4860 * %252f in query string is decoded/normalized to %2F
4861 */
4862static int HTPParserDecodingTest01(void)
4863{
4864 int result = 0;
4865 Flow *f = NULL;
4866 uint8_t httpbuf1[] =
4867 "GET /abc%2fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
4868 "GET /abc/def?ghi%2fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
4869 "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
4870 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4871 TcpSession ssn;
8dbf7a0d 4872 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
ad827ad0
VJ
4873
4874 HtpState *htp_state = NULL;
4875 int r = 0;
4876 char input[] = "\
4877%YAML 1.1\n\
4878---\n\
4879libhtp:\n\
4880\n\
4881 default-config:\n\
48cf0585 4882 personality: Apache_2\n\
ad827ad0
VJ
4883";
4884
4885 ConfCreateContextBackup();
4886 ConfInit();
4887 HtpConfigCreateBackup();
4888 ConfYamlLoadString(input, strlen(input));
4889 HTPConfigure();
ab1200fb 4890 const char *addr = "4.3.2.1";
ad827ad0
VJ
4891 memset(&ssn, 0, sizeof(ssn));
4892
4893 f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4894 if (f == NULL)
4895 goto end;
4896 f->protoctx = &ssn;
429c6388 4897 f->proto = IPPROTO_TCP;
5c01b409 4898 f->alproto = ALPROTO_HTTP;
ad827ad0
VJ
4899
4900 StreamTcpInitConfig(TRUE);
4901
4902 uint32_t u;
4903 for (u = 0; u < httplen1; u++) {
4904 uint8_t flags = 0;
4905
4906 if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4907 else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4908 else flags = STREAM_TOSERVER;
4909
6530c3d0 4910 FLOWLOCK_WRLOCK(f);
675fa564
GL
4911 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags,
4912 &httpbuf1[u], 1);
ad827ad0
VJ
4913 if (r != 0) {
4914 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
4915 " 0: ", u, r);
6530c3d0 4916 FLOWLOCK_UNLOCK(f);
ad827ad0
VJ
4917 goto end;
4918 }
6530c3d0 4919 FLOWLOCK_UNLOCK(f);
ad827ad0
VJ
4920 }
4921
4922 htp_state = f->alstate;
4923 if (htp_state == NULL) {
4924 printf("no http state: ");
ad827ad0
VJ
4925 goto end;
4926 }
4927
4928 uint8_t ref1[] = "/abc%2fdef";
4929 size_t reflen = sizeof(ref1) - 1;
4930
d4d18e31 4931 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
48cf0585
AS
4932 if (tx == NULL)
4933 goto end;
4934 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
4935 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
4936 if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
ad827ad0 4937 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
48cf0585 4938 (uintmax_t)reflen,
d5fdfa4b 4939 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
ad827ad0
VJ
4940 goto end;
4941 }
4942
48cf0585
AS
4943 if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1,
4944 bstr_len(tx_ud->request_uri_normalized)) != 0)
ad827ad0
VJ
4945 {
4946 printf("normalized uri \"");
48cf0585 4947 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
ad827ad0
VJ
4948 printf("\" != \"");
4949 PrintRawUriFp(stdout, ref1, reflen);
4950 printf("\": ");
4951 goto end;
4952 }
4953 }
4954
48cf0585 4955 uint8_t ref2[] = "/abc/def?ghi/jkl";
ad827ad0
VJ
4956 reflen = sizeof(ref2) - 1;
4957
d4d18e31 4958 tx = HTPStateGetTx(htp_state, 1);
48cf0585
AS
4959 if (tx == NULL)
4960 goto end;
4961 tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
4962 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
4963 if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
ad827ad0 4964 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
48cf0585 4965 (uintmax_t)reflen,
d5fdfa4b 4966 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
ad827ad0
VJ
4967 goto end;
4968 }
4969
48cf0585
AS
4970 if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref2,
4971 bstr_len(tx_ud->request_uri_normalized)) != 0)
ad827ad0
VJ
4972 {
4973 printf("normalized uri \"");
48cf0585 4974 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
ad827ad0
VJ
4975 printf("\" != \"");
4976 PrintRawUriFp(stdout, ref2, reflen);
4977 printf("\": ");
4978 goto end;
4979 }
4980 }
4981
48cf0585
AS
4982 uint8_t ref3[] = "/abc/def?ghi%2fjkl";
4983 reflen = sizeof(ref3) - 1;
d4d18e31 4984 tx = HTPStateGetTx(htp_state, 2);
48cf0585
AS
4985 if (tx == NULL)
4986 goto end;
4987 tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
4988 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
4989 if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
ad827ad0 4990 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
48cf0585 4991 (uintmax_t)reflen,
d5fdfa4b 4992 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
ad827ad0
VJ
4993 goto end;
4994 }
4995
48cf0585
AS
4996 if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref3,
4997 bstr_len(tx_ud->request_uri_normalized)) != 0)
ad827ad0
VJ
4998 {
4999 printf("normalized uri \"");
48cf0585 5000 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
ad827ad0
VJ
5001 printf("\" != \"");
5002 PrintRawUriFp(stdout, ref3, reflen);
5003 printf("\": ");
5004 goto end;
5005 }
5006 }
5007
5008 result = 1;
5009
5010end:
429c6388 5011 if (alp_tctx != NULL)
fdefb65b 5012 AppLayerParserThreadCtxFree(alp_tctx);
ad827ad0
VJ
5013 HTPFreeConfig();
5014 ConfDeInit();
5015 ConfRestoreContextBackup();
5016 HtpConfigRestoreBackup();
5017
5018 StreamTcpFreeConfig(TRUE);
ad827ad0
VJ
5019 UTHFreeFlow(f);
5020 return result;
5021}
5022
5023/** \test Test %2f decoding in profile IDS
5024 *
5025 * %2f in path decoded to /
5026 * %2f in query string is decoded to /
e839cea9 5027 * %252f in query string is decoded to %2F
ad827ad0
VJ
5028 */
5029static int HTPParserDecodingTest02(void)
5030{
5031 int result = 0;
5032 Flow *f = NULL;
5033 uint8_t httpbuf1[] =
5034 "GET /abc%2fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
5035 "GET /abc/def?ghi%2fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
5036 "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
5037 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5038 TcpSession ssn;
8dbf7a0d 5039 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
ad827ad0
VJ
5040
5041 HtpState *htp_state = NULL;
5042 int r = 0;
5043 char input[] = "\
5044%YAML 1.1\n\
5045---\n\
5046libhtp:\n\
5047\n\
5048 default-config:\n\
5049 personality: IDS\n\
e839cea9
VJ
5050 double-decode-path: no\n\
5051 double-decode-query: no\n\
ad827ad0
VJ
5052";
5053
5054 ConfCreateContextBackup();
5055 ConfInit();
5056 HtpConfigCreateBackup();
5057 ConfYamlLoadString(input, strlen(input));
5058 HTPConfigure();
ab1200fb 5059 const char *addr = "4.3.2.1";
ad827ad0
VJ
5060 memset(&ssn, 0, sizeof(ssn));
5061
5062 f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
5063 if (f == NULL)
5064 goto end;
5065 f->protoctx = &ssn;
429c6388 5066 f->proto = IPPROTO_TCP;
5c01b409 5067 f->alproto = ALPROTO_HTTP;
ad827ad0
VJ
5068
5069 StreamTcpInitConfig(TRUE);
5070
5071 uint32_t u;
5072 for (u = 0; u < httplen1; u++) {
5073 uint8_t flags = 0;
5074
5075 if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
5076 else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
5077 else flags = STREAM_TOSERVER;
5078
6530c3d0 5079 FLOWLOCK_WRLOCK(f);
675fa564
GL
5080 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags,
5081 &httpbuf1[u], 1);
ad827ad0
VJ
5082 if (r != 0) {
5083 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
5084 " 0: ", u, r);
6530c3d0 5085 FLOWLOCK_UNLOCK(f);
ad827ad0
VJ
5086 goto end;
5087 }
6530c3d0 5088 FLOWLOCK_UNLOCK(f);
ad827ad0
VJ
5089 }
5090
5091 htp_state = f->alstate;
5092 if (htp_state == NULL) {
5093 printf("no http state: ");
ad827ad0
VJ
5094 goto end;
5095 }
5096
5097 uint8_t ref1[] = "/abc/def";
5098 size_t reflen = sizeof(ref1) - 1;
5099
d4d18e31 5100 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
48cf0585
AS
5101 if (tx == NULL)
5102 goto end;
5103 HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
5104 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
5105 if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
ad827ad0 5106 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
48cf0585 5107 (uintmax_t)reflen,
d5fdfa4b 5108 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
ad827ad0
VJ
5109 goto end;
5110 }
5111
48cf0585
AS
5112 if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1,
5113 bstr_len(tx_ud->request_uri_normalized)) != 0)
ad827ad0
VJ
5114 {
5115 printf("normalized uri \"");
48cf0585 5116 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
ad827ad0
VJ
5117 printf("\" != \"");
5118 PrintRawUriFp(stdout, ref1, reflen);
5119 printf("\": ");
5120 goto end;
5121 }
5122 }
5123
5124 uint8_t ref2[] = "/abc/def?ghi/jkl";
5125 reflen = sizeof(ref2) - 1;
5126
d4d18e31 5127 tx = HTPStateGetTx(htp_state, 1);
48cf0585
AS
5128 if (tx == NULL)
5129 goto end;
5130 tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
5131 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
5132 if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
ad827ad0 5133 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
48cf0585 5134 (uintmax_t)reflen,
d5fdfa4b 5135 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
ad827ad0
VJ
5136 goto end;
5137 }
5138
48cf0585
AS
5139 if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref2,
5140 bstr_len(tx_ud->request_uri_normalized)) != 0)
ad827ad0
VJ
5141 {
5142 printf("normalized uri \"");
48cf0585 5143 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
ad827ad0
VJ
5144 printf("\" != \"");
5145 PrintRawUriFp(stdout, ref2, reflen);
5146 printf("\": ");
5147 goto end;
5148 }
5149 }
5150
48cf0585 5151 uint8_t ref3[] = "/abc/def?ghi%2fjkl";
e839cea9 5152 reflen = sizeof(ref3) - 1;
d4d18e31 5153 tx = HTPStateGetTx(htp_state, 2);
48cf0585
AS
5154 if (tx == NULL)
5155 goto end;
5156 tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
5157 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
5158 if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
e839cea9 5159 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX" (3): ",
48cf0585 5160 (uintmax_t)reflen,
d5fdfa4b 5161 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
ad827ad0
VJ
5162 goto end;
5163 }
5164
48cf0585
AS
5165 if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref3,
5166 bstr_len(tx_ud->request_uri_normalized)) != 0)
ad827ad0
VJ
5167 {
5168 printf("normalized uri \"");
48cf0585 5169 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
ad827ad0
VJ
5170 printf("\" != \"");
5171 PrintRawUriFp(stdout, ref3, reflen);
5172 printf("\": ");
5173 goto end;
5174 }
5175 }
5176
5177 result = 1;
5178
5179end:
429c6388 5180 if (alp_tctx != NULL)
fdefb65b 5181 AppLayerParserThreadCtxFree(alp_tctx);
ad827ad0
VJ
5182 HTPFreeConfig();
5183 ConfDeInit();
5184 ConfRestoreContextBackup();
5185 HtpConfigRestoreBackup();
5186
5187 StreamTcpFreeConfig(TRUE);
ad827ad0
VJ
5188 UTHFreeFlow(f);
5189 return result;
5190}
5191
e839cea9
VJ
5192/** \test Test %2f decoding in profile IDS with double-decode-* options
5193 *
5194 * %252f in path decoded to /
5195 * %252f in query string is decoded to /
5196 */
5197static int HTPParserDecodingTest03(void)
5198{
5199 int result = 0;
5200 Flow *f = NULL;
5201 uint8_t httpbuf1[] =
5202 "GET /abc%252fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
5203 "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
5204 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5205 TcpSession ssn;
8dbf7a0d 5206 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
e839cea9
VJ
5207
5208 HtpState *htp_state = NULL;
5209 int r = 0;
5210 char input[] = "\
5211%YAML 1.1\n\
5212---\n\
5213libhtp:\n\
5214\n\
5215 default-config:\n\
5216 personality: IDS\n\
5217 double-decode-path: yes\n\
5218 double-decode-query: yes\n\
5219";
5220
5221 ConfCreateContextBackup();
5222 ConfInit();
5223 HtpConfigCreateBackup();
5224 ConfYamlLoadString(input, strlen(input));
5225 HTPConfigure();
ab1200fb 5226 const char *addr = "4.3.2.1";
e839cea9
VJ
5227 memset(&ssn, 0, sizeof(ssn));
5228
5229 f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
5230 if (f == NULL)
5231 goto end;
5232 f->protoctx = &ssn;
429c6388 5233 f->proto = IPPROTO_TCP;
5c01b409 5234 f->alproto = ALPROTO_HTTP;
e839cea9
VJ
5235
5236 StreamTcpInitConfig(TRUE);
5237
5238 uint32_t u;
5239 for (u = 0; u < httplen1; u++) {
5240 uint8_t flags = 0;
5241
5242 if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
5243 else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
5244 else flags = STREAM_TOSERVER;
5245
6530c3d0 5246 FLOWLOCK_WRLOCK(f);
675fa564
GL
5247 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags,
5248 &httpbuf1[u], 1);
e839cea9
VJ
5249 if (r != 0) {
5250 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
5251 " 0: ", u, r);
6530c3d0 5252 FLOWLOCK_UNLOCK(f);
e839cea9
VJ
5253 goto end;
5254 }
6530c3d0 5255 FLOWLOCK_UNLOCK(f);
e839cea9
VJ
5256 }
5257
5258 htp_state = f->alstate;
5259 if (htp_state == NULL) {
5260 printf("no http state: ");
e839cea9
VJ
5261 goto end;
5262 }
5263
5264 uint8_t ref1[] = "/abc/def";
5265 size_t reflen = sizeof(ref1) - 1;
5266
d4d18e31 5267 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
48cf0585
AS
5268 if (tx == NULL)
5269 goto end;
5270 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
5271 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
5272 if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
e839cea9 5273 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
48cf0585 5274 (uintmax_t)reflen,
d5fdfa4b 5275 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
e839cea9
VJ
5276 goto end;
5277 }
5278
48cf0585
AS
5279 if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1,
5280 bstr_len(tx_ud->request_uri_normalized)) != 0)
e839cea9
VJ
5281 {
5282 printf("normalized uri \"");
48cf0585 5283 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
e839cea9
VJ
5284 printf("\" != \"");
5285 PrintRawUriFp(stdout, ref1, reflen);
5286 printf("\": ");
5287 goto end;
5288 }
5289 }
5290
5291 uint8_t ref2[] = "/abc/def?ghi/jkl";
5292 reflen = sizeof(ref2) - 1;
5293
d4d18e31 5294 tx = HTPStateGetTx(htp_state, 1);
48cf0585
AS
5295 if (tx == NULL)
5296 goto end;
5297 tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
5298 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
5299 if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
e839cea9 5300 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
48cf0585 5301 (uintmax_t)reflen,
d5fdfa4b 5302 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
e839cea9
VJ
5303 goto end;
5304 }
5305
48cf0585
AS
5306 if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref2,
5307 bstr_len(tx_ud->request_uri_normalized)) != 0)
e839cea9
VJ
5308 {
5309 printf("normalized uri \"");
48cf0585 5310 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
e839cea9
VJ
5311 printf("\" != \"");
5312 PrintRawUriFp(stdout, ref2, reflen);
5313 printf("\": ");
5314 goto end;
5315 }
5316 }
5317
5318 result = 1;
5319
5320end:
429c6388 5321 if (alp_tctx != NULL)
fdefb65b 5322 AppLayerParserThreadCtxFree(alp_tctx);
e839cea9
VJ
5323 HTPFreeConfig();
5324 ConfDeInit();
5325 ConfRestoreContextBackup();
5326 HtpConfigRestoreBackup();
5327
5328 StreamTcpFreeConfig(TRUE);
e839cea9
VJ
5329 UTHFreeFlow(f);
5330 return result;
5331}
5332
cc51eec5
VJ
5333/** \test Test http:// in query profile IDS
5334 */
5335static int HTPParserDecodingTest04(void)
5336{
5337 int result = 0;
5338 Flow *f = NULL;
5339 uint8_t httpbuf1[] =
5340 "GET /abc/def?a=http://www.abc.com/ HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
5341 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5342 TcpSession ssn;
8dbf7a0d 5343 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
cc51eec5
VJ
5344
5345 HtpState *htp_state = NULL;
5346 int r = 0;
5347 char input[] = "\
5348%YAML 1.1\n\
5349---\n\
5350libhtp:\n\
5351\n\
5352 default-config:\n\
5353 personality: IDS\n\
5354 double-decode-path: yes\n\
5355 double-decode-query: yes\n\
5356";
5357
5358 ConfCreateContextBackup();
5359 ConfInit();
5360 HtpConfigCreateBackup();
5361 ConfYamlLoadString(input, strlen(input));
5362 HTPConfigure();
ab1200fb 5363 const char *addr = "4.3.2.1";
cc51eec5
VJ
5364 memset(&ssn, 0, sizeof(ssn));
5365
5366 f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
5367 if (f == NULL)
5368 goto end;
5369 f->protoctx = &ssn;
429c6388 5370 f->proto = IPPROTO_TCP;
5c01b409 5371 f->alproto = ALPROTO_HTTP;
cc51eec5
VJ
5372
5373 StreamTcpInitConfig(TRUE);
5374
5375 uint32_t u;
5376 for (u = 0; u < httplen1; u++) {
5377 uint8_t flags = 0;
5378
5379 if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
5380 else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
5381 else flags = STREAM_TOSERVER;
5382
6530c3d0 5383 FLOWLOCK_WRLOCK(f);
675fa564
GL
5384 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags,
5385 &httpbuf1[u], 1);
cc51eec5
VJ
5386 if (r != 0) {
5387 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
5388 " 0: ", u, r);
6530c3d0 5389 FLOWLOCK_UNLOCK(f);
cc51eec5
VJ
5390 goto end;
5391 }
6530c3d0 5392 FLOWLOCK_UNLOCK(f);
cc51eec5
VJ
5393 }
5394
5395 htp_state = f->alstate;
5396 if (htp_state == NULL) {
5397 printf("no http state: ");
cc51eec5
VJ
5398 goto end;
5399 }
5400
5401 uint8_t ref1[] = "/abc/def?a=http://www.abc.com/";
5402 size_t reflen = sizeof(ref1) - 1;
5403
d4d18e31 5404 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
48cf0585
AS
5405 if (tx == NULL)
5406 goto end;
5407 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
5408 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
5409 if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
cc51eec5 5410 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
48cf0585 5411 (uintmax_t)reflen,
d5fdfa4b 5412 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
cc51eec5
VJ
5413 goto end;
5414 }
5415
48cf0585
AS
5416 if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1,
5417 bstr_len(tx_ud->request_uri_normalized)) != 0)
cc51eec5
VJ
5418 {
5419 printf("normalized uri \"");
48cf0585 5420 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
cc51eec5
VJ
5421 printf("\" != \"");
5422 PrintRawUriFp(stdout, ref1, reflen);
5423 printf("\": ");
5424 goto end;
5425 }
5426 }
5427
5428 result = 1;
5429
5430end:
429c6388 5431 if (alp_tctx != NULL)
fdefb65b 5432 AppLayerParserThreadCtxFree(alp_tctx);
cc51eec5
VJ
5433 HTPFreeConfig();
5434 ConfDeInit();
5435 ConfRestoreContextBackup();
5436 HtpConfigRestoreBackup();
5437
5438 StreamTcpFreeConfig(TRUE);
cc51eec5
VJ
5439 UTHFreeFlow(f);
5440 return result;
5441}
5442
5443/** \test Test \ char in query profile IDS. Bug 739
5444 */
5445static int HTPParserDecodingTest05(void)
5446{
5447 int result = 0;
5448 Flow *f = NULL;
5449 uint8_t httpbuf1[] =
5450 "GET /index?id=\\\"<script>alert(document.cookie)</script> HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
5451 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5452 TcpSession ssn;
8dbf7a0d 5453 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
cc51eec5
VJ
5454
5455 HtpState *htp_state = NULL;
5456 int r = 0;
5457 char input[] = "\
5458%YAML 1.1\n\
5459---\n\
5460libhtp:\n\
5461\n\
5462 default-config:\n\
5463 personality: IDS\n\
5464 double-decode-path: yes\n\
5465 double-decode-query: yes\n\
5466";
5467
5468 ConfCreateContextBackup();
5469 ConfInit();
5470 HtpConfigCreateBackup();
5471 ConfYamlLoadString(input, strlen(input));
5472 HTPConfigure();
ab1200fb 5473 const char *addr = "4.3.2.1";
cc51eec5
VJ
5474 memset(&ssn, 0, sizeof(ssn));
5475
5476 f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
5477 if (f == NULL)
5478 goto end;
5479 f->protoctx = &ssn;
429c6388 5480 f->proto = IPPROTO_TCP;
5c01b409 5481 f->alproto = ALPROTO_HTTP;
cc51eec5
VJ
5482
5483 StreamTcpInitConfig(TRUE);
5484
5485 uint32_t u;
5486 for (u = 0; u < httplen1; u++) {
5487 uint8_t flags = 0;
5488
5489 if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
5490 else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
5491 else flags = STREAM_TOSERVER;
5492
6530c3d0 5493 FLOWLOCK_WRLOCK(f);
675fa564
GL
5494 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags,
5495 &httpbuf1[u], 1);
cc51eec5
VJ
5496 if (r != 0) {
5497 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
5498 " 0: ", u, r);
6530c3d0 5499 FLOWLOCK_UNLOCK(f);
cc51eec5
VJ
5500 goto end;
5501 }
6530c3d0 5502 FLOWLOCK_UNLOCK(f);
cc51eec5
VJ
5503 }
5504
5505 htp_state = f->alstate;
5506 if (htp_state == NULL) {
5507 printf("no http state: ");
cc51eec5
VJ
5508 goto end;
5509 }
5510
5511 uint8_t ref1[] = "/index?id=\\\"<script>alert(document.cookie)</script>";
5512 size_t reflen = sizeof(ref1) - 1;
5513
d4d18e31 5514 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
48cf0585
AS
5515 if (tx == NULL)
5516 goto end;
5517 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
5518 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
5519 if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
cc51eec5 5520 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
48cf0585 5521 (uintmax_t)reflen,
d5fdfa4b 5522 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
cc51eec5
VJ
5523 goto end;
5524 }
5525
48cf0585
AS
5526 if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1,
5527 bstr_len(tx_ud->request_uri_normalized)) != 0)
cc51eec5
VJ
5528 {
5529 printf("normalized uri \"");
48cf0585 5530 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
cc51eec5
VJ
5531 printf("\" != \"");
5532 PrintRawUriFp(stdout, ref1, reflen);
5533 printf("\": ");
5534 goto end;
5535 }
5536 }
5537
5538 result = 1;
5539
5540end:
429c6388 5541 if (alp_tctx != NULL)
fdefb65b 5542 AppLayerParserThreadCtxFree(alp_tctx);
cc51eec5
VJ
5543 HTPFreeConfig();
5544 ConfDeInit();
5545 ConfRestoreContextBackup();
5546 HtpConfigRestoreBackup();
5547
5548 StreamTcpFreeConfig(TRUE);
cc51eec5
VJ
5549 UTHFreeFlow(f);
5550 return result;
5551}
5552
9a7353e1
VJ
5553/** \test Test + char in query. Bug 1035
5554 */
5555static int HTPParserDecodingTest06(void)
5556{
5557 int result = 0;
5558 Flow *f = NULL;
5559 uint8_t httpbuf1[] =
5560 "GET /put.php?ip=1.2.3.4&port=+6000 HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
5561 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5562 TcpSession ssn;
8dbf7a0d 5563 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
9a7353e1
VJ
5564
5565 HtpState *htp_state = NULL;
5566 int r = 0;
5567 char input[] = "\
5568%YAML 1.1\n\
5569---\n\
5570libhtp:\n\
5571\n\
5572 default-config:\n\
5573 personality: IDS\n\
5574 double-decode-path: yes\n\
5575 double-decode-query: yes\n\
5576";
5577
5578 ConfCreateContextBackup();
5579 ConfInit();
5580 HtpConfigCreateBackup();
5581 ConfYamlLoadString(input, strlen(input));
5582 HTPConfigure();
ab1200fb 5583 const char *addr = "4.3.2.1";
9a7353e1
VJ
5584 memset(&ssn, 0, sizeof(ssn));
5585
5586 f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
5587 if (f == NULL)
5588 goto end;
5589 f->protoctx = &ssn;
429c6388 5590 f->proto = IPPROTO_TCP;
5c01b409 5591 f->alproto = ALPROTO_HTTP;
9a7353e1
VJ
5592
5593 StreamTcpInitConfig(TRUE);
5594
5595 uint32_t u;
5596 for (u = 0; u < httplen1; u++) {
5597 uint8_t flags = 0;
5598
5599 if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
5600 else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
5601 else flags = STREAM_TOSERVER;
5602
6530c3d0 5603 FLOWLOCK_WRLOCK(f);
675fa564
GL
5604 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags,
5605 &httpbuf1[u], 1);
9a7353e1
VJ
5606 if (r != 0) {
5607 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
5608 " 0: ", u, r);
6530c3d0 5609 FLOWLOCK_UNLOCK(f);
9a7353e1
VJ
5610 goto end;
5611 }
6530c3d0 5612 FLOWLOCK_UNLOCK(f);
9a7353e1
VJ
5613 }
5614
5615 htp_state = f->alstate;
5616 if (htp_state == NULL) {
5617 printf("no http state: ");
9a7353e1
VJ
5618 goto end;
5619 }
5620
5621 uint8_t ref1[] = "/put.php?ip=1.2.3.4&port=+6000";
5622 size_t reflen = sizeof(ref1) - 1;
5623
5624 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
5625 if (tx == NULL)
5626 goto end;
5627 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
5628 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
5629 if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
5630 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
5631 (uintmax_t)reflen,
d5fdfa4b 5632 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
9a7353e1
VJ
5633 goto end;
5634 }
5635
5636 if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1,
5637 bstr_len(tx_ud->request_uri_normalized)) != 0)
5638 {
5639 printf("normalized uri \"");
5640 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
5641 printf("\" != \"");
5642 PrintRawUriFp(stdout, ref1, reflen);
5643 printf("\": ");
5644 goto end;
5645 }
5646 }
5647
5648 result = 1;
5649
5650end:
429c6388 5651 if (alp_tctx != NULL)
fdefb65b 5652 AppLayerParserThreadCtxFree(alp_tctx);
9a7353e1
VJ
5653 HTPFreeConfig();
5654 ConfDeInit();
5655 ConfRestoreContextBackup();
5656 HtpConfigRestoreBackup();
5657
5658 StreamTcpFreeConfig(TRUE);
9a7353e1
VJ
5659 UTHFreeFlow(f);
5660 return result;
5661}
5662
5663/** \test Test + char in query. Bug 1035
5664 */
5665static int HTPParserDecodingTest07(void)
5666{
5667 int result = 0;
5668 Flow *f = NULL;
5669 uint8_t httpbuf1[] =
5670 "GET /put.php?ip=1.2.3.4&port=+6000 HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
5671 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5672 TcpSession ssn;
8dbf7a0d 5673 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
9a7353e1
VJ
5674
5675 HtpState *htp_state = NULL;
5676 int r = 0;
5677 char input[] = "\
5678%YAML 1.1\n\
5679---\n\
5680libhtp:\n\
5681\n\
5682 default-config:\n\
5683 personality: IDS\n\
5684 double-decode-path: yes\n\
5685 double-decode-query: yes\n\
5686 query-plusspace-decode: yes\n\
5687";
5688
5689 ConfCreateContextBackup();
5690 ConfInit();
5691 HtpConfigCreateBackup();
5692 ConfYamlLoadString(input, strlen(input));
5693 HTPConfigure();
ab1200fb 5694 const char *addr = "4.3.2.1";
9a7353e1
VJ
5695 memset(&ssn, 0, sizeof(ssn));
5696
5697 f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
5698 if (f == NULL)
5699 goto end;
5700 f->protoctx = &ssn;
429c6388 5701 f->proto = IPPROTO_TCP;
5c01b409 5702 f->alproto = ALPROTO_HTTP;
9a7353e1
VJ
5703
5704 StreamTcpInitConfig(TRUE);
5705
5706 uint32_t u;
5707 for (u = 0; u < httplen1; u++) {
5708 uint8_t flags = 0;
5709
5710 if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
5711 else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
5712 else flags = STREAM_TOSERVER;
5713
6530c3d0 5714 FLOWLOCK_WRLOCK(f);
675fa564
GL
5715 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags,
5716 &httpbuf1[u], 1);
9a7353e1
VJ
5717 if (r != 0) {
5718 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
5719 " 0: ", u, r);
6530c3d0 5720 FLOWLOCK_UNLOCK(f);
9a7353e1
VJ
5721 goto end;
5722 }
6530c3d0 5723 FLOWLOCK_UNLOCK(f);
9a7353e1
VJ
5724 }
5725
5726 htp_state = f->alstate;
5727 if (htp_state == NULL) {
5728 printf("no http state: ");
9a7353e1
VJ
5729 goto end;
5730 }
5731
5732 uint8_t ref1[] = "/put.php?ip=1.2.3.4&port= 6000";
5733 size_t reflen = sizeof(ref1) - 1;
5734
5735 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
5736 if (tx == NULL)
5737 goto end;
5738 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
5739 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
5740 if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
5741 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
5742 (uintmax_t)reflen,
d5fdfa4b 5743 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
9a7353e1
VJ
5744 goto end;
5745 }
5746
5747 if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1,
5748 bstr_len(tx_ud->request_uri_normalized)) != 0)
5749 {
5750 printf("normalized uri \"");
5751 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
5752 printf("\" != \"");
5753 PrintRawUriFp(stdout, ref1, reflen);
5754 printf("\": ");
5755 goto end;
5756 }
5757 }
5758
5759 result = 1;
5760
5761end:
429c6388 5762 if (alp_tctx != NULL)
fdefb65b 5763 AppLayerParserThreadCtxFree(alp_tctx);
9a7353e1
VJ
5764 HTPFreeConfig();
5765 ConfDeInit();
5766 ConfRestoreContextBackup();
5767 HtpConfigRestoreBackup();
5768
5769 StreamTcpFreeConfig(TRUE);
9a7353e1
VJ
5770 UTHFreeFlow(f);
5771 return result;
5772}
5773
a8b971c7
VJ
5774/** \test Test 'proxy' URI normalization. Ticket 1008
5775 */
5776static int HTPParserDecodingTest08(void)
5777{
5778 int result = 0;
5779 Flow *f = NULL;
5780 uint8_t httpbuf1[] =
5781 "GET http://suricata-ids.org/blah/ HTTP/1.1\r\nHost: suricata-ids.org\r\n\r\n";
5782 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5783 TcpSession ssn;
8dbf7a0d 5784 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
a8b971c7
VJ
5785
5786 HtpState *htp_state = NULL;
5787 int r = 0;
5788 char input[] = "\
5789%YAML 1.1\n\
5790---\n\
5791libhtp:\n\
5792\n\
5793 default-config:\n\
5794 personality: IDS\n\
5795";
5796
5797 ConfCreateContextBackup();
5798 ConfInit();
5799 HtpConfigCreateBackup();
5800 ConfYamlLoadString(input, strlen(input));
5801 HTPConfigure();
ab1200fb 5802 const char *addr = "4.3.2.1";
a8b971c7
VJ
5803 memset(&ssn, 0, sizeof(ssn));
5804
5805 f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
5806 if (f == NULL)
5807 goto end;
5808 f->protoctx = &ssn;
429c6388 5809 f->proto = IPPROTO_TCP;
5c01b409 5810 f->alproto = ALPROTO_HTTP;
a8b971c7
VJ
5811
5812 StreamTcpInitConfig(TRUE);
5813
5814 uint32_t u;
5815 for (u = 0; u < httplen1; u++) {
5816 uint8_t flags = 0;
5817
5818 if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
5819 else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
5820 else flags = STREAM_TOSERVER;
5821
6530c3d0 5822 FLOWLOCK_WRLOCK(f);
675fa564
GL
5823 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags,
5824 &httpbuf1[u], 1);
a8b971c7
VJ
5825 if (r != 0) {
5826 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
5827 " 0: ", u, r);
6530c3d0 5828 FLOWLOCK_UNLOCK(f);
a8b971c7
VJ
5829 goto end;
5830 }
6530c3d0 5831 FLOWLOCK_UNLOCK(f);
a8b971c7
VJ
5832 }
5833
5834 htp_state = f->alstate;
5835 if (htp_state == NULL) {
5836 printf("no http state: ");
a8b971c7
VJ
5837 goto end;
5838 }
5839
5840 uint8_t ref1[] = "/blah/";
5841 size_t reflen = sizeof(ref1) - 1;
5842
5843 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
5844 if (tx == NULL)
5845 goto end;
5846 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
5847 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
5848 if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
5849 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
5850 (uintmax_t)reflen,
d5fdfa4b 5851 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
a8b971c7
VJ
5852 goto end;
5853 }
5854
5855 if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1,
5856 bstr_len(tx_ud->request_uri_normalized)) != 0)
5857 {
5858 printf("normalized uri \"");
5859 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
5860 printf("\" != \"");
5861 PrintRawUriFp(stdout, ref1, reflen);
5862 printf("\": ");
5863 goto end;
5864 }
5865 }
5866
5867 result = 1;
5868
5869end:
429c6388 5870 if (alp_tctx != NULL)
fdefb65b 5871 AppLayerParserThreadCtxFree(alp_tctx);
a8b971c7
VJ
5872 HTPFreeConfig();
5873 ConfDeInit();
5874 ConfRestoreContextBackup();
5875 HtpConfigRestoreBackup();
5876
5877 StreamTcpFreeConfig(TRUE);
a8b971c7
VJ
5878 UTHFreeFlow(f);
5879 return result;
5880}
5881
5882/** \test Test 'proxy' URI normalization. Ticket 1008
5883 */
5884static int HTPParserDecodingTest09(void)
5885{
5886 int result = 0;
5887 Flow *f = NULL;
5888 uint8_t httpbuf1[] =
5889 "GET http://suricata-ids.org/blah/ HTTP/1.1\r\nHost: suricata-ids.org\r\n\r\n";
5890 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5891 TcpSession ssn;
8dbf7a0d 5892 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
a8b971c7
VJ
5893
5894 HtpState *htp_state = NULL;
5895 int r = 0;
5896 char input[] = "\
5897%YAML 1.1\n\
5898---\n\
5899libhtp:\n\
5900\n\
5901 default-config:\n\
5902 personality: IDS\n\
5903 uri-include-all: true\n\
5904";
5905
5906 ConfCreateContextBackup();
5907 ConfInit();
5908 HtpConfigCreateBackup();
5909 ConfYamlLoadString(input, strlen(input));
5910 HTPConfigure();
ab1200fb 5911 const char *addr = "4.3.2.1";
a8b971c7
VJ
5912 memset(&ssn, 0, sizeof(ssn));
5913
5914 f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
5915 if (f == NULL)
5916 goto end;
5917 f->protoctx = &ssn;
429c6388 5918 f->proto = IPPROTO_TCP;
5c01b409 5919 f->alproto = ALPROTO_HTTP;
a8b971c7
VJ
5920
5921 StreamTcpInitConfig(TRUE);
5922
5923 uint32_t u;
5924 for (u = 0; u < httplen1; u++) {
5925 uint8_t flags = 0;
5926
5927 if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
5928 else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
5929 else flags = STREAM_TOSERVER;
5930
6530c3d0 5931 FLOWLOCK_WRLOCK(f);
675fa564
GL
5932 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags,
5933 &httpbuf1[u], 1);
a8b971c7
VJ
5934 if (r != 0) {
5935 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
5936 " 0: ", u, r);
6530c3d0 5937 FLOWLOCK_UNLOCK(f);
a8b971c7
VJ
5938 goto end;
5939 }
6530c3d0 5940 FLOWLOCK_UNLOCK(f);
a8b971c7
VJ
5941 }
5942
5943 htp_state = f->alstate;
5944 if (htp_state == NULL) {
5945 printf("no http state: ");
a8b971c7
VJ
5946 goto end;
5947 }
5948
5949 uint8_t ref1[] = "http://suricata-ids.org/blah/";
5950 size_t reflen = sizeof(ref1) - 1;
5951
5952 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
5953 if (tx == NULL)
5954 goto end;
5955 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
5956 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
5957 if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
5958 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
5959 (uintmax_t)reflen,
d5fdfa4b 5960 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
a8b971c7
VJ
5961 goto end;
5962 }
5963
5964 if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1,
5965 bstr_len(tx_ud->request_uri_normalized)) != 0)
5966 {
5967 printf("normalized uri \"");
5968 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
5969 printf("\" != \"");
5970 PrintRawUriFp(stdout, ref1, reflen);
5971 printf("\": ");
5972 goto end;
5973 }
5974 }
5975
5976 result = 1;
5977
5978end:
429c6388 5979 if (alp_tctx != NULL)
fdefb65b 5980 AppLayerParserThreadCtxFree(alp_tctx);
a8b971c7
VJ
5981 HTPFreeConfig();
5982 ConfDeInit();
5983 ConfRestoreContextBackup();
5984 HtpConfigRestoreBackup();
5985
5986 StreamTcpFreeConfig(TRUE);
a8b971c7
VJ
5987 UTHFreeFlow(f);
5988 return result;
5989}
5990
fcc21ae4
VJ
5991/** \test BG box crash -- chunks are messed up. Observed for real. */
5992static int HTPBodyReassemblyTest01(void)
5993{
5994 int result = 0;
5995 HtpTxUserData htud;
5996 memset(&htud, 0x00, sizeof(htud));
5997 HtpState hstate;
5998 memset(&hstate, 0x00, sizeof(hstate));
5999 Flow flow;
6000 memset(&flow, 0x00, sizeof(flow));
9634e60e 6001 AppLayerParserState *parser = AppLayerParserStateAlloc();
94e25276
AS
6002 htp_tx_t tx;
6003 memset(&tx, 0, sizeof(tx));
fcc21ae4
VJ
6004
6005 hstate.f = &flow;
c7ae662d 6006 flow.alparser = parser;
fcc21ae4
VJ
6007
6008 uint8_t chunk1[] = "--e5a320f21416a02493a0a6f561b1c494\r\nContent-Disposition: form-data; name=\"uploadfile\"; filename=\"D2GUef.jpg\"\r";
6009 uint8_t chunk2[] = "POST /uri HTTP/1.1\r\nHost: hostname.com\r\nKeep-Alive: 115\r\nAccept-Charset: utf-8\r\nUser-Agent: Mozilla/5.0 (X11; Linux i686; rv:9.0.1) Gecko/20100101 Firefox/9.0.1\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nConnection: keep-alive\r\nContent-length: 68102\r\nReferer: http://otherhost.com\r\nAccept-Encoding: gzip\r\nContent-Type: multipart/form-data; boundary=e5a320f21416a02493a0a6f561b1c494\r\nCookie: blah\r\nAccept-Language: us\r\n\r\n--e5a320f21416a02493a0a6f561b1c494\r\nContent-Disposition: form-data; name=\"uploadfile\"; filename=\"D2GUef.jpg\"\r";
6010
6fb808fc 6011 int r = HtpBodyAppendChunk(NULL, &htud.request_body, chunk1, sizeof(chunk1)-1);
fcc21ae4 6012 BUG_ON(r != 0);
6fb808fc 6013 r = HtpBodyAppendChunk(NULL, &htud.request_body, chunk2, sizeof(chunk2)-1);
fcc21ae4
VJ
6014 BUG_ON(r != 0);
6015
46e55f1e 6016 const uint8_t *chunks_buffer = NULL;
fcc21ae4
VJ
6017 uint32_t chunks_buffer_len = 0;
6018
6019 HtpRequestBodyReassemble(&htud, &chunks_buffer, &chunks_buffer_len);
6020 if (chunks_buffer == NULL) {
6021 goto end;
6022 }
6023#ifdef PRINT
6024 printf("REASSCHUNK START: \n");
6025 PrintRawDataFp(stdout, chunks_buffer, chunks_buffer_len);
6026 printf("REASSCHUNK END: \n");
6027#endif
6028
94e25276 6029 HtpRequestBodyHandleMultipart(&hstate, &htud, &tx, chunks_buffer, chunks_buffer_len);
fcc21ae4
VJ
6030
6031 if (htud.request_body.content_len_so_far != 669) {
6032 printf("htud.request_body.content_len_so_far %"PRIu64": ", htud.request_body.content_len_so_far);
6033 goto end;
6034 }
6035
6036 if (hstate.files_ts != NULL)
6037 goto end;
6038
6039 result = 1;
6040end:
6041 return result;
6042}
6043
6044/** \test BG crash */
8f1d7503
KS
6045static int HTPSegvTest01(void)
6046{
fcc21ae4
VJ
6047 int result = 0;
6048 Flow *f = NULL;
6049 uint8_t httpbuf1[] = "POST /uri HTTP/1.1\r\nHost: hostname.com\r\nKeep-Alive: 115\r\nAccept-Charset: utf-8\r\nUser-Agent: Mozilla/5.0 (X11; Linux i686; rv:9.0.1) Gecko/20100101 Firefox/9.0.1\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nConnection: keep-alive\r\nContent-length: 68102\r\nReferer: http://otherhost.com\r\nAccept-Encoding: gzip\r\nContent-Type: multipart/form-data; boundary=e5a320f21416a02493a0a6f561b1c494\r\nCookie: blah\r\nAccept-Language: us\r\n\r\n--e5a320f21416a02493a0a6f561b1c494\r\nContent-Disposition: form-data; name=\"uploadfile\"; filename=\"D2GUef.jpg\"\r";
6050 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
6051 char input[] = "\
6052%YAML 1.1\n\
6053---\n\
6054libhtp:\n\
6055\n\
6056 default-config:\n\
6057 personality: IDS\n\
6058 double-decode-path: no\n\
6059 double-decode-query: no\n\
6060 request-body-limit: 0\n\
6061 response-body-limit: 0\n\
6062";
6063
6064 ConfCreateContextBackup();
6065 ConfInit();
6066 HtpConfigCreateBackup();
6067 ConfYamlLoadString(input, strlen(input));
6068 HTPConfigure();
6069
6070 TcpSession ssn;
6071 HtpState *http_state = NULL;
8dbf7a0d 6072 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
fcc21ae4
VJ
6073
6074 memset(&ssn, 0, sizeof(ssn));
6075
6076 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
6077 if (f == NULL)
6078 goto end;
6079 f->protoctx = &ssn;
429c6388 6080 f->proto = IPPROTO_TCP;
5c01b409 6081 f->alproto = ALPROTO_HTTP;
fcc21ae4
VJ
6082
6083 StreamTcpInitConfig(TRUE);
6084
6085 SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
6530c3d0 6086 FLOWLOCK_WRLOCK(f);
675fa564
GL
6087 int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
6088 STREAM_TOSERVER | STREAM_START, httpbuf1,
6089 httplen1);
fcc21ae4
VJ
6090 if (r != 0) {
6091 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
6530c3d0 6092 FLOWLOCK_UNLOCK(f);
fcc21ae4
VJ
6093 goto end;
6094 }
6530c3d0 6095 FLOWLOCK_UNLOCK(f);
fcc21ae4 6096 SCLogDebug("\n>>>> processing chunk 1 again <<<<\n");
6530c3d0 6097 FLOWLOCK_WRLOCK(f);
675fa564
GL
6098 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER,
6099 httpbuf1, httplen1);
fcc21ae4
VJ
6100 if (r != 0) {
6101 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
6530c3d0 6102 FLOWLOCK_UNLOCK(f);
fcc21ae4
VJ
6103 goto end;
6104 }
6530c3d0 6105 FLOWLOCK_UNLOCK(f);
fcc21ae4
VJ
6106
6107 http_state = f->alstate;
6108 if (http_state == NULL) {
6109 printf("no http state: ");
fcc21ae4
VJ
6110 goto end;
6111 }
6112
6530c3d0 6113 FLOWLOCK_WRLOCK(f);
429c6388 6114 AppLayerDecoderEvents *decoder_events = AppLayerParserGetDecoderEvents(f->alparser);
fcc21ae4
VJ
6115 if (decoder_events != NULL) {
6116 printf("app events: ");
6530c3d0 6117 FLOWLOCK_UNLOCK(f);
fcc21ae4
VJ
6118 goto end;
6119 }
6530c3d0 6120 FLOWLOCK_UNLOCK(f);
fcc21ae4
VJ
6121 result = 1;
6122end:
429c6388 6123 if (alp_tctx != NULL)
fdefb65b 6124 AppLayerParserThreadCtxFree(alp_tctx);
fcc21ae4
VJ
6125 HTPFreeConfig();
6126 ConfDeInit();
6127 ConfRestoreContextBackup();
6128 HtpConfigRestoreBackup();
6129 StreamTcpFreeConfig(TRUE);
fcc21ae4
VJ
6130 UTHFreeFlow(f);
6131 return result;
6132}
6133
129b6a65 6134/** \test Test really long request, this should result in HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG */
ab1200fb 6135static int HTPParserTest14(void)
8f1d7503 6136{
129b6a65
VJ
6137 size_t len = 18887;
6138 TcpSession ssn;
129b6a65
VJ
6139 char input[] = "\
6140%YAML 1.1\n\
6141---\n\
6142libhtp:\n\
6143\n\
6144 default-config:\n\
6145 personality: IDS\n\
6146 double-decode-path: no\n\
6147 double-decode-query: no\n\
6148 request-body-limit: 0\n\
6149 response-body-limit: 0\n\
6150";
8dbf7a0d 6151 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
26b61bad 6152 FAIL_IF_NULL(alp_tctx);
129b6a65
VJ
6153
6154 memset(&ssn, 0, sizeof(ssn));
6155
6156 ConfCreateContextBackup();
6157 ConfInit();
6158 HtpConfigCreateBackup();
6159 ConfYamlLoadString(input, strlen(input));
6160 HTPConfigure();
6161
26b61bad
VJ
6162 char *httpbuf = SCMalloc(len);
6163 FAIL_IF_NULL(httpbuf);
129b6a65
VJ
6164 memset(httpbuf, 0x00, len);
6165
6166 /* create the request with a longer than 18k cookie */
6167 strlcpy(httpbuf, "GET /blah/ HTTP/1.1\r\n"
6168 "Host: myhost.lan\r\n"
6169 "Connection: keep-alive\r\n"
6170 "Accept: */*\r\n"
6171 "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.76 Safari/537.36\r\n"
6172 "Referer: http://blah.lan/\r\n"
6173 "Accept-Encoding: gzip,deflate,sdch\r\nAccept-Language: en-US,en;q=0.8\r\n"
6174 "Cookie: ", len);
6175 size_t o = strlen(httpbuf);
6176 for ( ; o < len - 4; o++) {
6177 httpbuf[o] = 'A';
6178 }
6179 httpbuf[len - 4] = '\r';
6180 httpbuf[len - 3] = '\n';
6181 httpbuf[len - 2] = '\r';
6182 httpbuf[len - 1] = '\n';
6183
26b61bad
VJ
6184 Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
6185 FAIL_IF_NULL(f);
129b6a65 6186 f->protoctx = &ssn;
5c01b409 6187 f->alproto = ALPROTO_HTTP;
429c6388 6188 f->proto = IPPROTO_TCP;
129b6a65
VJ
6189
6190 StreamTcpInitConfig(TRUE);
6191
6192 uint32_t u;
6193 for (u = 0; u < len; u++) {
6194 uint8_t flags = 0;
6195
6196 if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
6197 else if (u == (len - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
6198 else flags = STREAM_TOSERVER;
6199
26b61bad 6200 (void)AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags,
675fa564 6201 (uint8_t *)&httpbuf[u], 1);
129b6a65 6202 }
26b61bad
VJ
6203 HtpState *htp_state = f->alstate;
6204 FAIL_IF_NULL(htp_state);
129b6a65
VJ
6205
6206 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
26b61bad
VJ
6207 FAIL_IF_NULL(tx);
6208 FAIL_IF(tx->request_method_number != HTP_M_GET);
6209 FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1);
129b6a65 6210
d568e7fa
JL
6211 void *txtmp = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0);
6212 AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP, txtmp);
26b61bad 6213 FAIL_IF_NULL(decoder_events);
129b6a65 6214
26b61bad 6215 FAIL_IF(decoder_events->events[0] != HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG);
129b6a65 6216
26b61bad 6217 AppLayerParserThreadCtxFree(alp_tctx);
129b6a65 6218 StreamTcpFreeConfig(TRUE);
129b6a65 6219 UTHFreeFlow(f);
26b61bad 6220 SCFree(httpbuf);
129b6a65
VJ
6221 HTPFreeConfig();
6222 ConfDeInit();
6223 ConfRestoreContextBackup();
6224 HtpConfigRestoreBackup();
26b61bad 6225 PASS;
129b6a65 6226}
fb496791
VJ
6227
6228/** \test Test really long request (same as HTPParserTest14), now with config
6229 * update to allow it */
ab1200fb 6230static int HTPParserTest15(void)
8f1d7503 6231{
fb496791
VJ
6232 int result = 0;
6233 Flow *f = NULL;
6234 char *httpbuf = NULL;
6235 size_t len = 18887;
6236 TcpSession ssn;
6237 HtpState *htp_state = NULL;
6238 int r = 0;
6239 char input[] = "\
6240%YAML 1.1\n\
6241---\n\
6242libhtp:\n\
6243\n\
6244 default-config:\n\
6245 personality: IDS\n\
6246 double-decode-path: no\n\
6247 double-decode-query: no\n\
6248 request-body-limit: 0\n\
6249 response-body-limit: 0\n\
6250 meta-field-limit: 20000\n\
6251";
8dbf7a0d 6252 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
fb496791
VJ
6253
6254 memset(&ssn, 0, sizeof(ssn));
6255
6256 ConfCreateContextBackup();
6257 ConfInit();
6258 HtpConfigCreateBackup();
6259 ConfYamlLoadString(input, strlen(input));
6260 HTPConfigure();
6261
6262 httpbuf = SCMalloc(len);
6263 if (unlikely(httpbuf == NULL))
6264 goto end;
6265 memset(httpbuf, 0x00, len);
6266
6267 /* create the request with a longer than 18k cookie */
6268 strlcpy(httpbuf, "GET /blah/ HTTP/1.1\r\n"
6269 "Host: myhost.lan\r\n"
6270 "Connection: keep-alive\r\n"
6271 "Accept: */*\r\n"
6272 "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.76 Safari/537.36\r\n"
6273 "Referer: http://blah.lan/\r\n"
6274 "Accept-Encoding: gzip,deflate,sdch\r\nAccept-Language: en-US,en;q=0.8\r\n"
6275 "Cookie: ", len);
6276 size_t o = strlen(httpbuf);
6277 for ( ; o < len - 4; o++) {
6278 httpbuf[o] = 'A';
6279 }
6280 httpbuf[len - 4] = '\r';
6281 httpbuf[len - 3] = '\n';
6282 httpbuf[len - 2] = '\r';
6283 httpbuf[len - 1] = '\n';
6284
6285 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
6286 if (f == NULL)
6287 goto end;
6288 f->protoctx = &ssn;
429c6388 6289 f->proto = IPPROTO_TCP;
5c01b409 6290 f->alproto = ALPROTO_HTTP;
fb496791
VJ
6291
6292 StreamTcpInitConfig(TRUE);
6293
6294 uint32_t u;
6295 for (u = 0; u < len; u++) {
6296 uint8_t flags = 0;
6297
6298 if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
6299 else if (u == (len - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
6300 else flags = STREAM_TOSERVER;
6301
6530c3d0 6302 FLOWLOCK_WRLOCK(f);
675fa564
GL
6303 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags,
6304 (uint8_t *)&httpbuf[u], 1);
fb496791
VJ
6305 if (r != 0) {
6306 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
6307 " 0: ", u, r);
6530c3d0 6308 FLOWLOCK_UNLOCK(f);
fb496791
VJ
6309 goto end;
6310 }
6530c3d0 6311 FLOWLOCK_UNLOCK(f);
fb496791
VJ
6312 }
6313 htp_state = f->alstate;
6314 if (htp_state == NULL) {
6315 printf("no http state: ");
6316 goto end;
6317 }
6318
6319 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
6320 if (tx == NULL || tx->request_method_number != HTP_M_GET || tx->request_protocol_number != HTP_PROTOCOL_1_1)
6321 {
6322 printf("expected method M_GET and got %s: , expected protocol "
6323 "HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method),
6324 bstr_util_strdup_to_c(tx->request_protocol));
6325 goto end;
6326 }
6327
6530c3d0 6328 FLOWLOCK_WRLOCK(f);
d568e7fa
JL
6329 void *txtmp = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0);
6330 AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP, txtmp);
fb496791
VJ
6331 if (decoder_events != NULL) {
6332 printf("app events: ");
6530c3d0 6333 FLOWLOCK_UNLOCK(f);
fb496791
VJ
6334 goto end;
6335 }
6530c3d0 6336 FLOWLOCK_UNLOCK(f);
fb496791
VJ
6337
6338 result = 1;
6339end:
429c6388 6340 if (alp_tctx != NULL)
fdefb65b 6341 AppLayerParserThreadCtxFree(alp_tctx);
fb496791 6342 StreamTcpFreeConfig(TRUE);
fb496791
VJ
6343 UTHFreeFlow(f);
6344 if (httpbuf != NULL)
6345 SCFree(httpbuf);
6346 HTPFreeConfig();
6347 ConfDeInit();
6348 ConfRestoreContextBackup();
6349 HtpConfigRestoreBackup();
6350 return result;
6351}
e78e33a4
VJ
6352
6353/** \test Test unusual delims in request line HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG */
ab1200fb 6354static int HTPParserTest16(void)
e78e33a4
VJ
6355{
6356 int result = 0;
6357 Flow *f = NULL;
6358 TcpSession ssn;
6359 HtpState *htp_state = NULL;
6360 int r = 0;
6361 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
6362
6363 memset(&ssn, 0, sizeof(ssn));
6364
6365 uint8_t httpbuf[] = "GET\f/blah/\fHTTP/1.1\r\n"
6366 "Host: myhost.lan\r\n"
6367 "Connection: keep-alive\r\n"
6368 "Accept: */*\r\n"
6369 "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.76 Safari/537.36\r\n"
6370 "Referer: http://blah.lan/\r\n"
6371 "Accept-Encoding: gzip,deflate,sdch\r\nAccept-Language: en-US,en;q=0.8\r\n"
6372 "Cookie: blah\r\n\r\n";
6373 size_t len = sizeof(httpbuf) - 1;
6374
6375 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
6376 if (f == NULL)
6377 goto end;
6378 f->protoctx = &ssn;
6379 f->proto = IPPROTO_TCP;
5c01b409 6380 f->alproto = ALPROTO_HTTP;
e78e33a4
VJ
6381
6382 StreamTcpInitConfig(TRUE);
6383
6384 uint8_t flags = STREAM_TOSERVER|STREAM_START|STREAM_EOF;
6385
6530c3d0 6386 FLOWLOCK_WRLOCK(f);
675fa564
GL
6387 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags,
6388 (uint8_t *)httpbuf, len);
e78e33a4
VJ
6389 if (r != 0) {
6390 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
6530c3d0 6391 FLOWLOCK_UNLOCK(f);
e78e33a4
VJ
6392 goto end;
6393 }
6530c3d0 6394 FLOWLOCK_UNLOCK(f);
e78e33a4
VJ
6395
6396 htp_state = f->alstate;
6397 if (htp_state == NULL) {
6398 printf("no http state: ");
6399 goto end;
6400 }
6401
6402 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
6403 if (tx == NULL || tx->request_method_number != HTP_M_GET || tx->request_protocol_number != HTP_PROTOCOL_1_1)
6404 {
6405 printf("expected method M_GET and got %s: , expected protocol "
b3b7625b
VJ
6406 "HTTP/1.1 and got %s \n", tx ? bstr_util_strdup_to_c(tx->request_method) : "tx null",
6407 tx ? bstr_util_strdup_to_c(tx->request_protocol) : "tx null");
e78e33a4
VJ
6408 goto end;
6409 }
6410
6530c3d0 6411 FLOWLOCK_WRLOCK(f);
d568e7fa
JL
6412 void *txtmp = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0);
6413 AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP, txtmp);
e78e33a4
VJ
6414 if (decoder_events == NULL) {
6415 printf("no app events: ");
6530c3d0 6416 FLOWLOCK_UNLOCK(f);
e78e33a4
VJ
6417 goto end;
6418 }
6530c3d0 6419 FLOWLOCK_UNLOCK(f);
e78e33a4
VJ
6420
6421 if (decoder_events->events[0] != HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT) {
6422 printf("HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT not set: ");
6423 goto end;
6424 }
6425
6426 if (decoder_events->events[1] != HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT) {
6427 printf("HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT not set: ");
6428 goto end;
6429 }
6430
6431 result = 1;
6432end:
6433 if (alp_tctx != NULL)
6434 AppLayerParserThreadCtxFree(alp_tctx);
6435 StreamTcpFreeConfig(TRUE);
e78e33a4
VJ
6436 UTHFreeFlow(f);
6437 return result;
6438}
6439
a1075ee2 6440/** \test CONNECT with plain text HTTP being tunneled */
ab1200fb 6441static int HTPParserTest17(void)
a1075ee2
VJ
6442{
6443 int result = 0;
6444 Flow *f = NULL;
6445 HtpState *http_state = NULL;
6446 /* CONNECT setup */
6447 uint8_t httpbuf1[] = "CONNECT abc:443 HTTP/1.1\r\nUser-Agent: Victor/1.0\r\n\r\n";
6448 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
6449 uint8_t httpbuf2[] = "HTTP/1.1 200 OK\r\nServer: VictorServer/1.0\r\n\r\n";
6450 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
6451 /* plain text HTTP */
6452 uint8_t httpbuf3[] = "GET / HTTP/1.1\r\nUser-Agent: Victor/1.0\r\n\r\n";
6453 uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
6454 uint8_t httpbuf4[] = "HTTP/1.1 200 OK\r\nServer: VictorServer/1.0\r\n\r\n";
6455 uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
6456 TcpSession ssn;
6457 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
6458
6459 memset(&ssn, 0, sizeof(ssn));
6460
6461 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
6462 if (f == NULL)
6463 goto end;
6464 f->protoctx = &ssn;
6465 f->proto = IPPROTO_TCP;
5c01b409 6466 f->alproto = ALPROTO_HTTP;
a1075ee2
VJ
6467
6468 StreamTcpInitConfig(TRUE);
6469
6530c3d0 6470 FLOWLOCK_WRLOCK(f);
675fa564
GL
6471 int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
6472 STREAM_TOSERVER | STREAM_START, httpbuf1,
6473 httplen1);
a1075ee2
VJ
6474 if (r != 0) {
6475 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
6530c3d0 6476 FLOWLOCK_UNLOCK(f);
a1075ee2
VJ
6477 goto end;
6478 }
6479
675fa564
GL
6480 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
6481 STREAM_TOCLIENT | STREAM_START, httpbuf2,
a1075ee2
VJ
6482 httplen2);
6483 if (r != 0) {
6484 printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
6530c3d0 6485 FLOWLOCK_UNLOCK(f);
a1075ee2
VJ
6486 goto end;
6487 }
675fa564
GL
6488 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER,
6489 httpbuf3, httplen3);
a1075ee2
VJ
6490 if (r != 0) {
6491 printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
6530c3d0 6492 FLOWLOCK_UNLOCK(f);
a1075ee2
VJ
6493 goto end;
6494 }
6495
675fa564
GL
6496 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT,
6497 httpbuf4, httplen4);
a1075ee2
VJ
6498 if (r != 0) {
6499 printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
6530c3d0 6500 FLOWLOCK_UNLOCK(f);
a1075ee2
VJ
6501 goto end;
6502 }
6503
6530c3d0 6504 FLOWLOCK_UNLOCK(f);
a1075ee2
VJ
6505
6506 http_state = f->alstate;
6507 if (http_state == NULL) {
6508 printf("no http state: ");
6509 goto end;
6510 }
6511
6512 htp_tx_t *tx = HTPStateGetTx(http_state, 0);
6513 if (tx == NULL)
6514 goto end;
6515 htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
6516 if (tx->request_method_number != HTP_M_CONNECT ||
6517 h == NULL || tx->request_protocol_number != HTP_PROTOCOL_1_1)
6518 {
6519 printf("expected method M_POST and got %s: , expected protocol "
6520 "HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method),
6521 bstr_util_strdup_to_c(tx->request_protocol));
6522 goto end;
6523 }
6524
6525 if (tx->response_status_number != 200) {
6526 printf("expected response 200 OK and got %"PRId32" %s: , expected protocol "
6527 "HTTP/1.1 and got %s \n", tx->response_status_number,
6528 bstr_util_strdup_to_c(tx->response_message),
6529 bstr_util_strdup_to_c(tx->response_protocol));
6530 goto end;
6531 }
6532
6533 tx = HTPStateGetTx(http_state, 1);
6534 if (tx == NULL)
6535 goto end;
6536 h = htp_table_get_index(tx->request_headers, 0, NULL);
6537 if (tx->request_method_number != HTP_M_GET ||
6538 h == NULL || tx->request_protocol_number != HTP_PROTOCOL_1_1)
6539 {
6540 printf("expected method M_GET and got %s: , expected protocol "
6541 "HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method),
6542 bstr_util_strdup_to_c(tx->request_protocol));
6543 goto end;
6544 }
6545
6546 if (tx->response_status_number != 200) {
6547 printf("expected response 200 OK and got %"PRId32" %s: , expected protocol "
6548 "HTTP/1.1 and got %s \n", tx->response_status_number,
6549 bstr_util_strdup_to_c(tx->response_message),
6550 bstr_util_strdup_to_c(tx->response_protocol));
6551 goto end;
6552 }
6553 result = 1;
6554end:
6555 if (alp_tctx != NULL)
6556 AppLayerParserThreadCtxFree(alp_tctx);
6557 StreamTcpFreeConfig(TRUE);
a1075ee2
VJ
6558 UTHFreeFlow(f);
6559 return result;
6560}
6561
6562/** \test CONNECT with plain text HTTP being tunneled */
ab1200fb 6563static int HTPParserTest18(void)
a1075ee2
VJ
6564{
6565 int result = 0;
6566 Flow *f = NULL;
6567 HtpState *http_state = NULL;
6568 /* CONNECT setup */
6569 uint8_t httpbuf1[] = "CONNECT abc:443 HTTP/1.1\r\nUser-Agent: Victor/1.0\r\n\r\n";
6570 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
6571 uint8_t httpbuf2[] = "HTTP/1.1 200 OK\r\nServer: VictorServer/1.0\r\n\r\n";
6572 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
6573 /* plain text HTTP */
6574 uint8_t httpbuf3[] = "GE";
6575 uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
6576 uint8_t httpbuf4[] = "T / HTTP/1.1\r\nUser-Agent: Victor/1.0\r\n\r\n";
6577 uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
6578 uint8_t httpbuf5[] = "HTTP/1.1 200 OK\r\nServer: VictorServer/1.0\r\n\r\n";
6579 uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
6580 TcpSession ssn;
6581 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
6582
6583 memset(&ssn, 0, sizeof(ssn));
6584
6585 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
6586 if (f == NULL)
6587 goto end;
6588 f->protoctx = &ssn;
6589 f->proto = IPPROTO_TCP;
5c01b409 6590 f->alproto = ALPROTO_HTTP;
a1075ee2
VJ
6591
6592 StreamTcpInitConfig(TRUE);
6593
6530c3d0 6594 FLOWLOCK_WRLOCK(f);
675fa564
GL
6595 int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
6596 STREAM_TOSERVER | STREAM_START, httpbuf1,
6597 httplen1);
a1075ee2
VJ
6598 if (r != 0) {
6599 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
6530c3d0 6600 FLOWLOCK_UNLOCK(f);
a1075ee2
VJ
6601 goto end;
6602 }
6603
675fa564
GL
6604 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
6605 STREAM_TOCLIENT | STREAM_START, httpbuf2,
a1075ee2
VJ
6606 httplen2);
6607 if (r != 0) {
6608 printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
6530c3d0 6609 FLOWLOCK_UNLOCK(f);
a1075ee2
VJ
6610 goto end;
6611 }
675fa564
GL
6612 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER,
6613 httpbuf3, httplen3);
a1075ee2
VJ
6614 if (r != 0) {
6615 printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
6530c3d0 6616 FLOWLOCK_UNLOCK(f);
a1075ee2
VJ
6617 goto end;
6618 }
675fa564
GL
6619 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER,
6620 httpbuf4, httplen4);
a1075ee2
VJ
6621 if (r != 0) {
6622 printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
6530c3d0 6623 FLOWLOCK_UNLOCK(f);
a1075ee2
VJ
6624 goto end;
6625 }
6626
6627
675fa564
GL
6628 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT,
6629 httpbuf5, httplen5);
a1075ee2
VJ
6630 if (r != 0) {
6631 printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r);
6530c3d0 6632 FLOWLOCK_UNLOCK(f);
a1075ee2
VJ
6633 goto end;
6634 }
6635
6530c3d0 6636 FLOWLOCK_UNLOCK(f);
a1075ee2
VJ
6637
6638 http_state = f->alstate;
6639 if (http_state == NULL) {
6640 printf("no http state: ");
6641 goto end;
6642 }
6643
6644 htp_tx_t *tx = HTPStateGetTx(http_state, 0);
6645 if (tx == NULL)
6646 goto end;
6647 htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
6648 if (tx->request_method_number != HTP_M_CONNECT ||
6649 h == NULL || tx->request_protocol_number != HTP_PROTOCOL_1_1)
6650 {
6651 printf("expected method M_POST and got %s: , expected protocol "
6652 "HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method),
6653 bstr_util_strdup_to_c(tx->request_protocol));
6654 goto end;
6655 }
6656
6657 if (tx->response_status_number != 200) {
6658 printf("expected response 200 OK and got %"PRId32" %s: , expected protocol "
6659 "HTTP/1.1 and got %s \n", tx->response_status_number,
6660 bstr_util_strdup_to_c(tx->response_message),
6661 bstr_util_strdup_to_c(tx->response_protocol));
6662 goto end;
6663 }
6664
6665 tx = HTPStateGetTx(http_state, 1);
6666 if (tx == NULL)
6667 goto end;
6668 h = htp_table_get_index(tx->request_headers, 0, NULL);
6669 if (tx->request_method_number != HTP_M_GET ||
6670 h == NULL || tx->request_protocol_number != HTP_PROTOCOL_1_1)
6671 {
6672 printf("expected method M_GET and got %s: , expected protocol "
6673 "HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method),
6674 bstr_util_strdup_to_c(tx->request_protocol));
6675 goto end;
6676 }
6677
6678 if (tx->response_status_number != 200) {
6679 printf("expected response 200 OK and got %"PRId32" %s: , expected protocol "
6680 "HTTP/1.1 and got %s \n", tx->response_status_number,
6681 bstr_util_strdup_to_c(tx->response_message),
6682 bstr_util_strdup_to_c(tx->response_protocol));
6683 goto end;
6684 }
6685 result = 1;
6686end:
6687 if (alp_tctx != NULL)
6688 AppLayerParserThreadCtxFree(alp_tctx);
6689 StreamTcpFreeConfig(TRUE);
a1075ee2
VJ
6690 UTHFreeFlow(f);
6691 return result;
6692}
6693
6694/** \test CONNECT with TLS content (start of it at least) */
ab1200fb 6695static int HTPParserTest19(void)
a1075ee2
VJ
6696{
6697 int result = 0;
6698 Flow *f = NULL;
6699 HtpState *http_state = NULL;
6700 /* CONNECT setup */
6701 uint8_t httpbuf1[] = "CONNECT abc:443 HTTP/1.1\r\nUser-Agent: Victor/1.0\r\n\r\n";
6702 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
6703 uint8_t httpbuf2[] = "HTTP/1.1 200 OK\r\nServer: VictorServer/1.0\r\n\r\n";
6704 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
6705 /* start of TLS/SSL */
6706 uint8_t httpbuf3[] = "\x16\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
6707 uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
6708 TcpSession ssn;
6709 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
6710
6711 memset(&ssn, 0, sizeof(ssn));
6712
6713 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
6714 if (f == NULL)
6715 goto end;
6716 f->protoctx = &ssn;
6717 f->proto = IPPROTO_TCP;
5c01b409 6718 f->alproto = ALPROTO_HTTP;
a1075ee2
VJ
6719
6720 StreamTcpInitConfig(TRUE);
6721
6530c3d0 6722 FLOWLOCK_WRLOCK(f);
675fa564
GL
6723 int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
6724 STREAM_TOSERVER | STREAM_START, httpbuf1,
6725 httplen1);
a1075ee2
VJ
6726 if (r != 0) {
6727 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
6530c3d0 6728 FLOWLOCK_UNLOCK(f);
a1075ee2
VJ
6729 goto end;
6730 }
6731
675fa564
GL
6732 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
6733 STREAM_TOCLIENT | STREAM_START, httpbuf2,
a1075ee2
VJ
6734 httplen2);
6735 if (r != 0) {
6736 printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
6530c3d0 6737 FLOWLOCK_UNLOCK(f);
a1075ee2
VJ
6738 goto end;
6739 }
675fa564
GL
6740 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER,
6741 httpbuf3, httplen3);
a1075ee2
VJ
6742 if (r != 0) {
6743 printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
6530c3d0 6744 FLOWLOCK_UNLOCK(f);
a1075ee2
VJ
6745 goto end;
6746 }
6747
6530c3d0 6748 FLOWLOCK_UNLOCK(f);
a1075ee2
VJ
6749
6750 http_state = f->alstate;
6751 if (http_state == NULL) {
6752 printf("no http state: ");
6753 goto end;
6754 }
6755
6756 htp_tx_t *tx = HTPStateGetTx(http_state, 0);
6757 if (tx == NULL)
6758 goto end;
6759 htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
6760 if (tx->request_method_number != HTP_M_CONNECT ||
6761 h == NULL || tx->request_protocol_number != HTP_PROTOCOL_1_1)
6762 {
6763 printf("expected method M_POST and got %s: , expected protocol "
6764 "HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method),
6765 bstr_util_strdup_to_c(tx->request_protocol));
6766 goto end;
6767 }
6768
6769 if (tx->response_status_number != 200) {
6770 printf("expected response 200 OK and got %"PRId32" %s: , expected protocol "
6771 "HTTP/1.1 and got %s \n", tx->response_status_number,
6772 bstr_util_strdup_to_c(tx->response_message),
6773 bstr_util_strdup_to_c(tx->response_protocol));
6774 goto end;
6775 }
6776
6777 /* no new tx should have been set up for the tunneled data */
6778 tx = HTPStateGetTx(http_state, 1);
6779 if (tx != NULL)
6780 goto end;
6781
6782 result = 1;
6783end:
6784 if (alp_tctx != NULL)
6785 AppLayerParserThreadCtxFree(alp_tctx);
6786 StreamTcpFreeConfig(TRUE);
a1075ee2
VJ
6787 UTHFreeFlow(f);
6788 return result;
6789}
6790
49927024
VJ
6791/** \test Test response not HTTP
6792 */
6793static int HTPParserTest20(void)
6794{
6795 Flow *f = NULL;
6796 uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
6797 "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
6798 "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
6799 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
6800 uint8_t httpbuf2[] = "NOTHTTP\r\nSOMEOTHERDATA";
6801 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
6802 uint8_t httpbuf3[] = "STILLNOTHTTP\r\nSOMEMOREOTHERDATA";
6803 uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
6804 TcpSession ssn;
6805 HtpState *http_state = NULL;
6806 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
6807 FAIL_IF_NULL(alp_tctx);
6808
6809 memset(&ssn, 0, sizeof(ssn));
6810
6811 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
6812 FAIL_IF_NULL(f);
6813 f->protoctx = &ssn;
6814 f->proto = IPPROTO_TCP;
6815 f->alproto = ALPROTO_HTTP;
6816
6817 StreamTcpInitConfig(TRUE);
6818
6819 int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
6820 STREAM_TOSERVER | STREAM_START, httpbuf1,
6821 httplen1);
6822 FAIL_IF(r != 0);
6823
6824 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
6825 STREAM_TOCLIENT | STREAM_START, httpbuf2,
6826 httplen2);
6827 FAIL_IF(r != 0);
6828
6829 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
6830 STREAM_TOCLIENT | STREAM_START, httpbuf3,
6831 httplen3);
6832 FAIL_IF(r != 0);
6833
6834 http_state = f->alstate;
6835 FAIL_IF_NULL(http_state);
6836 htp_tx_t *tx = HTPStateGetTx(http_state, 0);
6837 FAIL_IF_NULL(tx);
6838 htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
6839 FAIL_IF_NULL(h);
6840
6841 FAIL_IF(tx->request_method_number != HTP_M_GET);
6842 FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1);
6843
6844 FAIL_IF(tx->response_status_number != 0);
6845 FAIL_IF(tx->response_protocol_number != -1);
6846
6847 AppLayerParserThreadCtxFree(alp_tctx);
6848 StreamTcpFreeConfig(TRUE);
6849 UTHFreeFlow(f);
6850 PASS;
6851}
6852
6853/** \test Test response not HTTP
6854 */
6855static int HTPParserTest21(void)
6856{
6857 Flow *f = NULL;
6858 uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
6859 "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
6860 "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
6861 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
6862 uint8_t httpbuf2[] = "999 NOTHTTP REALLY\r\nSOMEOTHERDATA\r\n";
6863 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
6864 uint8_t httpbuf3[] = "STILLNOTHTTP\r\nSOMEMOREOTHERDATA";
6865 uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
6866 TcpSession ssn;
6867 HtpState *http_state = NULL;
6868 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
6869 FAIL_IF_NULL(alp_tctx);
6870
6871 memset(&ssn, 0, sizeof(ssn));
6872
6873 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
6874 FAIL_IF_NULL(f);
6875 f->protoctx = &ssn;
6876 f->proto = IPPROTO_TCP;
6877 f->alproto = ALPROTO_HTTP;
6878
6879 StreamTcpInitConfig(TRUE);
6880
6881 int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
6882 STREAM_TOSERVER | STREAM_START, httpbuf1,
6883 httplen1);
6884 FAIL_IF(r != 0);
6885
6886 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
6887 STREAM_TOCLIENT | STREAM_START, httpbuf2,
6888 httplen2);
6889 FAIL_IF(r != 0);
6890
6891 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
6892 STREAM_TOCLIENT | STREAM_START, httpbuf3,
6893 httplen3);
6894 FAIL_IF(r != 0);
6895
6896 http_state = f->alstate;
6897 FAIL_IF_NULL(http_state);
6898 htp_tx_t *tx = HTPStateGetTx(http_state, 0);
6899 FAIL_IF_NULL(tx);
6900 htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
6901 FAIL_IF_NULL(h);
6902
6903 FAIL_IF(tx->request_method_number != HTP_M_GET);
6904 FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1);
6905
6906 FAIL_IF(tx->response_status_number != 0);
6907 FAIL_IF(tx->response_protocol_number != -1);
6908
6909 AppLayerParserThreadCtxFree(alp_tctx);
6910 StreamTcpFreeConfig(TRUE);
6911 UTHFreeFlow(f);
6912 PASS;
6913}
6914
6915/** \test Test response not HTTP
6916 */
6917static int HTPParserTest22(void)
6918{
6919 Flow *f = NULL;
6920 uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
6921 "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
6922 "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
6923 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
6924 uint8_t httpbuf2[] = "\r\n0000=0000000/ASDF3_31.zip, 456723\r\n"
6925 "AAAAAA_0000=0000000/AAAAAAAA.zip,46725\r\n";
6926 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
6927 TcpSession ssn;
6928 HtpState *http_state = NULL;
6929 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
6930 FAIL_IF_NULL(alp_tctx);
6931
6932 memset(&ssn, 0, sizeof(ssn));
6933
6934 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
6935 FAIL_IF_NULL(f);
6936 f->protoctx = &ssn;
6937 f->proto = IPPROTO_TCP;
6938 f->alproto = ALPROTO_HTTP;
6939
6940 StreamTcpInitConfig(TRUE);
6941
6942 int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
6943 STREAM_TOSERVER | STREAM_START, httpbuf1,
6944 httplen1);
6945 FAIL_IF(r != 0);
6946
6947 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
6948 STREAM_TOCLIENT | STREAM_START, httpbuf2,
6949 httplen2);
6950 FAIL_IF(r != 0);
6951
6952 http_state = f->alstate;
6953 FAIL_IF_NULL(http_state);
6954 htp_tx_t *tx = HTPStateGetTx(http_state, 0);
6955 FAIL_IF_NULL(tx);
6956 htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
6957 FAIL_IF_NULL(h);
6958
6959 FAIL_IF(tx->request_method_number != HTP_M_GET);
6960 FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1);
6961
6962 FAIL_IF(tx->response_status_number != -0);
6963 FAIL_IF(tx->response_protocol_number != -1);
6964
6965 AppLayerParserThreadCtxFree(alp_tctx);
6966 StreamTcpFreeConfig(TRUE);
6967 UTHFreeFlow(f);
6968 PASS;
6969}
6970
6971/** \test Test response not HTTP
6972 */
6973static int HTPParserTest23(void)
6974{
6975 Flow *f = NULL;
6976 uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
6977 "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
6978 "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
6979 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
6980 uint8_t httpbuf2[] = "HTTP0000=0000000/ASDF3_31.zip, 456723\r\n"
6981 "AAAAAA_0000=0000000/AAAAAAAA.zip,46725\r\n";
6982 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
6983 TcpSession ssn;
6984 HtpState *http_state = NULL;
6985 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
6986 FAIL_IF_NULL(alp_tctx);
6987
6988 memset(&ssn, 0, sizeof(ssn));
6989
6990 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
6991 FAIL_IF_NULL(f);
6992 f->protoctx = &ssn;
6993 f->proto = IPPROTO_TCP;
6994 f->alproto = ALPROTO_HTTP;
6995
6996 StreamTcpInitConfig(TRUE);
6997
6998 int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
6999 STREAM_TOSERVER | STREAM_START, httpbuf1,
7000 httplen1);
7001 FAIL_IF(r != 0);
7002
7003 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
7004 STREAM_TOCLIENT | STREAM_START, httpbuf2,
7005 httplen2);
7006 FAIL_IF(r != 0);
7007
7008 http_state = f->alstate;
7009 FAIL_IF_NULL(http_state);
7010 htp_tx_t *tx = HTPStateGetTx(http_state, 0);
7011 FAIL_IF_NULL(tx);
7012 htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
7013 FAIL_IF_NULL(h);
7014
7015 FAIL_IF(tx->request_method_number != HTP_M_GET);
7016 FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1);
7017
7018 FAIL_IF(tx->response_status_number != -1);
7019 FAIL_IF(tx->response_protocol_number != -2);
7020
7021 AppLayerParserThreadCtxFree(alp_tctx);
7022 StreamTcpFreeConfig(TRUE);
7023 UTHFreeFlow(f);
7024 PASS;
7025}
7026
7027/** \test Test response not HTTP
7028 */
7029static int HTPParserTest24(void)
7030{
7031 Flow *f = NULL;
7032 uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
7033 "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
7034 "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
7035 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
7036 uint8_t httpbuf2[] = "HTTP/1.0 0000=0000000/ASDF3_31.zip, 456723\r\n"
7037 "AAAAAA_0000=0000000/AAAAAAAA.zip,46725\r\n";
7038 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
7039 TcpSession ssn;
7040 HtpState *http_state = NULL;
7041 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
7042 FAIL_IF_NULL(alp_tctx);
7043
7044 memset(&ssn, 0, sizeof(ssn));
7045
7046 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
7047 FAIL_IF_NULL(f);
7048 f->protoctx = &ssn;
7049 f->proto = IPPROTO_TCP;
7050 f->alproto = ALPROTO_HTTP;
7051
7052 StreamTcpInitConfig(TRUE);
7053
7054 int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
7055 STREAM_TOSERVER | STREAM_START, httpbuf1,
7056 httplen1);
7057 FAIL_IF(r != 0);
7058
7059 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
7060 STREAM_TOCLIENT | STREAM_START, httpbuf2,
7061 httplen2);
7062 FAIL_IF(r != 0);
7063
7064 http_state = f->alstate;
7065 FAIL_IF_NULL(http_state);
7066 htp_tx_t *tx = HTPStateGetTx(http_state, 0);
7067 FAIL_IF_NULL(tx);
7068 htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
7069 FAIL_IF_NULL(h);
7070
7071 FAIL_IF(tx->request_method_number != HTP_M_GET);
7072 FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1);
7073
7074 FAIL_IF(tx->response_status_number != -1);
7075 FAIL_IF(tx->response_protocol_number != HTP_PROTOCOL_1_0);
7076
7077 AppLayerParserThreadCtxFree(alp_tctx);
7078 StreamTcpFreeConfig(TRUE);
7079 UTHFreeFlow(f);
7080 PASS;
7081}
7082
d34e4106
VJ
7083/** \test multi transactions and cleanup */
7084static int HTPParserTest25(void)
7085{
7086 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
7087 FAIL_IF_NULL(alp_tctx);
7088
7089 StreamTcpInitConfig(TRUE);
7090 TcpSession ssn;
7091 memset(&ssn, 0, sizeof(ssn));
7092
7093 Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
7094 FAIL_IF_NULL(f);
7095 f->protoctx = &ssn;
7096 f->proto = IPPROTO_TCP;
7097 f->alproto = ALPROTO_HTTP;
7098
7099 const char *str = "GET / HTTP/1.1\r\nHost: www.google.com\r\nUser-Agent: Suricata/1.0\r\n\r\n";
7100 int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
7101 STREAM_TOSERVER | STREAM_START, (uint8_t *)str, strlen(str));
7102 FAIL_IF_NOT(r == 0);
7103 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
7104 STREAM_TOSERVER, (uint8_t *)str, strlen(str));
7105 FAIL_IF_NOT(r == 0);
7106 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
7107 STREAM_TOSERVER, (uint8_t *)str, strlen(str));
7108 FAIL_IF_NOT(r == 0);
7109 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
7110 STREAM_TOSERVER, (uint8_t *)str, strlen(str));
7111 FAIL_IF_NOT(r == 0);
7112 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
7113 STREAM_TOSERVER, (uint8_t *)str, strlen(str));
7114 FAIL_IF_NOT(r == 0);
7115 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
7116 STREAM_TOSERVER, (uint8_t *)str, strlen(str));
7117 FAIL_IF_NOT(r == 0);
7118 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
7119 STREAM_TOSERVER, (uint8_t *)str, strlen(str));
7120 FAIL_IF_NOT(r == 0);
7121 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
7122 STREAM_TOSERVER, (uint8_t *)str, strlen(str));
7123 FAIL_IF_NOT(r == 0);
7124
7125 str = "HTTP 1.1 200 OK\r\nServer: Suricata/1.0\r\nContent-Length: 8\r\n\r\nSuricata";
7126 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
7127 STREAM_TOCLIENT | STREAM_START, (uint8_t *)str, strlen(str));
7128 FAIL_IF_NOT(r == 0);
7129 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
7130 STREAM_TOCLIENT, (uint8_t *)str, strlen(str));
7131 FAIL_IF_NOT(r == 0);
7132 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
7133 STREAM_TOCLIENT, (uint8_t *)str, strlen(str));
7134 FAIL_IF_NOT(r == 0);
7135 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
7136 STREAM_TOCLIENT, (uint8_t *)str, strlen(str));
7137 FAIL_IF_NOT(r == 0);
7138 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
7139 STREAM_TOCLIENT, (uint8_t *)str, strlen(str));
7140 FAIL_IF_NOT(r == 0);
7141 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
7142 STREAM_TOCLIENT, (uint8_t *)str, strlen(str));
7143 FAIL_IF_NOT(r == 0);
7144 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
7145 STREAM_TOCLIENT, (uint8_t *)str, strlen(str));
7146 FAIL_IF_NOT(r == 0);
7147 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
7148 STREAM_TOCLIENT, (uint8_t *)str, strlen(str));
7149 FAIL_IF_NOT(r == 0);
7150
7151 AppLayerParserTransactionsCleanup(f);
7152
7153 uint64_t ret[4];
7154 UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]);
7155 FAIL_IF_NOT(ret[0] == 8); // inspect_id[0]
7156 FAIL_IF_NOT(ret[1] == 8); // inspect_id[1]
7157 FAIL_IF_NOT(ret[2] == 8); // log_id
7158 FAIL_IF_NOT(ret[3] == 8); // min_id
7159
7160 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
7161 STREAM_TOSERVER | STREAM_EOF, (uint8_t *)str, strlen(str));
7162 FAIL_IF_NOT(r == 0);
7163 AppLayerParserTransactionsCleanup(f);
7164
7165 UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]);
7166 FAIL_IF_NOT(ret[0] == 8); // inspect_id[0] not updated by ..Cleanup() until full tx is done
7167 FAIL_IF_NOT(ret[1] == 8); // inspect_id[1]
7168 FAIL_IF_NOT(ret[2] == 8); // log_id
7169 FAIL_IF_NOT(ret[3] == 8); // min_id
7170
7171 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
7172 STREAM_TOCLIENT | STREAM_EOF, (uint8_t *)str, strlen(str));
7173 FAIL_IF_NOT(r == 0);
7174 AppLayerParserTransactionsCleanup(f);
7175
7176 UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]);
7177 FAIL_IF_NOT(ret[0] == 9); // inspect_id[0]
7178 FAIL_IF_NOT(ret[1] == 9); // inspect_id[1]
7179 FAIL_IF_NOT(ret[2] == 9); // log_id
7180 FAIL_IF_NOT(ret[3] == 9); // min_id
7181
7182 HtpState *http_state = f->alstate;
7183 FAIL_IF_NULL(http_state);
7184
7185 AppLayerParserThreadCtxFree(alp_tctx);
7186 StreamTcpFreeConfig(TRUE);
7187 UTHFreeFlow(f);
7188
7189 PASS;
7190}
7191
de904db8
GL
7192static int HTPParserTest26(void)
7193{
7194 char input[] = "\
7195%YAML 1.1\n\
7196---\n\
7197libhtp:\n\
7198\n\
7199 default-config:\n\
7200 personality: IDS\n\
7201 request-body-limit: 1\n\
7202 response-body-limit: 1\n\
7203";
7204 ConfCreateContextBackup();
7205 ConfInit();
7206 HtpConfigCreateBackup();
7207 ConfYamlLoadString(input, strlen(input));
7208 HTPConfigure();
7209
7210 Packet *p1 = NULL;
7211 Packet *p2 = NULL;
7212 ThreadVars th_v;
7213 DetectEngineCtx *de_ctx = NULL;
7214 DetectEngineThreadCtx *det_ctx = NULL;
7215 Flow f;
7216 uint8_t httpbuf1[] = "GET /alice.txt HTTP/1.1\r\n\r\n";
7217 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
7218 uint8_t httpbuf2[] = "HTTP/1.1 200 OK\r\n"
7219 "Content-Type: text/plain\r\n"
7220 "Content-Length: 228\r\n\r\n"
7221 "Alice was beginning to get very tired of sitting by her sister on the bank."
7222 "Alice was beginning to get very tired of sitting by her sister on the bank.";
7223 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
7224 uint8_t httpbuf3[] = "Alice was beginning to get very tired of sitting by her sister on the bank.\r\n\r\n";
7225 uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
7226 TcpSession ssn;
7227 HtpState *http_state = NULL;
7228 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
7229 FAIL_IF_NULL(alp_tctx);
7230
7231 memset(&th_v, 0, sizeof(th_v));
7232 memset(&f, 0, sizeof(f));
7233 memset(&ssn, 0, sizeof(ssn));
7234
7235 p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
7236 p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
7237
7238 FLOW_INITIALIZE(&f);
7239 f.protoctx = (void *)&ssn;
7240 f.proto = IPPROTO_TCP;
7241 f.flags |= FLOW_IPV4;
7242
7243 p1->flow = &f;
7244 p1->flowflags |= FLOW_PKT_TOSERVER;
7245 p1->flowflags |= FLOW_PKT_ESTABLISHED;
7246 p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
7247 p2->flow = &f;
7248 p2->flowflags |= FLOW_PKT_TOCLIENT;
7249 p2->flowflags |= FLOW_PKT_ESTABLISHED;
7250 p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
7251 f.alproto = ALPROTO_HTTP;
7252
7253 StreamTcpInitConfig(TRUE);
7254
7255 de_ctx = DetectEngineCtxInit();
7256 FAIL_IF_NULL(de_ctx);
7257
7258 de_ctx->flags |= DE_QUIET;
7259
7260 de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any "
7261 "(filestore; sid:1; rev:1;)");
7262 FAIL_IF_NULL(de_ctx->sig_list);
7263
7264 SigGroupBuild(de_ctx);
7265 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
7266
7267
7268 int r = AppLayerParserParse(&th_v, alp_tctx, &f, ALPROTO_HTTP,
7269 STREAM_TOSERVER, httpbuf1,
7270 httplen1);
7271 FAIL_IF(r != 0);
7272
7273 http_state = f.alstate;
7274 FAIL_IF_NULL(http_state);
7275
7276 /* do detect */
7277 SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
7278
7279 FAIL_IF((PacketAlertCheck(p1, 1)));
7280
7281 /* do detect */
7282 SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
7283
7284 FAIL_IF((PacketAlertCheck(p1, 1)));
7285
7286 r = AppLayerParserParse(&th_v, alp_tctx, &f, ALPROTO_HTTP,
7287 STREAM_TOCLIENT, httpbuf2,
7288 httplen2);
7289 FAIL_IF(r != 0);
7290
7291 http_state = f.alstate;
7292 FAIL_IF_NULL(http_state);
7293
7294 /* do detect */
7295 SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
7296
7297 FAIL_IF(!(PacketAlertCheck(p2, 1)));
7298
7299 r = AppLayerParserParse(&th_v, alp_tctx, &f, ALPROTO_HTTP,
7300 STREAM_TOCLIENT, httpbuf3,
7301 httplen3);
7302 FAIL_IF(r != 0);
7303
7304 http_state = f.alstate;
7305 FAIL_IF_NULL(http_state);
7306
7307 FileContainer *ffc = HTPStateGetFiles(http_state, STREAM_TOCLIENT);
7308 FAIL_IF_NULL(ffc);
7309
7310 File *ptr = ffc->head;
7311 FAIL_IF(ptr->state != FILE_STATE_CLOSED);
7312
7313 AppLayerParserThreadCtxFree(alp_tctx);
7314 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
7315 DetectEngineCtxFree(de_ctx);
7316 StreamTcpFreeConfig(TRUE);
7317
7318 HTPFreeConfig();
7319 FLOW_DESTROY(&f);
7320 UTHFreePackets(&p1, 1);
7321 UTHFreePackets(&p2, 1);
7322 ConfDeInit();
7323 ConfRestoreContextBackup();
7324 HtpConfigRestoreBackup();
7325 PASS;
7326}
7327
7328static int HTPParserTest27(void)
7329{
7330 FileReassemblyDepthEnable(2000);
7331
7332 uint32_t len = 1000;
7333
7334 HtpTxUserData *tx_ud = SCMalloc(sizeof(HtpTxUserData));
7335 FAIL_IF_NULL(tx_ud);
7336
7337 tx_ud->tsflags |= HTP_STREAM_DEPTH_SET;
7338 tx_ud->request_body.content_len_so_far = 2500;
7339
7340 FAIL_IF(AppLayerHtpCheckStreamDepth(tx_ud->request_body.content_len_so_far, tx_ud->tsflags));
7341
7342 len = AppLayerHtpComputeChunkLength(tx_ud->request_body.content_len_so_far,
7343 0,
7344 FileReassemblyDepth(),
7345 tx_ud->tsflags,
7346 len);
7347 FAIL_IF(len != 1000);
7348
7349 SCFree(tx_ud);
7350
7351 PASS;
7352}
c352bff6
VJ
7353#endif /* UNITTESTS */
7354
07f7ba55
GS
7355/**
7356 * \brief Register the Unit tests for the HTTP protocol
7357 */
8f1d7503
KS
7358void HTPParserRegisterTests(void)
7359{
07f7ba55 7360#ifdef UNITTESTS
796dd522
JI
7361 UtRegisterTest("HTPParserTest01", HTPParserTest01);
7362 UtRegisterTest("HTPParserTest01a", HTPParserTest01a);
08af5ddd
VJ
7363 UtRegisterTest("HTPParserTest01b", HTPParserTest01b);
7364 UtRegisterTest("HTPParserTest01c", HTPParserTest01c);
796dd522
JI
7365 UtRegisterTest("HTPParserTest02", HTPParserTest02);
7366 UtRegisterTest("HTPParserTest03", HTPParserTest03);
7367 UtRegisterTest("HTPParserTest04", HTPParserTest04);
7368 UtRegisterTest("HTPParserTest05", HTPParserTest05);
7369 UtRegisterTest("HTPParserTest06", HTPParserTest06);
7370 UtRegisterTest("HTPParserTest07", HTPParserTest07);
7371 UtRegisterTest("HTPParserTest08", HTPParserTest08);
7372 UtRegisterTest("HTPParserTest09", HTPParserTest09);
7373 UtRegisterTest("HTPParserTest10", HTPParserTest10);
7374 UtRegisterTest("HTPParserTest11", HTPParserTest11);
7375 UtRegisterTest("HTPParserTest12", HTPParserTest12);
7376 UtRegisterTest("HTPParserTest13", HTPParserTest13);
7377 UtRegisterTest("HTPParserConfigTest01", HTPParserConfigTest01);
7378 UtRegisterTest("HTPParserConfigTest02", HTPParserConfigTest02);
7379 UtRegisterTest("HTPParserConfigTest03", HTPParserConfigTest03);
48cf0585 7380#if 0 /* disabled when we upgraded to libhtp 0.5.x */
028c6c17 7381 UtRegisterTest("HTPParserConfigTest04", HTPParserConfigTest04, 1);
48cf0585 7382#endif
a0ee6ade 7383
796dd522
JI
7384 UtRegisterTest("HTPParserDecodingTest01", HTPParserDecodingTest01);
7385 UtRegisterTest("HTPParserDecodingTest02", HTPParserDecodingTest02);
7386 UtRegisterTest("HTPParserDecodingTest03", HTPParserDecodingTest03);
7387 UtRegisterTest("HTPParserDecodingTest04", HTPParserDecodingTest04);
7388 UtRegisterTest("HTPParserDecodingTest05", HTPParserDecodingTest05);
7389 UtRegisterTest("HTPParserDecodingTest06", HTPParserDecodingTest06);
7390 UtRegisterTest("HTPParserDecodingTest07", HTPParserDecodingTest07);
7391 UtRegisterTest("HTPParserDecodingTest08", HTPParserDecodingTest08);
7392 UtRegisterTest("HTPParserDecodingTest09", HTPParserDecodingTest09);
7393
7394 UtRegisterTest("HTPBodyReassemblyTest01", HTPBodyReassemblyTest01);
7395
7396 UtRegisterTest("HTPSegvTest01", HTPSegvTest01);
7397
7398 UtRegisterTest("HTPParserTest14", HTPParserTest14);
7399 UtRegisterTest("HTPParserTest15", HTPParserTest15);
7400 UtRegisterTest("HTPParserTest16", HTPParserTest16);
7401 UtRegisterTest("HTPParserTest17", HTPParserTest17);
7402 UtRegisterTest("HTPParserTest18", HTPParserTest18);
7403 UtRegisterTest("HTPParserTest19", HTPParserTest19);
49927024
VJ
7404 UtRegisterTest("HTPParserTest20", HTPParserTest20);
7405 UtRegisterTest("HTPParserTest21", HTPParserTest21);
7406 UtRegisterTest("HTPParserTest22", HTPParserTest22);
7407 UtRegisterTest("HTPParserTest23", HTPParserTest23);
7408 UtRegisterTest("HTPParserTest24", HTPParserTest24);
d34e4106 7409 UtRegisterTest("HTPParserTest25", HTPParserTest25);
de904db8
GL
7410 UtRegisterTest("HTPParserTest26", HTPParserTest26);
7411 UtRegisterTest("HTPParserTest27", HTPParserTest27);
fcc21ae4 7412
a0ee6ade 7413 HTPFileParserRegisterTests();
1235c578 7414 HTPXFFParserRegisterTests();
07f7ba55
GS
7415#endif /* UNITTESTS */
7416}
7417
60a99915
EL
7418/**
7419 * @}
7420 */