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