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