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  */
50 int 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 = SCFileFlowFlagsToFlags(tx->tx_data.file_flags, STREAM_TOCLIENT);
62 
63  // we shall not open a new file if there is a current one
64  DEBUG_VALIDATE_BUG_ON(tx->file_range != NULL);
65  } else {
66  files = &tx->files_ts;
67  flags = SCFileFlowFlagsToFlags(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  */
96 int 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  */
110 static 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  */
149 int 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 = SCHttpRangeContainerOpenFile(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  */
223 int 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 (SCHttpRangeAppendData(&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 
259 end:
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 (SCHttpRangeAppendData(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  SCHTPFileCloseHandleRange(&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 
351 end:
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 
360 static 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;
386  f->alproto = ALPROTO_HTTP1;
387 
388  StreamTcpInitConfig(true);
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  char *m = bstr_util_strdup_to_c(htp_tx_request_method(tx));
408  FAIL_IF(memcmp(m, "POST", 4) != 0);
409  SCFree(m);
410 
412  StreamTcpFreeConfig(true);
413  UTHFreeFlow(f);
414  PASS;
415 }
416 
417 static int HTPFileParserTest02(void)
418 {
419  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
420  "Host: www.server.lan\r\n"
421  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
422  "Content-Length: 337\r\n"
423  "\r\n";
424  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
425 
426  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
427  "Content-Disposition: form-data; name=\"email\"\r\n"
428  "\r\n"
429  "someaddress@somedomain.lan\r\n";
430  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
431 
432  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
433  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
434  "Content-Type: image/jpeg\r\n"
435  "\r\n";
436  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
437 
438  uint8_t httpbuf4[] = "filecontent\r\n"
439  "-----------------------------277531038314945--";
440  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
441 
442  TcpSession ssn;
443  HtpState *http_state = NULL;
445 
446  memset(&ssn, 0, sizeof(ssn));
447 
448  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
449  FAIL_IF_NULL(f);
450  f->protoctx = &ssn;
451  f->proto = IPPROTO_TCP;
452  f->alproto = ALPROTO_HTTP1;
453 
454  StreamTcpInitConfig(true);
455 
456  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
457  int r = AppLayerParserParse(
458  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
459  FAIL_IF_NOT(r == 0);
460 
461  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
463  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
464  FAIL_IF_NOT(r == 0);
465 
466  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
468  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
469  FAIL_IF_NOT(r == 0);
470 
471  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
473  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
474  FAIL_IF_NOT(r == 0);
475 
476  http_state = f->alstate;
477  FAIL_IF_NULL(http_state);
478 
479  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
480  FAIL_IF_NULL(tx);
481  FAIL_IF_NULL(htp_tx_request_method(tx));
482  char *m = bstr_util_strdup_to_c(htp_tx_request_method(tx));
483  FAIL_IF(memcmp(m, "POST", 4) != 0);
484  SCFree(m);
485  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
486  FAIL_IF_NULL(tx_ud);
487  FAIL_IF_NULL(tx_ud->files_ts.tail);
489 
491  StreamTcpFreeConfig(true);
492  UTHFreeFlow(f);
493  PASS;
494 }
495 
496 static int HTPFileParserTest03(void)
497 {
498  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
499  "Host: www.server.lan\r\n"
500  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
501  "Content-Length: 337\r\n"
502  "\r\n";
503  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
504 
505  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
506  "Content-Disposition: form-data; name=\"email\"\r\n"
507  "\r\n"
508  "someaddress@somedomain.lan\r\n";
509  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
510 
511  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
512  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
513  "Content-Type: image/jpeg\r\n"
514  "\r\n";
515  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
516 
517  uint8_t httpbuf4[] = "file";
518  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
519 
520  uint8_t httpbuf5[] = "content\r\n";
521  uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
522 
523  uint8_t httpbuf6[] = "-----------------------------277531038314945--";
524  uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
525 
526  TcpSession ssn;
527  HtpState *http_state = NULL;
529 
530  memset(&ssn, 0, sizeof(ssn));
531 
532  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
533  FAIL_IF_NULL(f);
534  f->protoctx = &ssn;
535  f->proto = IPPROTO_TCP;
536  f->alproto = ALPROTO_HTTP1;
537 
538  StreamTcpInitConfig(true);
539 
540  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
541  int r = AppLayerParserParse(
542  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
543  FAIL_IF_NOT(r == 0);
544 
545  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
547  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
548  FAIL_IF_NOT(r == 0);
549 
550  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
552  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
553  FAIL_IF_NOT(r == 0);
554 
555  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
557  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
558  FAIL_IF_NOT(r == 0);
559 
560  SCLogDebug("\n>>>> processing chunk 5 size %u <<<<\n", httplen5);
562  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf5, httplen5);
563  FAIL_IF_NOT(r == 0);
564 
565  SCLogDebug("\n>>>> processing chunk 6 size %u <<<<\n", httplen6);
567  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf6, httplen6);
568  FAIL_IF_NOT(r == 0);
569 
570  http_state = f->alstate;
571  FAIL_IF_NULL(http_state);
572 
573  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
574  FAIL_IF_NULL(tx);
575  FAIL_IF_NULL(htp_tx_request_method(tx));
576 
577  char *m = bstr_util_strdup_to_c(htp_tx_request_method(tx));
578  FAIL_IF(memcmp(m, "POST", 4) != 0);
579  SCFree(m);
580 
581  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
582  FAIL_IF_NULL(tx_ud);
583  FAIL_IF_NULL(tx_ud->files_ts.head);
584  FAIL_IF_NULL(tx_ud->files_ts.tail);
586  FAIL_IF(FileDataSize(tx_ud->files_ts.head) != 11);
587 
589  StreamTcpFreeConfig(true);
590  UTHFreeFlow(f);
591  PASS;
592 }
593 
594 static int HTPFileParserTest04(void)
595 {
596  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
597  "Host: www.server.lan\r\n"
598  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
599  "Content-Length: 373\r\n"
600  "\r\n";
601  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
602 
603  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
604  "Content-Disposition: form-data; name=\"email\"\r\n"
605  "\r\n"
606  "someaddress@somedomain.lan\r\n";
607  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
608 
609  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
610  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
611  "Content-Type: image/jpeg\r\n"
612  "\r\n";
613  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
614 
615  uint8_t httpbuf4[] = "file0123456789abcdefghijklmnopqrstuvwxyz";
616  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
617 
618  uint8_t httpbuf5[] = "content\r\n";
619  uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
620 
621  uint8_t httpbuf6[] = "-----------------------------277531038314945--";
622  uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
623 
624  TcpSession ssn;
625  HtpState *http_state = NULL;
627 
628  memset(&ssn, 0, sizeof(ssn));
629 
630  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
631  FAIL_IF_NULL(f);
632  f->protoctx = &ssn;
633  f->proto = IPPROTO_TCP;
634  f->alproto = ALPROTO_HTTP1;
635 
636  StreamTcpInitConfig(true);
637 
638  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
639  int r = AppLayerParserParse(
640  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
641  FAIL_IF_NOT(r == 0);
642 
643  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
645  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
646  FAIL_IF_NOT(r == 0);
647 
648  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
650  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
651  FAIL_IF_NOT(r == 0);
652 
653  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
655  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
656  FAIL_IF_NOT(r == 0);
657 
658  SCLogDebug("\n>>>> processing chunk 5 size %u <<<<\n", httplen5);
660  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf5, httplen5);
661  FAIL_IF_NOT(r == 0);
662 
663  SCLogDebug("\n>>>> processing chunk 6 size %u <<<<\n", httplen6);
665  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf6, httplen6);
666  FAIL_IF_NOT(r == 0);
667 
668  http_state = f->alstate;
669  FAIL_IF_NULL(http_state);
670 
671  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
672  FAIL_IF_NULL(tx);
673  FAIL_IF_NULL(htp_tx_request_method(tx));
674 
675  char *m = bstr_util_strdup_to_c(htp_tx_request_method(tx));
676  FAIL_IF(memcmp(m, "POST", 4) != 0);
677  SCFree(m);
678 
679  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
680  FAIL_IF_NULL(tx_ud);
681  FAIL_IF_NULL(tx_ud->files_ts.head);
682  FAIL_IF_NULL(tx_ud->files_ts.tail);
684 
686  StreamTcpFreeConfig(true);
687  UTHFreeFlow(f);
688  PASS;
689 }
690 
691 static int HTPFileParserTest05(void)
692 {
693  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
694  "Host: www.server.lan\r\n"
695  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
696  "Content-Length: 544\r\n"
697  "\r\n"
698  "-----------------------------277531038314945\r\n"
699  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
700  "Content-Type: image/jpeg\r\n"
701  "\r\n"
702  "filecontent\r\n"
703  "-----------------------------277531038314945\r\n";
704  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
705  uint8_t httpbuf2[] = "Content-Disposition: form-data; name=\"uploadfile_1\"; filename=\"somepicture2.jpg\"\r\n"
706  "Content-Type: image/jpeg\r\n"
707  "\r\n"
708  "FILECONTENT\r\n"
709  "-----------------------------277531038314945--";
710  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
711 
712  TcpSession ssn;
713  HtpState *http_state = NULL;
715 
716  memset(&ssn, 0, sizeof(ssn));
717 
718  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
719  FAIL_IF_NULL(f);
720  f->protoctx = &ssn;
721  f->proto = IPPROTO_TCP;
722  f->alproto = ALPROTO_HTTP1;
723 
724  StreamTcpInitConfig(true);
725 
726  SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1);
727  int r = AppLayerParserParse(
728  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
729  FAIL_IF_NOT(r == 0);
730 
731  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
733  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
734  FAIL_IF_NOT(r == 0);
735 
736  http_state = f->alstate;
737  FAIL_IF_NULL(http_state);
738 
739  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
740  FAIL_IF_NULL(tx);
741  FAIL_IF_NULL(htp_tx_request_method(tx));
742 
743  char *m = bstr_util_strdup_to_c(htp_tx_request_method(tx));
744  FAIL_IF(memcmp(m, "POST", 4) != 0);
745  SCFree(m);
746 
747  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
748  FAIL_IF_NULL(tx_ud);
749  FAIL_IF_NULL(tx_ud->files_ts.head);
750  FAIL_IF_NULL(tx_ud->files_ts.tail);
752 
753  FAIL_IF(tx_ud->files_ts.head == tx_ud->files_ts.tail);
754  FAIL_IF(tx_ud->files_ts.head->next != tx_ud->files_ts.tail);
755 
756  FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.head->sb, (uint8_t *)"filecontent", 11) !=
757  1);
758 
759  FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.tail->sb, (uint8_t *)"FILECONTENT", 11) !=
760  1);
762  StreamTcpFreeConfig(true);
763  UTHFreeFlow(f);
764  PASS;
765 }
766 
767 /** \test first multipart part contains file but doesn't end in first chunk */
768 static int HTPFileParserTest06(void)
769 {
770  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
771  "Host: www.server.lan\r\n"
772  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
773  "Content-Length: 544\r\n"
774  "\r\n"
775  "-----------------------------277531038314945\r\n"
776  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
777  "Content-Type: image/jpeg\r\n"
778  "\r\n"
779  "filecontent\r\n"
780  "-----------------------------27753103831494";
781  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
782  uint8_t httpbuf2[] = "5\r\nContent-Disposition: form-data; name=\"uploadfile_1\"; filename=\"somepicture2.jpg\"\r\n"
783  "Content-Type: image/jpeg\r\n"
784  "\r\n"
785  "FILECONTENT\r\n"
786  "-----------------------------277531038314945--";
787  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
788 
789  TcpSession ssn;
790  HtpState *http_state = NULL;
792 
793  memset(&ssn, 0, sizeof(ssn));
794 
795  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
796  FAIL_IF_NULL(f);
797  f->protoctx = &ssn;
798  f->proto = IPPROTO_TCP;
799  f->alproto = ALPROTO_HTTP1;
800 
801  StreamTcpInitConfig(true);
802 
803  SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1);
804  int r = AppLayerParserParse(
805  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
806  FAIL_IF_NOT(r == 0);
807 
808  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
810  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
811  FAIL_IF_NOT(r == 0);
812 
813  http_state = f->alstate;
814  FAIL_IF_NULL(http_state);
815 
816  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
817  FAIL_IF_NULL(tx);
818  FAIL_IF_NULL(htp_tx_request_method(tx));
819 
820  char *m = bstr_util_strdup_to_c(htp_tx_request_method(tx));
821  FAIL_IF(memcmp(m, "POST", 4) != 0);
822  SCFree(m);
823 
824  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
825  FAIL_IF_NULL(tx_ud);
826  FAIL_IF_NULL(tx_ud->files_ts.head);
827  FAIL_IF_NULL(tx_ud->files_ts.tail);
829 
830  FAIL_IF(tx_ud->files_ts.head == tx_ud->files_ts.tail);
831  FAIL_IF(tx_ud->files_ts.head->next != tx_ud->files_ts.tail);
832 
833  FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.head->sb, (uint8_t *)"filecontent", 11) !=
834  1);
835 
836  FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.tail->sb, (uint8_t *)"FILECONTENT", 11) !=
837  1);
838 
840  StreamTcpFreeConfig(true);
841  UTHFreeFlow(f);
842  PASS;
843 }
844 
845 /** \test POST, but not multipart */
846 static int HTPFileParserTest07(void)
847 {
848  uint8_t httpbuf1[] = "POST /filename HTTP/1.1\r\n"
849  "Host: www.server.lan\r\n"
850  "Content-Length: 11\r\n"
851  "\r\n";
852  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
853  uint8_t httpbuf2[] = "FILECONTENT";
854  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
855 
856  TcpSession ssn;
857  HtpState *http_state = NULL;
859 
860  memset(&ssn, 0, sizeof(ssn));
861 
862  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
863  FAIL_IF_NULL(f);
864  f->protoctx = &ssn;
865  f->proto = IPPROTO_TCP;
866  f->alproto = ALPROTO_HTTP1;
867 
868  StreamTcpInitConfig(true);
869 
870  SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1);
871  int r = AppLayerParserParse(
872  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
873  FAIL_IF_NOT(r == 0);
874 
875  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
877  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
878  FAIL_IF_NOT(r == 0);
879 
880  http_state = f->alstate;
881  FAIL_IF_NULL(http_state);
882 
883  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
884  FAIL_IF_NULL(tx);
885  FAIL_IF_NULL(htp_tx_request_method(tx));
886  char *m = bstr_util_strdup_to_c(htp_tx_request_method(tx));
887  FAIL_IF(memcmp(m, "POST", 4) != 0);
888  SCFree(m);
889 
890  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
891  FAIL_IF_NULL(tx_ud);
892  FAIL_IF_NULL(tx_ud->files_ts.head);
893  FAIL_IF_NULL(tx_ud->files_ts.tail);
895 
896  FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.tail->sb, (uint8_t *)"FILECONTENT", 11) !=
897  1);
898 
900  StreamTcpFreeConfig(true);
901  UTHFreeFlow(f);
902  PASS;
903 }
904 
905 static int HTPFileParserTest08(void)
906 {
907  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
908  "Host: www.server.lan\r\n"
909  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
910  "Content-Length: 215\r\n"
911  "\r\n"
912  "-----------------------------277531038314945\r\n"
913  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
914  "Content-Type: image/jpeg\r\n";
915 
916  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
917  uint8_t httpbuf2[] = "filecontent\r\n\r\n"
918  "-----------------------------277531038314945--";
919  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
920 
921  TcpSession ssn;
923  HtpState *http_state = NULL;
924  memset(&ssn, 0, sizeof(ssn));
925 
926  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
927  FAIL_IF_NULL(f);
928  f->protoctx = &ssn;
929  f->proto = IPPROTO_TCP;
930  f->alproto = ALPROTO_HTTP1;
931 
932  StreamTcpInitConfig(true);
933 
934  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
935  int r = AppLayerParserParse(
936  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
937  FAIL_IF_NOT(r == 0);
938 
939  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
941  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
942  FAIL_IF_NOT(r == 0);
943 
944  http_state = f->alstate;
945  FAIL_IF_NULL(http_state);
946 
947  void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
948  FAIL_IF_NULL(tx);
949 
950  AppLayerDecoderEvents *decoder_events =
951  AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, tx);
952  FAIL_IF_NULL(decoder_events);
953 
954  FAIL_IF(decoder_events->cnt != 2);
955 
957  StreamTcpFreeConfig(true);
958  UTHFreeFlow(f);
959  PASS;
960 }
961 
962 /** \test invalid header: Somereallylongheaderstr: has no value */
963 static int HTPFileParserTest09(void)
964 {
965  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
966  "Host: www.server.lan\r\n"
967  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
968  "Content-Length: 337\r\n"
969  "\r\n";
970  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
971 
972  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
973  "Content-Disposition: form-data; name=\"email\"\r\n"
974  "\r\n"
975  "someaddress@somedomain.lan\r\n";
976  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
977 
978  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
979  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
980  "Somereallylongheaderstr:\r\n"
981  "\r\n";
982  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
983 
984  uint8_t httpbuf4[] = "filecontent\r\n"
985  "-----------------------------277531038314945--";
986  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
987 
988  TcpSession ssn;
989  HtpState *http_state = NULL;
991 
992  memset(&ssn, 0, sizeof(ssn));
993 
994  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
995  FAIL_IF_NULL(f);
996  f->protoctx = &ssn;
997  f->proto = IPPROTO_TCP;
998  f->alproto = ALPROTO_HTTP1;
999 
1000  StreamTcpInitConfig(true);
1001 
1002  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
1003  int r = AppLayerParserParse(
1004  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
1005  FAIL_IF_NOT(r == 0);
1006 
1007  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
1008  r = AppLayerParserParse(
1009  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
1010  FAIL_IF_NOT(r == 0);
1011 
1012  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
1013  r = AppLayerParserParse(
1014  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
1015  FAIL_IF_NOT(r == 0);
1016 
1017  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
1018  r = AppLayerParserParse(
1019  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1020  FAIL_IF_NOT(r == 0);
1021 
1022  http_state = f->alstate;
1023  FAIL_IF_NULL(http_state);
1024 
1025  void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
1026  FAIL_IF_NULL(tx);
1027 
1028  AppLayerDecoderEvents *decoder_events =
1029  AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, tx);
1030  FAIL_IF_NULL(decoder_events);
1031 
1032  FAIL_IF(decoder_events->cnt != 1);
1033 
1035  StreamTcpFreeConfig(true);
1036  UTHFreeFlow(f);
1037  PASS;
1038 }
1039 
1040 /** \test empty entries */
1041 static int HTPFileParserTest10(void)
1042 {
1043  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
1044  "Host: www.server.lan\r\n"
1045  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
1046  "Content-Length: 337\r\n"
1047  "\r\n";
1048  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1049 
1050  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
1051  "\r\n";
1052  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1053 
1054  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
1055  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
1056  "Somereallylongheaderstr: with a good value\r\n"
1057  "\r\n";
1058  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1059 
1060  uint8_t httpbuf4[] = "filecontent\r\n"
1061  "-----------------------------277531038314945--";
1062  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1063 
1064  TcpSession ssn;
1065  HtpState *http_state = NULL;
1067 
1068  memset(&ssn, 0, sizeof(ssn));
1069 
1070  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1071  FAIL_IF_NULL(f);
1072  f->protoctx = &ssn;
1073  f->proto = IPPROTO_TCP;
1074  f->alproto = ALPROTO_HTTP1;
1075 
1076  StreamTcpInitConfig(true);
1077 
1078  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
1079  int r = AppLayerParserParse(
1080  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
1081  FAIL_IF_NOT(r == 0);
1082 
1083  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
1084  r = AppLayerParserParse(
1085  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
1086  FAIL_IF_NOT(r == 0);
1087 
1088  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
1089  r = AppLayerParserParse(
1090  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
1091  FAIL_IF_NOT(r == 0);
1092 
1093  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
1094  r = AppLayerParserParse(
1095  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1096  FAIL_IF_NOT(r == 0);
1097 
1098  http_state = f->alstate;
1099  FAIL_IF_NULL(http_state);
1100 
1101  void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
1102  FAIL_IF_NULL(tx);
1103  AppLayerDecoderEvents *decoder_events =
1104  AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, tx);
1105  FAIL_IF_NOT_NULL(decoder_events);
1106 
1108  StreamTcpFreeConfig(true);
1109  UTHFreeFlow(f);
1110  PASS;
1111 }
1112 
1113 /** \test filedata cut in two pieces */
1114 static int HTPFileParserTest11(void)
1115 {
1116  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
1117  "Host: www.server.lan\r\n"
1118  "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1119  "Content-Length: 1102\r\n"
1120  "\r\n";
1121  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1122 
1123  uint8_t httpbuf2[] = "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n";
1124  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1125 
1126  uint8_t httpbuf3[] = "Content-Disposition: form-data; name=\"PROGRESS_URL\"\r\n"
1127  "\r\n"
1128  "http://somserver.com/progress.php?UPLOAD_IDENTIFIER=XXXXXXXXX.XXXXXXXXXX.XXXXXXXX.XX.X\r\n"
1129  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1130  "Content-Disposition: form-data; name=\"DESTINATION_DIR\"\r\n"
1131  "\r\n"
1132  "10\r\n"
1133  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1134  "Content-Disposition: form-data; name=\"js_enabled\"\r\n"
1135  "\r\n"
1136  "1"
1137  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1138  "Content-Disposition: form-data; name=\"signature\"\r\n"
1139  "\r\n"
1140  "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n"
1141  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1142  "Content-Disposition: form-data; name=\"upload_files\"\r\n"
1143  "\r\n"
1144  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1145  "Content-Disposition: form-data; name=\"terms\"\r\n"
1146  "\r\n"
1147  "1"
1148  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1149  "Content-Disposition: form-data; name=\"file[]\"\r\n"
1150  "\r\n"
1151  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1152  "Content-Disposition: form-data; name=\"description[]\"\r\n"
1153  "\r\n"
1154  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1155  "Content-Disposition: form-data; name=\"upload_file[]\"; filename=\"filename.doc\"\r\n"
1156  "Content-Type: application/msword\r\n"
1157  "\r\n"
1158  "FILE";
1159  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1160 
1161  uint8_t httpbuf4[] = "CONTENT\r\n"
1162  "------WebKitFormBoundaryBRDbP74mBhBxsIdo--";
1163  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1164 
1165  TcpSession ssn;
1166  HtpState *http_state = NULL;
1168 
1169  memset(&ssn, 0, sizeof(ssn));
1170 
1171  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1172  FAIL_IF_NULL(f);
1173  f->protoctx = &ssn;
1174  f->proto = IPPROTO_TCP;
1175  f->alproto = ALPROTO_HTTP1;
1176 
1177  StreamTcpInitConfig(true);
1178 
1179  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
1180  int r = AppLayerParserParse(
1181  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
1182  FAIL_IF_NOT(r == 0);
1183 
1184  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
1185  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
1186  FAIL_IF_NOT(r == 0);
1187 
1188  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
1189  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf3, httplen3);
1190  FAIL_IF_NOT(r == 0);
1191 
1192  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
1193  r = AppLayerParserParse(
1194  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1195  FAIL_IF_NOT(r == 0);
1196 
1197  http_state = f->alstate;
1198  FAIL_IF_NULL(http_state);
1199 
1200  void *txtmp = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
1201  FAIL_IF_NULL(txtmp);
1202 
1203  AppLayerDecoderEvents *decoder_events =
1204  AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, txtmp);
1205  FAIL_IF_NOT_NULL(decoder_events);
1206 
1207  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
1208  FAIL_IF_NULL(tx);
1209  FAIL_IF_NULL(htp_tx_request_method(tx));
1210 
1211  char *m = bstr_util_strdup_to_c(htp_tx_request_method(tx));
1212  FAIL_IF(memcmp(m, "POST", 4) != 0);
1213  SCFree(m);
1214 
1215  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
1216  FAIL_IF_NULL(tx_ud);
1217  FAIL_IF_NULL(tx_ud->files_ts.head);
1218  FAIL_IF_NULL(tx_ud->files_ts.tail);
1220 
1221  FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.tail->sb, (uint8_t *)"FILECONTENT", 11) !=
1222  1);
1223 
1225  StreamTcpFreeConfig(true);
1226  UTHFreeFlow(f);
1227  PASS;
1228 }
1229 
1230 void AppLayerHtpFileRegisterTests (void);
1231 #include "tests/app-layer-htp-file.c"
1232 #endif /* UNITTESTS */
1233 
1235 {
1236 #ifdef UNITTESTS
1237  UtRegisterTest("HTPFileParserTest01", HTPFileParserTest01);
1238  UtRegisterTest("HTPFileParserTest02", HTPFileParserTest02);
1239  UtRegisterTest("HTPFileParserTest03", HTPFileParserTest03);
1240  UtRegisterTest("HTPFileParserTest04", HTPFileParserTest04);
1241  UtRegisterTest("HTPFileParserTest05", HTPFileParserTest05);
1242  UtRegisterTest("HTPFileParserTest06", HTPFileParserTest06);
1243  UtRegisterTest("HTPFileParserTest07", HTPFileParserTest07);
1244  UtRegisterTest("HTPFileParserTest08", HTPFileParserTest08);
1245  UtRegisterTest("HTPFileParserTest09", HTPFileParserTest09);
1246  UtRegisterTest("HTPFileParserTest10", HTPFileParserTest10);
1247  UtRegisterTest("HTPFileParserTest11", HTPFileParserTest11);
1249 #endif /* UNITTESTS */
1250 }
HtpState_::cfg
const struct HTPCfgRec_ * cfg
Definition: app-layer-htp.h:188
FILE_TRUNCATED
#define FILE_TRUNCATED
Definition: util-file.h:73
FileContainer_
Definition: util-file.h:37
len
uint8_t len
Definition: app-layer-dnp3.h:2
app-layer-htp-range.h
FAIL_IF_NULL
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
SCFileFlowFlagsToFlags
uint16_t SCFileFlowFlagsToFlags(const uint16_t flow_file_flags, uint8_t direction)
Definition: util-file.c:215
FileContainerAdd
void FileContainerAdd(FileContainer *ffc, File *ff)
Definition: util-file.c:594
stream-tcp.h
HTPCfgDir_
Definition: app-layer-htp.h:94
HtpTxUserData_::files_tc
FileContainer files_tc
Definition: app-layer-htp.h:178
HTPFileStoreChunk
int HTPFileStoreChunk(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:223
HTPCfgRec_::response
HTPCfgDir response
Definition: app-layer-htp.h:116
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:279
AppLayerParserGetEventsByTx
AppLayerDecoderEvents * AppLayerParserGetEventsByTx(uint8_t ipproto, AppProto alproto, void *tx)
Definition: app-layer-parser.c:857
Flow_::proto
uint8_t proto
Definition: flow.h:370
Flow_
Flow data structure.
Definition: flow.h:348
File_::state
FileState state
Definition: util-file.h:110
HtpState_::f
Flow * f
Definition: app-layer-htp.h:186
HttpRangeContainerFile::error
bool error
Definition: app-layer-htp-range.h:116
AppLayerParserThreadCtxFree
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
Destroys the app layer parser thread context obtained using AppLayerParserThreadCtxAlloc().
Definition: app-layer-parser.c:324
FileContainer_::tail
File * tail
Definition: util-file.h:39
m
SCMutex m
Definition: flow-hash.h:6
Flow_::protoctx
void * protoctx
Definition: flow.h:433
AppLayerDecoderEvents_
Data structure to store app layer decoder events.
Definition: app-layer-events.h:33
HTPCfgDir_::inspect_window
uint32_t inspect_window
Definition: app-layer-htp.h:97
HtpState_
Definition: app-layer-htp.h:181
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
HTPFileOpen
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.
Definition: app-layer-htp-file.c:50
SCAppLayerDecoderEventsSetEventRaw
void SCAppLayerDecoderEventsSetEventRaw(AppLayerDecoderEvents **sevents, uint8_t event)
Set an app layer decoder event.
Definition: app-layer-events.c:96
File_::sb
StreamingBuffer * sb
Definition: util-file.h:111
app-layer-htp-file.h
HttpRangeContainerBlock
Definition: app-layer-htp-range.h:33
HtpTxUserData_::file_range
HttpRangeContainerBlock * file_range
Definition: app-layer-htp.h:174
StreamTcpInitConfig
void StreamTcpInitConfig(bool)
To initialize the stream global configuration data.
Definition: stream-tcp.c:488
UTHBuildFlow
Flow * UTHBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp)
Definition: util-unittest-helper.c:497
HttpRangeClose
File * HttpRangeClose(const StreamingBufferConfig *sbcfg, HttpRangeContainerBlock *c, uint16_t flags)
Definition: app-layer-htp-range.c:451
FAIL_IF_NOT_NULL
#define FAIL_IF_NOT_NULL(expr)
Fail a test if expression evaluates to non-NULL.
Definition: util-unittest.h:96
HTTPContentRange
struct HTTPContentRange HTTPContentRange
Definition: app-layer-htp-range.h:26
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:272
HtpState_::file_track_id
uint32_t file_track_id
Definition: app-layer-htp.h:192
HTPCfgDir_::inspect_min_size
uint32_t inspect_min_size
Definition: app-layer-htp.h:96
alp_tctx
AppLayerParserThreadCtx * alp_tctx
Definition: fuzz_applayerparserparse.c:23
SCHttpRangeContainerOpenFile
HttpRangeContainerBlock * SCHttpRangeContainerOpenFile(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:342
SCEnter
#define SCEnter(...)
Definition: util-debug.h:281
FileContainer_::head
File * head
Definition: util-file.h:38
SCHTPFileCloseHandleRange
bool SCHTPFileCloseHandleRange(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:267
HtpTxUserData_::tx_data
AppLayerTxData tx_data
Definition: app-layer-htp.h:176
app-layer-parser.h
HTPFileParserRegisterTests
void HTPFileParserRegisterTests(void)
Definition: app-layer-htp-file.c:1234
HTTP_DECODER_EVENT_RANGE_INVALID
@ HTTP_DECODER_EVENT_RANGE_INVALID
Definition: app-layer-htp.h:82
AppLayerDecoderEvents_::cnt
uint8_t cnt
Definition: app-layer-events.h:37
StreamingBufferCompareRawData
int StreamingBufferCompareRawData(const StreamingBuffer *sb, const uint8_t *rawdata, uint32_t rawdata_len)
Definition: util-streaming-buffer.c:1853
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:966
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:765
AppLayerParserGetTx
void * AppLayerParserGetTx(uint8_t ipproto, AppProto alproto, void *alstate, uint64_t tx_id)
Definition: app-layer-parser.c:1109
SCHttpRangeAppendData
int SCHttpRangeAppendData(const StreamingBufferConfig *sbcfg, HttpRangeContainerBlock *c, const uint8_t *data, uint32_t len)
Definition: app-layer-htp-range.c:378
htp_sbcfg
StreamingBufferConfig htp_sbcfg
Definition: app-layer-htp.c:92
FileDataSize
uint64_t FileDataSize(const File *file)
get the size of the file data
Definition: util-file.c:308
HttpRangeContainerFile::hdata
THashData * hdata
Definition: app-layer-htp-range.h:102
UTHFreeFlow
void UTHFreeFlow(Flow *flow)
Definition: util-unittest-helper.c:502
AppLayerParserThreadCtxAlloc
AppLayerParserThreadCtx * AppLayerParserThreadCtxAlloc(void)
Gets a new app layer protocol's parser thread context.
Definition: app-layer-parser.c:297
HttpRangeContainerBlock::container
HttpRangeContainerFile * container
Definition: app-layer-htp-range.h:39
FILE_STATE_CLOSED
@ FILE_STATE_CLOSED
Definition: util-file.h:99
File_
Definition: util-file.h:107
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:859
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:1291
suricata-common.h
HTPCfgRec_::request
HTPCfgDir request
Definition: app-layer-htp.h:115
ALPROTO_HTTP1
@ ALPROTO_HTTP1
Definition: app-layer-protos.h:36
File_::next
struct File_ * next
Definition: util-file.h:120
FileSetInspectSizes
void FileSetInspectSizes(File *file, const uint32_t win, const uint32_t min)
Definition: util-file.c:842
FileSetRange
int FileSetRange(FileContainer *ffc, uint64_t start, uint64_t end)
Sets the offset range for a file.
Definition: util-file.c:858
HtpTxUserData_
Definition: app-layer-htp.h:151
app-layer-events.h
util-validate.h
StreamingBufferConfig_
Definition: util-streaming-buffer.h:65
HTPParseContentRange
int HTPParseContentRange(const bstr *rawvalue, HTTPContentRange *range)
Definition: app-layer-htp-file.c:96
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
HtpState_::events
uint16_t events
Definition: app-layer-htp.h:190
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:1061
SCFree
#define SCFree(p)
Definition: util-mem.h:61
Flow_::alstate
void * alstate
Definition: flow.h:471
SCHttpRangeFreeBlock
void SCHttpRangeFreeBlock(HttpRangeContainerBlock *b)
Definition: app-layer-htp-range.c:608
HTPFileClose
int HTPFileClose(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:309
HtpTxUserData_::files_ts
FileContainer files_ts
Definition: app-layer-htp.h:177
AppLayerParserThreadCtx_
Definition: app-layer-parser.c:60
TcpSession_
Definition: stream-tcp-private.h:283
Flow_::alproto
AppProto alproto
application level protocol
Definition: flow.h:442
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:285
HTPFileOpenWithRange
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.
Definition: app-layer-htp-file.c:149
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:102