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