suricata
app-layer-htp-file.c
Go to the documentation of this file.
1/* Copyright (C) 2007-2021 Open Information Security Foundation
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 */
17
18/**
19 * \file
20 *
21 * \author Victor Julien <victor@inliniac.net>
22 *
23 * This file provides HTTP protocol file handling support for the engine
24 * using the HTP library.
25 */
26
27#include "suricata-common.h"
28#include "app-layer-htp-file.h"
29#include "app-layer-htp-range.h"
30#include "app-layer-events.h"
31#include "util-validate.h"
32
34
35/**
36 * \brief Open the file with "filename" and pass the first chunk
37 * of data if any.
38 *
39 * \param s http state
40 * \param filename name of the file
41 * \param filename_len length of the name
42 * \param data data chunk (if any)
43 * \param data_len length of the data portion
44 * \param direction flow direction
45 *
46 * \retval 0 ok
47 * \retval -1 error
48 * \retval -2 not handling files on this flow
49 */
50int HTPFileOpen(HtpState *s, HtpTxUserData *tx, const uint8_t *filename, uint16_t filename_len,
51 const uint8_t *data, uint32_t data_len, uint8_t direction)
52{
53 int retval = 0;
54 uint16_t flags = 0;
55 FileContainer *files = NULL;
56
57 SCLogDebug("data %p data_len %"PRIu32, data, data_len);
58
59 if (direction & STREAM_TOCLIENT) {
60 files = &tx->files_tc;
61 flags = FileFlowFlagsToFlags(tx->tx_data.file_flags, STREAM_TOCLIENT);
62
63 // we shall not open a new file if there is a current one
65 } else {
66 files = &tx->files_ts;
67 flags = FileFlowFlagsToFlags(tx->tx_data.file_flags, STREAM_TOSERVER);
68 }
69
70 if (FileOpenFileWithId(files, &htp_sbcfg, s->file_track_id++, filename, filename_len, data,
71 data_len, flags) != 0) {
72 retval = -1;
73 } else {
74 const HTPCfgDir *cfg;
75 if (direction & STREAM_TOCLIENT) {
76 cfg = &s->cfg->response;
77 } else {
78 cfg = &s->cfg->request;
79 }
81 }
82
83 tx->tx_data.files_opened++;
84
85 SCReturnInt(retval);
86}
87
88/**
89 * Performs parsing of the content-range value
90 *
91 * @param[in] rawvalue
92 * @param[out] range
93 *
94 * @return HTP_STATUS_OK on success, HTP_STATUS_ERROR on failure.
95 */
96int HTPParseContentRange(const bstr *rawvalue, HTTPContentRange *range)
97{
98 uint32_t len = (uint32_t)bstr_len(rawvalue);
99 return SCHttpParseContentRange(range, bstr_ptr(rawvalue), len);
100}
101
102/**
103 * Performs parsing + checking of the content-range value
104 *
105 * @param[in] rawvalue
106 * @param[out] range
107 *
108 * @return HTP_STATUS_OK on success, HTP_STATUS_ERROR, -2, -3 on failure.
109 */
110static int HTPParseAndCheckContentRange(
111 const bstr *rawvalue, HTTPContentRange *range, HtpState *s, HtpTxUserData *htud)
112{
113 int r = HTPParseContentRange(rawvalue, range);
114 if (r != 0) {
116 s->events++;
117 SCLogDebug("parsing range failed, going back to normal file");
118 return r;
119 }
120 /* crparsed.end <= 0 means a range with only size
121 * this is the answer to an unsatisfied range with the whole file
122 * crparsed.size <= 0 means an unknown size, so we do not know
123 * when to close it...
124 */
125 if (range->end <= 0 || range->size <= 0) {
126 SCLogDebug("range without all information");
127 return -2;
128 } else if (range->end == range->size - 1 && range->start == 0) {
129 SCLogDebug("range without all information");
130 return -3;
131 } else if (range->start > range->end || range->end > range->size - 1) {
133 s->events++;
134 SCLogDebug("invalid range");
135 return -4;
136 }
137 return r;
138}
139
140/**
141 * \brief Sets range for a file
142 *
143 * \param s http state
144 * \param rawvalue raw header value
145 *
146 * \retval 0 ok
147 * \retval -1 error
148 */
149int HTPFileOpenWithRange(HtpState *s, HtpTxUserData *txud, const uint8_t *filename,
150 uint16_t filename_len, const uint8_t *data, uint32_t data_len, const htp_tx_t *tx,
151 const bstr *rawvalue, HtpTxUserData *htud)
152{
153 SCEnter();
154 uint16_t flags;
155
156 DEBUG_VALIDATE_BUG_ON(s == NULL);
157
158 // This function is only called STREAM_TOCLIENT from HtpResponseBodyHandle
159 HTTPContentRange crparsed;
160 if (HTPParseAndCheckContentRange(rawvalue, &crparsed, s, htud) != 0) {
161 // range is invalid, fall back to classic open
162 return HTPFileOpen(s, txud, filename, filename_len, data, data_len, STREAM_TOCLIENT);
163 }
164 flags = FileFlowToFlags(s->f, STREAM_TOCLIENT);
165 FileContainer *files = &txud->files_tc;
166
167 // we open a file for this specific range
168 if (FileOpenFileWithId(files, &htp_sbcfg, s->file_track_id++, filename, filename_len, data,
169 data_len, flags) != 0) {
170 SCReturnInt(-1);
171 } else {
172 const HTPCfgDir *cfg = &s->cfg->response;
174 }
175 txud->tx_data.files_opened++;
176
177 if (FileSetRange(files, crparsed.start, crparsed.end) < 0) {
178 SCLogDebug("set range failed");
179 }
180
181 // Then, we will try to handle reassembly of different ranges of the same file
182 uint8_t *keyurl;
183 uint32_t keylen;
184 if (htp_tx_request_hostname(tx) != NULL) {
185 uint32_t hlen = (uint32_t)bstr_len(htp_tx_request_hostname(tx));
186 if (hlen > UINT16_MAX) {
187 hlen = UINT16_MAX;
188 }
189 keylen = hlen + filename_len;
190 keyurl = SCMalloc(keylen);
191 if (keyurl == NULL) {
192 SCReturnInt(-1);
193 }
194 memcpy(keyurl, bstr_ptr(htp_tx_request_hostname(tx)), hlen);
195 memcpy(keyurl + hlen, filename, filename_len);
196 } else {
197 // do not reassemble file without host info
198 SCReturnInt(0);
199 }
201 htud->file_range = HttpRangeContainerOpenFile(keyurl, keylen, s->f, &crparsed, &htp_sbcfg,
202 filename, filename_len, flags, data, data_len);
203 SCFree(keyurl);
204 if (htud->file_range == NULL) {
205 SCReturnInt(-1);
206 }
207 SCReturnInt(0);
208}
209
210/**
211 * \brief Store a chunk of data in the flow
212 *
213 * \param s HtpState
214 * \param tx HtpTxUserData
215 * \param data data chunk (if any)
216 * \param data_len length of the data portion
217 * \param direction flow direction
218 *
219 * \retval 0 ok
220 * \retval -1 error
221 * \retval -2 file doesn't need storing
222 */
223int HTPFileStoreChunk(HtpTxUserData *tx, const uint8_t *data, uint32_t data_len, uint8_t direction)
224{
225 SCEnter();
226
227 int retval = 0;
228 int result = 0;
229 FileContainer *files = NULL;
230
231 if (direction & STREAM_TOCLIENT) {
232 files = &tx->files_tc;
233 } else {
234 files = &tx->files_ts;
235 }
236 SCLogDebug("files %p data %p data_len %" PRIu32, files, data, data_len);
237
238 if (files == NULL) {
239 SCLogDebug("no files in state");
240 retval = -1;
241 goto end;
242 }
243
244 if (tx->file_range != NULL) {
245 if (HttpRangeAppendData(&htp_sbcfg, tx->file_range, data, data_len) < 0) {
246 SCLogDebug("Failed to append data");
247 }
248 }
249
250 result = FileAppendData(files, &htp_sbcfg, data, data_len);
251 if (result == -1) {
252 SCLogDebug("appending data failed");
253 retval = -1;
254 } else if (result == -2) {
255 retval = -2;
256 }
257 SCLogDebug("result %u", result);
258
259end:
260 SCReturnInt(retval);
261}
262
263/** \brief close range, add reassembled file if possible
264 * \retval true if reassembled file was added
265 * \retval false if no reassembled file was added
266 */
268 const uint16_t flags, HttpRangeContainerBlock *c, const uint8_t *data, uint32_t data_len)
269{
270 bool added = false;
271 if (HttpRangeAppendData(sbcfg, c, data, data_len) < 0) {
272 SCLogDebug("Failed to append data");
273 }
274 if (c->container) {
275 // we only call HttpRangeClose if we may some new data
276 // ie we do not call it if we skipped all this range request
277 THashDataLock(c->container->hdata);
278 if (c->container->error) {
279 SCLogDebug("range in ERROR state");
280 }
281 File *ranged = HttpRangeClose(sbcfg, c, flags);
282 if (ranged && files) {
283 /* HtpState owns the constructed file now */
284 FileContainerAdd(files, ranged);
285 added = true;
286 }
287 DEBUG_VALIDATE_BUG_ON(ranged && !files);
288 THashDataUnlock(c->container->hdata);
289 }
290 return added;
291}
292
293/**
294 * \brief Close the file in the flow
295 *
296 * \param tx HtpTxUserData
297 * \param data data chunk if any
298 * \param data_len length of the data portion
299 * \param flags flags to indicate events
300 * \param direction flow direction
301 *
302 * Currently on the FLOW_FILE_TRUNCATED flag is implemented, indicating
303 * that the file isn't complete but we're stopping storing it.
304 *
305 * \retval 0 ok
306 * \retval -1 error
307 * \retval -2 not storing files on this flow/tx
308 */
310 HtpTxUserData *tx, const uint8_t *data, uint32_t data_len, uint8_t flags, uint8_t direction)
311{
312 SCEnter();
313
314 SCLogDebug("flags %04x FILE_TRUNCATED %s", flags, (flags & FILE_TRUNCATED) ? "true" : "false");
315
316 int retval = 0;
317 int result = 0;
318 FileContainer *files = NULL;
319
320 if (direction & STREAM_TOCLIENT) {
321 files = &tx->files_tc;
322 } else {
323 files = &tx->files_ts;
324 }
325
326 SCLogDebug("files %p data %p data_len %" PRIu32, files, data, data_len);
327
328 if (files == NULL) {
329 retval = -1;
330 goto end;
331 }
332
333 result = FileCloseFile(files, &htp_sbcfg, data, data_len, flags);
334 if (result == -1) {
335 retval = -1;
336 } else if (result == -2) {
337 retval = -2;
338 }
339 SCLogDebug("result %u", result);
340
341 if (tx->file_range != NULL) {
342 bool added =
343 HTPFileCloseHandleRange(&htp_sbcfg, files, flags, tx->file_range, data, data_len);
344 if (added) {
345 tx->tx_data.files_opened++;
346 }
348 tx->file_range = NULL;
349 }
350
351end:
352 SCReturnInt(retval);
353}
354
355#ifdef UNITTESTS
356#include "stream-tcp.h"
357#include "app-layer-parser.h"
358#include "util-unittest-helper.h"
359
360static int HTPFileParserTest01(void)
361{
362 uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
363 "Host: www.server.lan\r\n"
364 "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
365 "Content-Length: 215\r\n"
366 "\r\n"
367 "-----------------------------277531038314945\r\n"
368 "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
369 "Content-Type: image/jpeg\r\n"
370 "\r\n";
371
372 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
373 uint8_t httpbuf2[] = "filecontent\r\n"
374 "-----------------------------277531038314945--";
375 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
376
377 TcpSession ssn;
379 HtpState *http_state = NULL;
380 memset(&ssn, 0, sizeof(ssn));
381
382 Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
383 FAIL_IF_NULL(f);
384 f->protoctx = &ssn;
385 f->proto = IPPROTO_TCP;
387
389
390 SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
391 int r = AppLayerParserParse(
392 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
393 FAIL_IF_NOT(r == 0);
394
395 SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
397 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
398 FAIL_IF_NOT(r == 0);
399
400 http_state = f->alstate;
401 FAIL_IF_NULL(http_state);
402
403 htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
404 FAIL_IF_NULL(tx);
405 FAIL_IF_NULL(htp_tx_request_method(tx));
406
407 FAIL_IF(memcmp(bstr_util_strdup_to_c(htp_tx_request_method(tx)), "POST", 4) != 0);
408
411 UTHFreeFlow(f);
412 PASS;
413}
414
415static int HTPFileParserTest02(void)
416{
417 uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
418 "Host: www.server.lan\r\n"
419 "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
420 "Content-Length: 337\r\n"
421 "\r\n";
422 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
423
424 uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
425 "Content-Disposition: form-data; name=\"email\"\r\n"
426 "\r\n"
427 "someaddress@somedomain.lan\r\n";
428 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
429
430 uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
431 "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
432 "Content-Type: image/jpeg\r\n"
433 "\r\n";
434 uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
435
436 uint8_t httpbuf4[] = "filecontent\r\n"
437 "-----------------------------277531038314945--";
438 uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
439
440 TcpSession ssn;
441 HtpState *http_state = NULL;
443
444 memset(&ssn, 0, sizeof(ssn));
445
446 Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
447 FAIL_IF_NULL(f);
448 f->protoctx = &ssn;
449 f->proto = IPPROTO_TCP;
451
453
454 SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
455 int r = AppLayerParserParse(
456 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
457 FAIL_IF_NOT(r == 0);
458
459 SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
461 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
462 FAIL_IF_NOT(r == 0);
463
464 SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
466 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
467 FAIL_IF_NOT(r == 0);
468
469 SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
471 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
472 FAIL_IF_NOT(r == 0);
473
474 http_state = f->alstate;
475 FAIL_IF_NULL(http_state);
476
477 htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
478 FAIL_IF_NULL(tx);
479 FAIL_IF_NULL(htp_tx_request_method(tx));
480 FAIL_IF(memcmp(bstr_util_strdup_to_c(htp_tx_request_method(tx)), "POST", 4) != 0);
481 HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
482 FAIL_IF_NULL(tx_ud);
483 FAIL_IF_NULL(tx_ud->files_ts.tail);
485
488 UTHFreeFlow(f);
489 PASS;
490}
491
492static int HTPFileParserTest03(void)
493{
494 uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
495 "Host: www.server.lan\r\n"
496 "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
497 "Content-Length: 337\r\n"
498 "\r\n";
499 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
500
501 uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
502 "Content-Disposition: form-data; name=\"email\"\r\n"
503 "\r\n"
504 "someaddress@somedomain.lan\r\n";
505 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
506
507 uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
508 "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
509 "Content-Type: image/jpeg\r\n"
510 "\r\n";
511 uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
512
513 uint8_t httpbuf4[] = "file";
514 uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
515
516 uint8_t httpbuf5[] = "content\r\n";
517 uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
518
519 uint8_t httpbuf6[] = "-----------------------------277531038314945--";
520 uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
521
522 TcpSession ssn;
523 HtpState *http_state = NULL;
525
526 memset(&ssn, 0, sizeof(ssn));
527
528 Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
529 FAIL_IF_NULL(f);
530 f->protoctx = &ssn;
531 f->proto = IPPROTO_TCP;
533
535
536 SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
537 int r = AppLayerParserParse(
538 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
539 FAIL_IF_NOT(r == 0);
540
541 SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
543 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
544 FAIL_IF_NOT(r == 0);
545
546 SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
548 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
549 FAIL_IF_NOT(r == 0);
550
551 SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
553 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
554 FAIL_IF_NOT(r == 0);
555
556 SCLogDebug("\n>>>> processing chunk 5 size %u <<<<\n", httplen5);
558 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf5, httplen5);
559 FAIL_IF_NOT(r == 0);
560
561 SCLogDebug("\n>>>> processing chunk 6 size %u <<<<\n", httplen6);
563 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf6, httplen6);
564 FAIL_IF_NOT(r == 0);
565
566 http_state = f->alstate;
567 FAIL_IF_NULL(http_state);
568
569 htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
570 FAIL_IF_NULL(tx);
571 FAIL_IF_NULL(htp_tx_request_method(tx));
572
573 FAIL_IF(memcmp(bstr_util_strdup_to_c(htp_tx_request_method(tx)), "POST", 4) != 0);
574
575 HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
576 FAIL_IF_NULL(tx_ud);
577 FAIL_IF_NULL(tx_ud->files_ts.head);
578 FAIL_IF_NULL(tx_ud->files_ts.tail);
580 FAIL_IF(FileDataSize(tx_ud->files_ts.head) != 11);
581
584 UTHFreeFlow(f);
585 PASS;
586}
587
588static int HTPFileParserTest04(void)
589{
590 uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
591 "Host: www.server.lan\r\n"
592 "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
593 "Content-Length: 373\r\n"
594 "\r\n";
595 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
596
597 uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
598 "Content-Disposition: form-data; name=\"email\"\r\n"
599 "\r\n"
600 "someaddress@somedomain.lan\r\n";
601 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
602
603 uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
604 "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
605 "Content-Type: image/jpeg\r\n"
606 "\r\n";
607 uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
608
609 uint8_t httpbuf4[] = "file0123456789abcdefghijklmnopqrstuvwxyz";
610 uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
611
612 uint8_t httpbuf5[] = "content\r\n";
613 uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
614
615 uint8_t httpbuf6[] = "-----------------------------277531038314945--";
616 uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
617
618 TcpSession ssn;
619 HtpState *http_state = NULL;
621
622 memset(&ssn, 0, sizeof(ssn));
623
624 Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
625 FAIL_IF_NULL(f);
626 f->protoctx = &ssn;
627 f->proto = IPPROTO_TCP;
629
631
632 SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
633 int r = AppLayerParserParse(
634 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
635 FAIL_IF_NOT(r == 0);
636
637 SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
639 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
640 FAIL_IF_NOT(r == 0);
641
642 SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
644 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
645 FAIL_IF_NOT(r == 0);
646
647 SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
649 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
650 FAIL_IF_NOT(r == 0);
651
652 SCLogDebug("\n>>>> processing chunk 5 size %u <<<<\n", httplen5);
654 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf5, httplen5);
655 FAIL_IF_NOT(r == 0);
656
657 SCLogDebug("\n>>>> processing chunk 6 size %u <<<<\n", httplen6);
659 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf6, httplen6);
660 FAIL_IF_NOT(r == 0);
661
662 http_state = f->alstate;
663 FAIL_IF_NULL(http_state);
664
665 htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
666 FAIL_IF_NULL(tx);
667 FAIL_IF_NULL(htp_tx_request_method(tx));
668
669 FAIL_IF(memcmp(bstr_util_strdup_to_c(htp_tx_request_method(tx)), "POST", 4) != 0);
670
671 HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
672 FAIL_IF_NULL(tx_ud);
673 FAIL_IF_NULL(tx_ud->files_ts.head);
674 FAIL_IF_NULL(tx_ud->files_ts.tail);
676
679 UTHFreeFlow(f);
680 PASS;
681}
682
683static int HTPFileParserTest05(void)
684{
685 uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
686 "Host: www.server.lan\r\n"
687 "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
688 "Content-Length: 544\r\n"
689 "\r\n"
690 "-----------------------------277531038314945\r\n"
691 "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
692 "Content-Type: image/jpeg\r\n"
693 "\r\n"
694 "filecontent\r\n"
695 "-----------------------------277531038314945\r\n";
696 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
697 uint8_t httpbuf2[] = "Content-Disposition: form-data; name=\"uploadfile_1\"; filename=\"somepicture2.jpg\"\r\n"
698 "Content-Type: image/jpeg\r\n"
699 "\r\n"
700 "FILECONTENT\r\n"
701 "-----------------------------277531038314945--";
702 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
703
704 TcpSession ssn;
705 HtpState *http_state = NULL;
707
708 memset(&ssn, 0, sizeof(ssn));
709
710 Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
711 FAIL_IF_NULL(f);
712 f->protoctx = &ssn;
713 f->proto = IPPROTO_TCP;
715
717
718 SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1);
719 int r = AppLayerParserParse(
720 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
721 FAIL_IF_NOT(r == 0);
722
723 SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
725 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
726 FAIL_IF_NOT(r == 0);
727
728 http_state = f->alstate;
729 FAIL_IF_NULL(http_state);
730
731 htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
732 FAIL_IF_NULL(tx);
733 FAIL_IF_NULL(htp_tx_request_method(tx));
734
735 FAIL_IF(memcmp(bstr_util_strdup_to_c(htp_tx_request_method(tx)), "POST", 4) != 0);
736
737 HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
738 FAIL_IF_NULL(tx_ud);
739 FAIL_IF_NULL(tx_ud->files_ts.head);
740 FAIL_IF_NULL(tx_ud->files_ts.tail);
742
743 FAIL_IF(tx_ud->files_ts.head == tx_ud->files_ts.tail);
744 FAIL_IF(tx_ud->files_ts.head->next != tx_ud->files_ts.tail);
745
746 FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.head->sb, (uint8_t *)"filecontent", 11) !=
747 1);
748
749 FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.tail->sb, (uint8_t *)"FILECONTENT", 11) !=
750 1);
753 UTHFreeFlow(f);
754 PASS;
755}
756
757/** \test first multipart part contains file but doesn't end in first chunk */
758static int HTPFileParserTest06(void)
759{
760 uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
761 "Host: www.server.lan\r\n"
762 "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
763 "Content-Length: 544\r\n"
764 "\r\n"
765 "-----------------------------277531038314945\r\n"
766 "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
767 "Content-Type: image/jpeg\r\n"
768 "\r\n"
769 "filecontent\r\n"
770 "-----------------------------27753103831494";
771 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
772 uint8_t httpbuf2[] = "5\r\nContent-Disposition: form-data; name=\"uploadfile_1\"; filename=\"somepicture2.jpg\"\r\n"
773 "Content-Type: image/jpeg\r\n"
774 "\r\n"
775 "FILECONTENT\r\n"
776 "-----------------------------277531038314945--";
777 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
778
779 TcpSession ssn;
780 HtpState *http_state = NULL;
782
783 memset(&ssn, 0, sizeof(ssn));
784
785 Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
786 FAIL_IF_NULL(f);
787 f->protoctx = &ssn;
788 f->proto = IPPROTO_TCP;
790
792
793 SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1);
794 int r = AppLayerParserParse(
795 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
796 FAIL_IF_NOT(r == 0);
797
798 SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
800 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
801 FAIL_IF_NOT(r == 0);
802
803 http_state = f->alstate;
804 FAIL_IF_NULL(http_state);
805
806 htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
807 FAIL_IF_NULL(tx);
808 FAIL_IF_NULL(htp_tx_request_method(tx));
809
810 FAIL_IF(memcmp(bstr_util_strdup_to_c(htp_tx_request_method(tx)), "POST", 4) != 0);
811
812 HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
813 FAIL_IF_NULL(tx_ud);
814 FAIL_IF_NULL(tx_ud->files_ts.head);
815 FAIL_IF_NULL(tx_ud->files_ts.tail);
817
818 FAIL_IF(tx_ud->files_ts.head == tx_ud->files_ts.tail);
819 FAIL_IF(tx_ud->files_ts.head->next != tx_ud->files_ts.tail);
820
821 FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.head->sb, (uint8_t *)"filecontent", 11) !=
822 1);
823
824 FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.tail->sb, (uint8_t *)"FILECONTENT", 11) !=
825 1);
826
829 UTHFreeFlow(f);
830 PASS;
831}
832
833/** \test POST, but not multipart */
834static int HTPFileParserTest07(void)
835{
836 uint8_t httpbuf1[] = "POST /filename HTTP/1.1\r\n"
837 "Host: www.server.lan\r\n"
838 "Content-Length: 11\r\n"
839 "\r\n";
840 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
841 uint8_t httpbuf2[] = "FILECONTENT";
842 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
843
844 TcpSession ssn;
845 HtpState *http_state = NULL;
847
848 memset(&ssn, 0, sizeof(ssn));
849
850 Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
851 FAIL_IF_NULL(f);
852 f->protoctx = &ssn;
853 f->proto = IPPROTO_TCP;
855
857
858 SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1);
859 int r = AppLayerParserParse(
860 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
861 FAIL_IF_NOT(r == 0);
862
863 SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
865 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
866 FAIL_IF_NOT(r == 0);
867
868 http_state = f->alstate;
869 FAIL_IF_NULL(http_state);
870
871 htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
872 FAIL_IF_NULL(tx);
873 FAIL_IF_NULL(htp_tx_request_method(tx));
874 FAIL_IF(memcmp(bstr_util_strdup_to_c(htp_tx_request_method(tx)), "POST", 4) != 0);
875
876 HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
877 FAIL_IF_NULL(tx_ud);
878 FAIL_IF_NULL(tx_ud->files_ts.head);
879 FAIL_IF_NULL(tx_ud->files_ts.tail);
881
882 FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.tail->sb, (uint8_t *)"FILECONTENT", 11) !=
883 1);
884
887 UTHFreeFlow(f);
888 PASS;
889}
890
891static int HTPFileParserTest08(void)
892{
893 uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
894 "Host: www.server.lan\r\n"
895 "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
896 "Content-Length: 215\r\n"
897 "\r\n"
898 "-----------------------------277531038314945\r\n"
899 "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
900 "Content-Type: image/jpeg\r\n";
901
902 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
903 uint8_t httpbuf2[] = "filecontent\r\n\r\n"
904 "-----------------------------277531038314945--";
905 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
906
907 TcpSession ssn;
909 HtpState *http_state = NULL;
910 memset(&ssn, 0, sizeof(ssn));
911
912 Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
913 FAIL_IF_NULL(f);
914 f->protoctx = &ssn;
915 f->proto = IPPROTO_TCP;
917
919
920 SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
921 int r = AppLayerParserParse(
922 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
923 FAIL_IF_NOT(r == 0);
924
925 SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
927 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
928 FAIL_IF_NOT(r == 0);
929
930 http_state = f->alstate;
931 FAIL_IF_NULL(http_state);
932
933 void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
934 FAIL_IF_NULL(tx);
935
936 AppLayerDecoderEvents *decoder_events =
938 FAIL_IF_NULL(decoder_events);
939
940 FAIL_IF(decoder_events->cnt != 2);
941
944 UTHFreeFlow(f);
945 PASS;
946}
947
948/** \test invalid header: Somereallylongheaderstr: has no value */
949static int HTPFileParserTest09(void)
950{
951 uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
952 "Host: www.server.lan\r\n"
953 "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
954 "Content-Length: 337\r\n"
955 "\r\n";
956 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
957
958 uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
959 "Content-Disposition: form-data; name=\"email\"\r\n"
960 "\r\n"
961 "someaddress@somedomain.lan\r\n";
962 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
963
964 uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
965 "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
966 "Somereallylongheaderstr:\r\n"
967 "\r\n";
968 uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
969
970 uint8_t httpbuf4[] = "filecontent\r\n"
971 "-----------------------------277531038314945--";
972 uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
973
974 TcpSession ssn;
975 HtpState *http_state = NULL;
977
978 memset(&ssn, 0, sizeof(ssn));
979
980 Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
981 FAIL_IF_NULL(f);
982 f->protoctx = &ssn;
983 f->proto = IPPROTO_TCP;
985
987
988 SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
989 int r = AppLayerParserParse(
990 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
991 FAIL_IF_NOT(r == 0);
992
993 SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
995 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
996 FAIL_IF_NOT(r == 0);
997
998 SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
1000 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
1001 FAIL_IF_NOT(r == 0);
1002
1003 SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
1005 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1006 FAIL_IF_NOT(r == 0);
1007
1008 http_state = f->alstate;
1009 FAIL_IF_NULL(http_state);
1010
1011 void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
1012 FAIL_IF_NULL(tx);
1013
1014 AppLayerDecoderEvents *decoder_events =
1016 FAIL_IF_NULL(decoder_events);
1017
1018 FAIL_IF(decoder_events->cnt != 1);
1019
1021 StreamTcpFreeConfig(true);
1022 UTHFreeFlow(f);
1023 PASS;
1024}
1025
1026/** \test empty entries */
1027static int HTPFileParserTest10(void)
1028{
1029 uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
1030 "Host: www.server.lan\r\n"
1031 "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
1032 "Content-Length: 337\r\n"
1033 "\r\n";
1034 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1035
1036 uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
1037 "\r\n";
1038 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1039
1040 uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
1041 "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
1042 "Somereallylongheaderstr: with a good value\r\n"
1043 "\r\n";
1044 uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1045
1046 uint8_t httpbuf4[] = "filecontent\r\n"
1047 "-----------------------------277531038314945--";
1048 uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1049
1050 TcpSession ssn;
1051 HtpState *http_state = NULL;
1053
1054 memset(&ssn, 0, sizeof(ssn));
1055
1056 Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1057 FAIL_IF_NULL(f);
1058 f->protoctx = &ssn;
1059 f->proto = IPPROTO_TCP;
1061
1062 StreamTcpInitConfig(true);
1063
1064 SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
1065 int r = AppLayerParserParse(
1066 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
1067 FAIL_IF_NOT(r == 0);
1068
1069 SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
1071 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
1072 FAIL_IF_NOT(r == 0);
1073
1074 SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
1076 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
1077 FAIL_IF_NOT(r == 0);
1078
1079 SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
1081 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1082 FAIL_IF_NOT(r == 0);
1083
1084 http_state = f->alstate;
1085 FAIL_IF_NULL(http_state);
1086
1087 void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
1088 FAIL_IF_NULL(tx);
1089 AppLayerDecoderEvents *decoder_events =
1091 FAIL_IF_NOT_NULL(decoder_events);
1092
1094 StreamTcpFreeConfig(true);
1095 UTHFreeFlow(f);
1096 PASS;
1097}
1098
1099/** \test filedata cut in two pieces */
1100static int HTPFileParserTest11(void)
1101{
1102 uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
1103 "Host: www.server.lan\r\n"
1104 "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1105 "Content-Length: 1102\r\n"
1106 "\r\n";
1107 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1108
1109 uint8_t httpbuf2[] = "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n";
1110 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1111
1112 uint8_t httpbuf3[] = "Content-Disposition: form-data; name=\"PROGRESS_URL\"\r\n"
1113 "\r\n"
1114 "http://somserver.com/progress.php?UPLOAD_IDENTIFIER=XXXXXXXXX.XXXXXXXXXX.XXXXXXXX.XX.X\r\n"
1115 "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1116 "Content-Disposition: form-data; name=\"DESTINATION_DIR\"\r\n"
1117 "\r\n"
1118 "10\r\n"
1119 "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1120 "Content-Disposition: form-data; name=\"js_enabled\"\r\n"
1121 "\r\n"
1122 "1"
1123 "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1124 "Content-Disposition: form-data; name=\"signature\"\r\n"
1125 "\r\n"
1126 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n"
1127 "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1128 "Content-Disposition: form-data; name=\"upload_files\"\r\n"
1129 "\r\n"
1130 "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1131 "Content-Disposition: form-data; name=\"terms\"\r\n"
1132 "\r\n"
1133 "1"
1134 "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1135 "Content-Disposition: form-data; name=\"file[]\"\r\n"
1136 "\r\n"
1137 "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1138 "Content-Disposition: form-data; name=\"description[]\"\r\n"
1139 "\r\n"
1140 "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1141 "Content-Disposition: form-data; name=\"upload_file[]\"; filename=\"filename.doc\"\r\n"
1142 "Content-Type: application/msword\r\n"
1143 "\r\n"
1144 "FILE";
1145 uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1146
1147 uint8_t httpbuf4[] = "CONTENT\r\n"
1148 "------WebKitFormBoundaryBRDbP74mBhBxsIdo--";
1149 uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1150
1151 TcpSession ssn;
1152 HtpState *http_state = NULL;
1154
1155 memset(&ssn, 0, sizeof(ssn));
1156
1157 Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1158 FAIL_IF_NULL(f);
1159 f->protoctx = &ssn;
1160 f->proto = IPPROTO_TCP;
1162
1163 StreamTcpInitConfig(true);
1164
1165 SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
1166 int r = AppLayerParserParse(
1167 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
1168 FAIL_IF_NOT(r == 0);
1169
1170 SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
1171 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
1172 FAIL_IF_NOT(r == 0);
1173
1174 SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
1175 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf3, httplen3);
1176 FAIL_IF_NOT(r == 0);
1177
1178 SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
1180 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1181 FAIL_IF_NOT(r == 0);
1182
1183 http_state = f->alstate;
1184 FAIL_IF_NULL(http_state);
1185
1186 void *txtmp = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
1187 FAIL_IF_NULL(txtmp);
1188
1189 AppLayerDecoderEvents *decoder_events =
1190 AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, txtmp);
1191 FAIL_IF_NOT_NULL(decoder_events);
1192
1193 htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
1194 FAIL_IF_NULL(tx);
1195 FAIL_IF_NULL(htp_tx_request_method(tx));
1196
1197 FAIL_IF(memcmp(bstr_util_strdup_to_c(htp_tx_request_method(tx)), "POST", 4) != 0);
1198
1199 HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
1200 FAIL_IF_NULL(tx_ud);
1201 FAIL_IF_NULL(tx_ud->files_ts.head);
1202 FAIL_IF_NULL(tx_ud->files_ts.tail);
1204
1205 FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.tail->sb, (uint8_t *)"FILECONTENT", 11) !=
1206 1);
1207
1209 StreamTcpFreeConfig(true);
1210 UTHFreeFlow(f);
1211 PASS;
1212}
1213
1216#endif /* UNITTESTS */
1217
1219{
1220#ifdef UNITTESTS
1221 UtRegisterTest("HTPFileParserTest01", HTPFileParserTest01);
1222 UtRegisterTest("HTPFileParserTest02", HTPFileParserTest02);
1223 UtRegisterTest("HTPFileParserTest03", HTPFileParserTest03);
1224 UtRegisterTest("HTPFileParserTest04", HTPFileParserTest04);
1225 UtRegisterTest("HTPFileParserTest05", HTPFileParserTest05);
1226 UtRegisterTest("HTPFileParserTest06", HTPFileParserTest06);
1227 UtRegisterTest("HTPFileParserTest07", HTPFileParserTest07);
1228 UtRegisterTest("HTPFileParserTest08", HTPFileParserTest08);
1229 UtRegisterTest("HTPFileParserTest09", HTPFileParserTest09);
1230 UtRegisterTest("HTPFileParserTest10", HTPFileParserTest10);
1231 UtRegisterTest("HTPFileParserTest11", HTPFileParserTest11);
1233#endif /* UNITTESTS */
1234}
uint8_t len
void AppLayerDecoderEventsSetEventRaw(AppLayerDecoderEvents **sevents, uint8_t event)
Set an app layer decoder event.
void AppLayerHtpFileRegisterTests(void)
this function registers unit tests for AppLayerHtpFile
bool HTPFileCloseHandleRange(const StreamingBufferConfig *sbcfg, FileContainer *files, const uint16_t flags, HttpRangeContainerBlock *c, const uint8_t *data, uint32_t data_len)
close range, add reassembled file if possible
int HTPFileOpenWithRange(HtpState *s, HtpTxUserData *txud, const uint8_t *filename, uint16_t filename_len, const uint8_t *data, uint32_t data_len, const htp_tx_t *tx, const bstr *rawvalue, HtpTxUserData *htud)
Sets range for a file.
int HTPFileOpen(HtpState *s, HtpTxUserData *tx, const uint8_t *filename, uint16_t filename_len, const uint8_t *data, uint32_t data_len, uint8_t direction)
Open the file with "filename" and pass the first chunk of data if any.
int HTPFileClose(HtpTxUserData *tx, const uint8_t *data, uint32_t data_len, uint8_t flags, uint8_t direction)
Close the file in the flow.
int HTPFileStoreChunk(HtpTxUserData *tx, const uint8_t *data, uint32_t data_len, uint8_t direction)
Store a chunk of data in the flow.
void HTPFileParserRegisterTests(void)
int HTPParseContentRange(const bstr *rawvalue, HTTPContentRange *range)
StreamingBufferConfig htp_sbcfg
void HttpRangeFreeBlock(HttpRangeContainerBlock *b)
File * HttpRangeClose(const StreamingBufferConfig *sbcfg, HttpRangeContainerBlock *c, uint16_t flags)
int HttpRangeAppendData(const StreamingBufferConfig *sbcfg, HttpRangeContainerBlock *c, const uint8_t *data, uint32_t len)
HttpRangeContainerBlock * HttpRangeContainerOpenFile(const uint8_t *key, uint32_t keylen, const Flow *f, const HTTPContentRange *crparsed, const StreamingBufferConfig *sbcfg, const uint8_t *name, uint16_t name_len, uint16_t flags, const uint8_t *data, uint32_t data_len)
AppLayerParserThreadCtx * AppLayerParserThreadCtxAlloc(void)
Gets a new app layer protocol's parser thread context.
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
Destroys the app layer parser thread context obtained using AppLayerParserThreadCtxAlloc().
int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, uint8_t flags, const uint8_t *input, uint32_t input_len)
void * AppLayerParserGetTx(uint8_t ipproto, AppProto alproto, void *alstate, uint64_t tx_id)
AppLayerDecoderEvents * AppLayerParserGetEventsByTx(uint8_t ipproto, AppProto alproto, void *tx)
@ ALPROTO_HTTP1
uint8_t flags
Definition decode-gre.h:0
AppLayerParserThreadCtx * alp_tctx
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
#define PASS
Pass the test.
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
#define FAIL_IF_NOT_NULL(expr)
Fail a test if expression evaluates to non-NULL.
@ HTTP_DECODER_EVENT_RANGE_INVALID
void StreamTcpFreeConfig(bool quiet)
Definition stream-tcp.c:859
void StreamTcpInitConfig(bool)
To initialize the stream global configuration data.
Definition stream-tcp.c:488
Data structure to store app layer decoder events.
StreamingBuffer * sb
Definition util-file.h:83
FileState state
Definition util-file.h:82
struct File_ * next
Definition util-file.h:92
Flow data structure.
Definition flow.h:356
uint8_t proto
Definition flow.h:378
AppProto alproto
application level protocol
Definition flow.h:450
void * alstate
Definition flow.h:479
void * protoctx
Definition flow.h:441
uint32_t inspect_window
uint32_t inspect_min_size
HTPCfgDir request
HTPCfgDir response
uint16_t events
const struct HTPCfgRec_ * cfg
uint32_t file_track_id
FileContainer files_ts
HttpRangeContainerBlock * file_range
AppLayerTxData tx_data
FileContainer files_tc
HttpRangeContainerFile * container
#define SCEnter(...)
Definition util-debug.h:277
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCReturnInt(x)
Definition util-debug.h:281
int FileAppendData(FileContainer *ffc, const StreamingBufferConfig *sbcfg, const uint8_t *data, uint32_t data_len)
Store/handle a chunk of file data in the File structure The last file in the FileContainer will be us...
Definition util-file.c:766
uint64_t FileDataSize(const File *file)
get the size of the file data
Definition util-file.c:309
uint16_t FileFlowFlagsToFlags(const uint16_t flow_file_flags, uint8_t direction)
Definition util-file.c:216
void FileContainerAdd(FileContainer *ffc, File *ff)
Definition util-file.c:595
int FileCloseFile(FileContainer *ffc, const StreamingBufferConfig *sbcfg, const uint8_t *data, uint32_t data_len, uint16_t flags)
Close a File.
Definition util-file.c:1062
void FileSetInspectSizes(File *file, const uint32_t win, const uint32_t min)
Definition util-file.c:843
uint16_t FileFlowToFlags(const Flow *flow, uint8_t direction)
Definition util-file.c:273
int FileSetRange(FileContainer *ffc, uint64_t start, uint64_t end)
Sets the offset range for a file.
Definition util-file.c:859
int FileOpenFileWithId(FileContainer *ffc, const StreamingBufferConfig *sbcfg, uint32_t track_id, const uint8_t *name, uint16_t name_len, const uint8_t *data, uint32_t data_len, uint16_t flags)
Open a new File.
Definition util-file.c:967
#define FILE_TRUNCATED
Definition util-file.h:45
@ FILE_STATE_CLOSED
Definition util-file.h:71
#define SCMalloc(sz)
Definition util-mem.h:47
#define SCFree(p)
Definition util-mem.h:61
int StreamingBufferCompareRawData(const StreamingBuffer *sb, const uint8_t *rawdata, uint32_t rawdata_len)
void UTHFreeFlow(Flow *flow)
Flow * UTHBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp)
#define DEBUG_VALIDATE_BUG_ON(exp)