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