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 = FileFlowFlagsToFlags(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 = FileFlowFlagsToFlags(tx->tx_data.file_flags, STREAM_TOSERVER);
68  }
69 
70  if (FileOpenFileWithId(files, &htp_sbcfg, s->file_track_id++, filename, filename_len, data,
71  data_len, flags) != 0) {
72  retval = -1;
73  } else {
74  const HTPCfgDir *cfg;
75  if (direction & STREAM_TOCLIENT) {
76  cfg = &s->cfg->response;
77  } else {
78  cfg = &s->cfg->request;
79  }
81  }
82 
83  tx->tx_data.files_opened++;
84 
85  SCReturnInt(retval);
86 }
87 
88 /**
89  * Performs parsing of the content-range value
90  *
91  * @param[in] rawvalue
92  * @param[out] range
93  *
94  * @return HTP_OK on success, HTP_ERROR on failure.
95  */
96 int HTPParseContentRange(bstr *rawvalue, HTTPContentRange *range)
97 {
98  uint32_t len = (uint32_t)bstr_len(rawvalue);
99  return rs_http_parse_content_range(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_OK on success, HTP_ERROR, -2, -3 on failure.
109  */
110 static int HTPParseAndCheckContentRange(
111  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, htp_tx_t *tx, bstr *rawvalue,
151  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 (tx->request_hostname != NULL) {
185  uint32_t hlen = (uint32_t)bstr_len(tx->request_hostname);
186  if (bstr_len(tx->request_hostname) > 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(tx->request_hostname), hlen);
195  memcpy(keyurl + hlen, filename, filename_len);
196  } else {
197  // do not reassemble file without host info
198  SCReturnInt(0);
199  }
201  htud->file_range = HttpRangeContainerOpenFile(keyurl, keylen, s->f, &crparsed, &htp_sbcfg,
202  filename, filename_len, flags, data, data_len);
203  SCFree(keyurl);
204  if (htud->file_range == NULL) {
205  SCReturnInt(-1);
206  }
207  SCReturnInt(0);
208 }
209 
210 /**
211  * \brief Store a chunk of data in the flow
212  *
213  * \param s HtpState
214  * \param tx HtpTxUserData
215  * \param data data chunk (if any)
216  * \param data_len length of the data portion
217  * \param direction flow direction
218  *
219  * \retval 0 ok
220  * \retval -1 error
221  * \retval -2 file doesn't need storing
222  */
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 (HttpRangeAppendData(&htp_sbcfg, tx->file_range, data, data_len) < 0) {
246  SCLogDebug("Failed to append data");
247  }
248  }
249 
250  result = FileAppendData(files, &htp_sbcfg, data, data_len);
251  if (result == -1) {
252  SCLogDebug("appending data failed");
253  retval = -1;
254  } else if (result == -2) {
255  retval = -2;
256  }
257  SCLogDebug("result %u", result);
258 
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 (HttpRangeAppendData(sbcfg, c, data, data_len) < 0) {
272  SCLogDebug("Failed to append data");
273  }
274  if (c->container) {
275  // we only call HttpRangeClose if we may some new data
276  // ie we do not call it if we skipped all this range request
277  THashDataLock(c->container->hdata);
278  if (c->container->error) {
279  SCLogDebug("range in ERROR state");
280  }
281  File *ranged = HttpRangeClose(sbcfg, c, flags);
282  if (ranged && files) {
283  /* HtpState owns the constructed file now */
284  FileContainerAdd(files, ranged);
285  added = true;
286  }
287  DEBUG_VALIDATE_BUG_ON(ranged && !files);
288  THashDataUnlock(c->container->hdata);
289  }
290  return added;
291 }
292 
293 /**
294  * \brief Close the file in the flow
295  *
296  * \param tx HtpTxUserData
297  * \param data data chunk if any
298  * \param data_len length of the data portion
299  * \param flags flags to indicate events
300  * \param direction flow direction
301  *
302  * Currently on the FLOW_FILE_TRUNCATED flag is implemented, indicating
303  * that the file isn't complete but we're stopping storing it.
304  *
305  * \retval 0 ok
306  * \retval -1 error
307  * \retval -2 not storing files on this flow/tx
308  */
310  HtpTxUserData *tx, const uint8_t *data, uint32_t data_len, uint8_t flags, uint8_t direction)
311 {
312  SCEnter();
313 
314  SCLogDebug("flags %04x FILE_TRUNCATED %s", flags, (flags & FILE_TRUNCATED) ? "true" : "false");
315 
316  int retval = 0;
317  int result = 0;
318  FileContainer *files = NULL;
319 
320  if (direction & STREAM_TOCLIENT) {
321  files = &tx->files_tc;
322  } else {
323  files = &tx->files_ts;
324  }
325 
326  SCLogDebug("files %p data %p data_len %" PRIu32, files, data, data_len);
327 
328  if (files == NULL) {
329  retval = -1;
330  goto end;
331  }
332 
333  result = FileCloseFile(files, &htp_sbcfg, data, data_len, flags);
334  if (result == -1) {
335  retval = -1;
336  } else if (result == -2) {
337  retval = -2;
338  }
339  SCLogDebug("result %u", result);
340 
341  if (tx->file_range != NULL) {
342  bool added =
343  HTPFileCloseHandleRange(&htp_sbcfg, files, flags, tx->file_range, data, data_len);
344  if (added) {
345  tx->tx_data.files_opened++;
346  }
348  tx->file_range = NULL;
349  }
350 
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(tx->request_method);
406 
407  FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0);
408 
410  StreamTcpFreeConfig(true);
411  UTHFreeFlow(f);
412  PASS;
413 }
414 
415 static int HTPFileParserTest02(void)
416 {
417  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
418  "Host: www.server.lan\r\n"
419  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
420  "Content-Length: 337\r\n"
421  "\r\n";
422  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
423 
424  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
425  "Content-Disposition: form-data; name=\"email\"\r\n"
426  "\r\n"
427  "someaddress@somedomain.lan\r\n";
428  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
429 
430  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
431  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
432  "Content-Type: image/jpeg\r\n"
433  "\r\n";
434  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
435 
436  uint8_t httpbuf4[] = "filecontent\r\n"
437  "-----------------------------277531038314945--";
438  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
439 
440  TcpSession ssn;
441  HtpState *http_state = NULL;
443 
444  memset(&ssn, 0, sizeof(ssn));
445 
446  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
447  FAIL_IF_NULL(f);
448  f->protoctx = &ssn;
449  f->proto = IPPROTO_TCP;
450  f->alproto = ALPROTO_HTTP1;
451 
452  StreamTcpInitConfig(true);
453 
454  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
455  int r = AppLayerParserParse(
456  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
457  FAIL_IF_NOT(r == 0);
458 
459  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
461  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
462  FAIL_IF_NOT(r == 0);
463 
464  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
466  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
467  FAIL_IF_NOT(r == 0);
468 
469  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
471  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
472  FAIL_IF_NOT(r == 0);
473 
474  http_state = f->alstate;
475  FAIL_IF_NULL(http_state);
476 
477  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
478  FAIL_IF_NULL(tx);
479  FAIL_IF_NULL(tx->request_method);
480  FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0);
481  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
482  FAIL_IF_NULL(tx_ud);
483  FAIL_IF_NULL(tx_ud->files_ts.tail);
485 
487  StreamTcpFreeConfig(true);
488  UTHFreeFlow(f);
489  PASS;
490 }
491 
492 static int HTPFileParserTest03(void)
493 {
494  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
495  "Host: www.server.lan\r\n"
496  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
497  "Content-Length: 337\r\n"
498  "\r\n";
499  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
500 
501  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
502  "Content-Disposition: form-data; name=\"email\"\r\n"
503  "\r\n"
504  "someaddress@somedomain.lan\r\n";
505  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
506 
507  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
508  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
509  "Content-Type: image/jpeg\r\n"
510  "\r\n";
511  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
512 
513  uint8_t httpbuf4[] = "file";
514  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
515 
516  uint8_t httpbuf5[] = "content\r\n";
517  uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
518 
519  uint8_t httpbuf6[] = "-----------------------------277531038314945--";
520  uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
521 
522  TcpSession ssn;
523  HtpState *http_state = NULL;
525 
526  memset(&ssn, 0, sizeof(ssn));
527 
528  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
529  FAIL_IF_NULL(f);
530  f->protoctx = &ssn;
531  f->proto = IPPROTO_TCP;
532  f->alproto = ALPROTO_HTTP1;
533 
534  StreamTcpInitConfig(true);
535 
536  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
537  int r = AppLayerParserParse(
538  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
539  FAIL_IF_NOT(r == 0);
540 
541  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
543  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
544  FAIL_IF_NOT(r == 0);
545 
546  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
548  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
549  FAIL_IF_NOT(r == 0);
550 
551  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
553  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
554  FAIL_IF_NOT(r == 0);
555 
556  SCLogDebug("\n>>>> processing chunk 5 size %u <<<<\n", httplen5);
558  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf5, httplen5);
559  FAIL_IF_NOT(r == 0);
560 
561  SCLogDebug("\n>>>> processing chunk 6 size %u <<<<\n", httplen6);
563  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf6, httplen6);
564  FAIL_IF_NOT(r == 0);
565 
566  http_state = f->alstate;
567  FAIL_IF_NULL(http_state);
568 
569  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
570  FAIL_IF_NULL(tx);
571  FAIL_IF_NULL(tx->request_method);
572 
573  FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0);
574 
575  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
576  FAIL_IF_NULL(tx_ud);
577  FAIL_IF_NULL(tx_ud->files_ts.head);
578  FAIL_IF_NULL(tx_ud->files_ts.tail);
580  FAIL_IF(FileDataSize(tx_ud->files_ts.head) != 11);
581 
583  StreamTcpFreeConfig(true);
584  UTHFreeFlow(f);
585  PASS;
586 }
587 
588 static int HTPFileParserTest04(void)
589 {
590  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
591  "Host: www.server.lan\r\n"
592  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
593  "Content-Length: 373\r\n"
594  "\r\n";
595  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
596 
597  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
598  "Content-Disposition: form-data; name=\"email\"\r\n"
599  "\r\n"
600  "someaddress@somedomain.lan\r\n";
601  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
602 
603  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
604  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
605  "Content-Type: image/jpeg\r\n"
606  "\r\n";
607  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
608 
609  uint8_t httpbuf4[] = "file0123456789abcdefghijklmnopqrstuvwxyz";
610  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
611 
612  uint8_t httpbuf5[] = "content\r\n";
613  uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
614 
615  uint8_t httpbuf6[] = "-----------------------------277531038314945--";
616  uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
617 
618  TcpSession ssn;
619  HtpState *http_state = NULL;
621 
622  memset(&ssn, 0, sizeof(ssn));
623 
624  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
625  FAIL_IF_NULL(f);
626  f->protoctx = &ssn;
627  f->proto = IPPROTO_TCP;
628  f->alproto = ALPROTO_HTTP1;
629 
630  StreamTcpInitConfig(true);
631 
632  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
633  int r = AppLayerParserParse(
634  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
635  FAIL_IF_NOT(r == 0);
636 
637  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
639  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
640  FAIL_IF_NOT(r == 0);
641 
642  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
644  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
645  FAIL_IF_NOT(r == 0);
646 
647  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
649  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
650  FAIL_IF_NOT(r == 0);
651 
652  SCLogDebug("\n>>>> processing chunk 5 size %u <<<<\n", httplen5);
654  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf5, httplen5);
655  FAIL_IF_NOT(r == 0);
656 
657  SCLogDebug("\n>>>> processing chunk 6 size %u <<<<\n", httplen6);
659  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf6, httplen6);
660  FAIL_IF_NOT(r == 0);
661 
662  http_state = f->alstate;
663  FAIL_IF_NULL(http_state);
664 
665  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
666  FAIL_IF_NULL(tx);
667  FAIL_IF_NULL(tx->request_method);
668 
669  FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0);
670 
671  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
672  FAIL_IF_NULL(tx_ud);
673  FAIL_IF_NULL(tx_ud->files_ts.head);
674  FAIL_IF_NULL(tx_ud->files_ts.tail);
676 
678  StreamTcpFreeConfig(true);
679  UTHFreeFlow(f);
680  PASS;
681 }
682 
683 static int HTPFileParserTest05(void)
684 {
685  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
686  "Host: www.server.lan\r\n"
687  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
688  "Content-Length: 544\r\n"
689  "\r\n"
690  "-----------------------------277531038314945\r\n"
691  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
692  "Content-Type: image/jpeg\r\n"
693  "\r\n"
694  "filecontent\r\n"
695  "-----------------------------277531038314945\r\n";
696  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
697  uint8_t httpbuf2[] = "Content-Disposition: form-data; name=\"uploadfile_1\"; filename=\"somepicture2.jpg\"\r\n"
698  "Content-Type: image/jpeg\r\n"
699  "\r\n"
700  "FILECONTENT\r\n"
701  "-----------------------------277531038314945--";
702  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
703 
704  TcpSession ssn;
705  HtpState *http_state = NULL;
707 
708  memset(&ssn, 0, sizeof(ssn));
709 
710  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
711  FAIL_IF_NULL(f);
712  f->protoctx = &ssn;
713  f->proto = IPPROTO_TCP;
714  f->alproto = ALPROTO_HTTP1;
715 
716  StreamTcpInitConfig(true);
717 
718  SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1);
719  int r = AppLayerParserParse(
720  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
721  FAIL_IF_NOT(r == 0);
722 
723  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
725  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
726  FAIL_IF_NOT(r == 0);
727 
728  http_state = f->alstate;
729  FAIL_IF_NULL(http_state);
730 
731  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
732  FAIL_IF_NULL(tx);
733  FAIL_IF_NULL(tx->request_method);
734 
735  FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0);
736 
737  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
738  FAIL_IF_NULL(tx_ud);
739  FAIL_IF_NULL(tx_ud->files_ts.head);
740  FAIL_IF_NULL(tx_ud->files_ts.tail);
742 
743  FAIL_IF(tx_ud->files_ts.head == tx_ud->files_ts.tail);
744  FAIL_IF(tx_ud->files_ts.head->next != tx_ud->files_ts.tail);
745 
746  FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.head->sb, (uint8_t *)"filecontent", 11) !=
747  1);
748 
749  FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.tail->sb, (uint8_t *)"FILECONTENT", 11) !=
750  1);
752  StreamTcpFreeConfig(true);
753  UTHFreeFlow(f);
754  PASS;
755 }
756 
757 /** \test first multipart part contains file but doesn't end in first chunk */
758 static int HTPFileParserTest06(void)
759 {
760  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
761  "Host: www.server.lan\r\n"
762  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
763  "Content-Length: 544\r\n"
764  "\r\n"
765  "-----------------------------277531038314945\r\n"
766  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
767  "Content-Type: image/jpeg\r\n"
768  "\r\n"
769  "filecontent\r\n"
770  "-----------------------------27753103831494";
771  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
772  uint8_t httpbuf2[] = "5\r\nContent-Disposition: form-data; name=\"uploadfile_1\"; filename=\"somepicture2.jpg\"\r\n"
773  "Content-Type: image/jpeg\r\n"
774  "\r\n"
775  "FILECONTENT\r\n"
776  "-----------------------------277531038314945--";
777  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
778 
779  TcpSession ssn;
780  HtpState *http_state = NULL;
782 
783  memset(&ssn, 0, sizeof(ssn));
784 
785  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
786  FAIL_IF_NULL(f);
787  f->protoctx = &ssn;
788  f->proto = IPPROTO_TCP;
789  f->alproto = ALPROTO_HTTP1;
790 
791  StreamTcpInitConfig(true);
792 
793  SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1);
794  int r = AppLayerParserParse(
795  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
796  FAIL_IF_NOT(r == 0);
797 
798  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
800  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
801  FAIL_IF_NOT(r == 0);
802 
803  http_state = f->alstate;
804  FAIL_IF_NULL(http_state);
805 
806  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
807  FAIL_IF_NULL(tx);
808  FAIL_IF_NULL(tx->request_method);
809 
810  FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0);
811 
812  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
813  FAIL_IF_NULL(tx_ud);
814  FAIL_IF_NULL(tx_ud->files_ts.head);
815  FAIL_IF_NULL(tx_ud->files_ts.tail);
817 
818  FAIL_IF(tx_ud->files_ts.head == tx_ud->files_ts.tail);
819  FAIL_IF(tx_ud->files_ts.head->next != tx_ud->files_ts.tail);
820 
821  FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.head->sb, (uint8_t *)"filecontent", 11) !=
822  1);
823 
824  FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.tail->sb, (uint8_t *)"FILECONTENT", 11) !=
825  1);
826 
828  StreamTcpFreeConfig(true);
829  UTHFreeFlow(f);
830  PASS;
831 }
832 
833 /** \test POST, but not multipart */
834 static int HTPFileParserTest07(void)
835 {
836  uint8_t httpbuf1[] = "POST /filename HTTP/1.1\r\n"
837  "Host: www.server.lan\r\n"
838  "Content-Length: 11\r\n"
839  "\r\n";
840  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
841  uint8_t httpbuf2[] = "FILECONTENT";
842  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
843 
844  TcpSession ssn;
845  HtpState *http_state = NULL;
847 
848  memset(&ssn, 0, sizeof(ssn));
849 
850  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
851  FAIL_IF_NULL(f);
852  f->protoctx = &ssn;
853  f->proto = IPPROTO_TCP;
854  f->alproto = ALPROTO_HTTP1;
855 
856  StreamTcpInitConfig(true);
857 
858  SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1);
859  int r = AppLayerParserParse(
860  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
861  FAIL_IF_NOT(r == 0);
862 
863  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
865  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
866  FAIL_IF_NOT(r == 0);
867 
868  http_state = f->alstate;
869  FAIL_IF_NULL(http_state);
870 
871  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
872  FAIL_IF_NULL(tx);
873  FAIL_IF_NULL(tx->request_method);
874  FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0);
875 
876  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
877  FAIL_IF_NULL(tx_ud);
878  FAIL_IF_NULL(tx_ud->files_ts.head);
879  FAIL_IF_NULL(tx_ud->files_ts.tail);
881 
882  FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.tail->sb, (uint8_t *)"FILECONTENT", 11) !=
883  1);
884 
886  StreamTcpFreeConfig(true);
887  UTHFreeFlow(f);
888  PASS;
889 }
890 
891 static int HTPFileParserTest08(void)
892 {
893  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
894  "Host: www.server.lan\r\n"
895  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
896  "Content-Length: 215\r\n"
897  "\r\n"
898  "-----------------------------277531038314945\r\n"
899  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
900  "Content-Type: image/jpeg\r\n";
901 
902  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
903  uint8_t httpbuf2[] = "filecontent\r\n\r\n"
904  "-----------------------------277531038314945--";
905  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
906 
907  TcpSession ssn;
909  HtpState *http_state = NULL;
910  memset(&ssn, 0, sizeof(ssn));
911 
912  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
913  FAIL_IF_NULL(f);
914  f->protoctx = &ssn;
915  f->proto = IPPROTO_TCP;
916  f->alproto = ALPROTO_HTTP1;
917 
918  StreamTcpInitConfig(true);
919 
920  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
921  int r = AppLayerParserParse(
922  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
923  FAIL_IF_NOT(r == 0);
924 
925  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
927  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
928  FAIL_IF_NOT(r == 0);
929 
930  http_state = f->alstate;
931  FAIL_IF_NULL(http_state);
932 
933  void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
934  FAIL_IF_NULL(tx);
935 
936  AppLayerDecoderEvents *decoder_events =
937  AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, tx);
938  FAIL_IF_NULL(decoder_events);
939 
940  FAIL_IF(decoder_events->cnt != 2);
941 
943  StreamTcpFreeConfig(true);
944  UTHFreeFlow(f);
945  PASS;
946 }
947 
948 /** \test invalid header: Somereallylongheaderstr: has no value */
949 static int HTPFileParserTest09(void)
950 {
951  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
952  "Host: www.server.lan\r\n"
953  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
954  "Content-Length: 337\r\n"
955  "\r\n";
956  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
957 
958  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
959  "Content-Disposition: form-data; name=\"email\"\r\n"
960  "\r\n"
961  "someaddress@somedomain.lan\r\n";
962  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
963 
964  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
965  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
966  "Somereallylongheaderstr:\r\n"
967  "\r\n";
968  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
969 
970  uint8_t httpbuf4[] = "filecontent\r\n"
971  "-----------------------------277531038314945--";
972  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
973 
974  TcpSession ssn;
975  HtpState *http_state = NULL;
977 
978  memset(&ssn, 0, sizeof(ssn));
979 
980  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
981  FAIL_IF_NULL(f);
982  f->protoctx = &ssn;
983  f->proto = IPPROTO_TCP;
984  f->alproto = ALPROTO_HTTP1;
985 
986  StreamTcpInitConfig(true);
987 
988  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
989  int r = AppLayerParserParse(
990  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
991  FAIL_IF_NOT(r == 0);
992 
993  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
995  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
996  FAIL_IF_NOT(r == 0);
997 
998  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
1000  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
1001  FAIL_IF_NOT(r == 0);
1002 
1003  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
1004  r = AppLayerParserParse(
1005  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1006  FAIL_IF_NOT(r == 0);
1007 
1008  http_state = f->alstate;
1009  FAIL_IF_NULL(http_state);
1010 
1011  void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
1012  FAIL_IF_NULL(tx);
1013 
1014  AppLayerDecoderEvents *decoder_events =
1015  AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, tx);
1016  FAIL_IF_NULL(decoder_events);
1017 
1018  FAIL_IF(decoder_events->cnt != 1);
1019 
1021  StreamTcpFreeConfig(true);
1022  UTHFreeFlow(f);
1023  PASS;
1024 }
1025 
1026 /** \test empty entries */
1027 static int HTPFileParserTest10(void)
1028 {
1029  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
1030  "Host: www.server.lan\r\n"
1031  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
1032  "Content-Length: 337\r\n"
1033  "\r\n";
1034  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1035 
1036  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
1037  "\r\n";
1038  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1039 
1040  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
1041  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
1042  "Somereallylongheaderstr: with a good value\r\n"
1043  "\r\n";
1044  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1045 
1046  uint8_t httpbuf4[] = "filecontent\r\n"
1047  "-----------------------------277531038314945--";
1048  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1049 
1050  TcpSession ssn;
1051  HtpState *http_state = NULL;
1053 
1054  memset(&ssn, 0, sizeof(ssn));
1055 
1056  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1057  FAIL_IF_NULL(f);
1058  f->protoctx = &ssn;
1059  f->proto = IPPROTO_TCP;
1060  f->alproto = ALPROTO_HTTP1;
1061 
1062  StreamTcpInitConfig(true);
1063 
1064  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
1065  int r = AppLayerParserParse(
1066  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
1067  FAIL_IF_NOT(r == 0);
1068 
1069  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
1070  r = AppLayerParserParse(
1071  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
1072  FAIL_IF_NOT(r == 0);
1073 
1074  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
1075  r = AppLayerParserParse(
1076  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
1077  FAIL_IF_NOT(r == 0);
1078 
1079  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
1080  r = AppLayerParserParse(
1081  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1082  FAIL_IF_NOT(r == 0);
1083 
1084  http_state = f->alstate;
1085  FAIL_IF_NULL(http_state);
1086 
1087  void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
1088  FAIL_IF_NULL(tx);
1089  AppLayerDecoderEvents *decoder_events =
1090  AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, tx);
1091  FAIL_IF_NOT_NULL(decoder_events);
1092 
1094  StreamTcpFreeConfig(true);
1095  UTHFreeFlow(f);
1096  PASS;
1097 }
1098 
1099 /** \test filedata cut in two pieces */
1100 static int HTPFileParserTest11(void)
1101 {
1102  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
1103  "Host: www.server.lan\r\n"
1104  "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1105  "Content-Length: 1102\r\n"
1106  "\r\n";
1107  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1108 
1109  uint8_t httpbuf2[] = "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n";
1110  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1111 
1112  uint8_t httpbuf3[] = "Content-Disposition: form-data; name=\"PROGRESS_URL\"\r\n"
1113  "\r\n"
1114  "http://somserver.com/progress.php?UPLOAD_IDENTIFIER=XXXXXXXXX.XXXXXXXXXX.XXXXXXXX.XX.X\r\n"
1115  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1116  "Content-Disposition: form-data; name=\"DESTINATION_DIR\"\r\n"
1117  "\r\n"
1118  "10\r\n"
1119  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1120  "Content-Disposition: form-data; name=\"js_enabled\"\r\n"
1121  "\r\n"
1122  "1"
1123  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1124  "Content-Disposition: form-data; name=\"signature\"\r\n"
1125  "\r\n"
1126  "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n"
1127  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1128  "Content-Disposition: form-data; name=\"upload_files\"\r\n"
1129  "\r\n"
1130  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1131  "Content-Disposition: form-data; name=\"terms\"\r\n"
1132  "\r\n"
1133  "1"
1134  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1135  "Content-Disposition: form-data; name=\"file[]\"\r\n"
1136  "\r\n"
1137  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1138  "Content-Disposition: form-data; name=\"description[]\"\r\n"
1139  "\r\n"
1140  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1141  "Content-Disposition: form-data; name=\"upload_file[]\"; filename=\"filename.doc\"\r\n"
1142  "Content-Type: application/msword\r\n"
1143  "\r\n"
1144  "FILE";
1145  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1146 
1147  uint8_t httpbuf4[] = "CONTENT\r\n"
1148  "------WebKitFormBoundaryBRDbP74mBhBxsIdo--";
1149  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1150 
1151  TcpSession ssn;
1152  HtpState *http_state = NULL;
1154 
1155  memset(&ssn, 0, sizeof(ssn));
1156 
1157  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1158  FAIL_IF_NULL(f);
1159  f->protoctx = &ssn;
1160  f->proto = IPPROTO_TCP;
1161  f->alproto = ALPROTO_HTTP1;
1162 
1163  StreamTcpInitConfig(true);
1164 
1165  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
1166  int r = AppLayerParserParse(
1167  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
1168  FAIL_IF_NOT(r == 0);
1169 
1170  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
1171  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
1172  FAIL_IF_NOT(r == 0);
1173 
1174  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
1175  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf3, httplen3);
1176  FAIL_IF_NOT(r == 0);
1177 
1178  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
1179  r = AppLayerParserParse(
1180  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1181  FAIL_IF_NOT(r == 0);
1182 
1183  http_state = f->alstate;
1184  FAIL_IF_NULL(http_state);
1185 
1186  void *txtmp = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
1187  FAIL_IF_NULL(txtmp);
1188 
1189  AppLayerDecoderEvents *decoder_events =
1190  AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, txtmp);
1191  FAIL_IF_NOT_NULL(decoder_events);
1192 
1193  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
1194  FAIL_IF_NULL(tx);
1195  FAIL_IF_NULL(tx->request_method);
1196 
1197  FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0);
1198 
1199  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
1200  FAIL_IF_NULL(tx_ud);
1201  FAIL_IF_NULL(tx_ud->files_ts.head);
1202  FAIL_IF_NULL(tx_ud->files_ts.tail);
1204 
1205  FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.tail->sb, (uint8_t *)"FILECONTENT", 11) !=
1206  1);
1207 
1209  StreamTcpFreeConfig(true);
1210  UTHFreeFlow(f);
1211  PASS;
1212 }
1213 
1214 void AppLayerHtpFileRegisterTests (void);
1215 #include "tests/app-layer-htp-file.c"
1216 #endif /* UNITTESTS */
1217 
1219 {
1220 #ifdef UNITTESTS
1221  UtRegisterTest("HTPFileParserTest01", HTPFileParserTest01);
1222  UtRegisterTest("HTPFileParserTest02", HTPFileParserTest02);
1223  UtRegisterTest("HTPFileParserTest03", HTPFileParserTest03);
1224  UtRegisterTest("HTPFileParserTest04", HTPFileParserTest04);
1225  UtRegisterTest("HTPFileParserTest05", HTPFileParserTest05);
1226  UtRegisterTest("HTPFileParserTest06", HTPFileParserTest06);
1227  UtRegisterTest("HTPFileParserTest07", HTPFileParserTest07);
1228  UtRegisterTest("HTPFileParserTest08", HTPFileParserTest08);
1229  UtRegisterTest("HTPFileParserTest09", HTPFileParserTest09);
1230  UtRegisterTest("HTPFileParserTest10", HTPFileParserTest10);
1231  UtRegisterTest("HTPFileParserTest11", HTPFileParserTest11);
1233 #endif /* UNITTESTS */
1234 }
HtpState_::cfg
const struct HTPCfgRec_ * cfg
Definition: app-layer-htp.h:252
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:267
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:612
stream-tcp.h
HTPCfgDir_
Definition: app-layer-htp.h:149
HtpTxUserData_::files_tc
FileContainer files_tc
Definition: app-layer-htp.h:235
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:171
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:838
Flow_::proto
uint8_t proto
Definition: flow.h:378
Flow_
Flow data structure.
Definition: flow.h:356
File_::state
FileState state
Definition: util-file.h:82
HtpState_::f
Flow * f
Definition: app-layer-htp.h:243
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:341
HttpRangeAppendData
int HttpRangeAppendData(const StreamingBufferConfig *sbcfg, HttpRangeContainerBlock *c, const uint8_t *data, uint32_t len)
Definition: app-layer-htp-range.c:377
AppLayerParserThreadCtxFree
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
Destroys the app layer parser thread context obtained using AppLayerParserThreadCtxAlloc().
Definition: app-layer-parser.c:300
FileContainer_::tail
File * tail
Definition: util-file.h:115
Flow_::protoctx
void * protoctx
Definition: flow.h:446
AppLayerDecoderEvents_
Data structure to store app layer decoder events.
Definition: app-layer-events.h:36
HTPCfgDir_::inspect_window
uint32_t inspect_window
Definition: app-layer-htp.h:152
HTPParseContentRange
int HTPParseContentRange(bstr *rawvalue, HTTPContentRange *range)
Definition: app-layer-htp-file.c:96
HtpState_
Definition: app-layer-htp.h:238
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
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:231
StreamTcpInitConfig
void StreamTcpInitConfig(bool)
To initialize the stream global configuration data.
Definition: stream-tcp.c:461
UTHBuildFlow
Flow * UTHBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp)
Definition: util-unittest-helper.c:482
HttpRangeClose
File * HttpRangeClose(const StreamingBufferConfig *sbcfg, HttpRangeContainerBlock *c, uint16_t flags)
Definition: app-layer-htp-range.c:450
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:290
HtpState_::file_track_id
uint32_t file_track_id
Definition: app-layer-htp.h:256
HTPCfgDir_::inspect_min_size
uint32_t inspect_min_size
Definition: app-layer-htp.h:151
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
HtpTxUserData_::tx_data
AppLayerTxData tx_data
Definition: app-layer-htp.h:233
app-layer-parser.h
HTPFileParserRegisterTests
void HTPFileParserRegisterTests(void)
Definition: app-layer-htp-file.c:1218
AppLayerDecoderEvents_::cnt
uint8_t cnt
Definition: app-layer-events.h:40
HTTP_DECODER_EVENT_RANGE_INVALID
@ HTTP_DECODER_EVENT_RANGE_INVALID
Definition: app-layer-htp.h:126
StreamingBufferCompareRawData
int StreamingBufferCompareRawData(const StreamingBuffer *sb, const uint8_t *rawdata, uint32_t rawdata_len)
Definition: util-streaming-buffer.c:1825
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:984
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:783
AppLayerParserGetTx
void * AppLayerParserGetTx(uint8_t ipproto, AppProto alproto, void *alstate, uint64_t tx_id)
Definition: app-layer-parser.c:1087
htp_sbcfg
StreamingBufferConfig htp_sbcfg
Definition: app-layer-htp.c:83
FileDataSize
uint64_t FileDataSize(const File *file)
get the size of the file data
Definition: util-file.c:326
HttpRangeContainerFile::hdata
THashData * hdata
Definition: app-layer-htp-range.h:68
UTHFreeFlow
void UTHFreeFlow(Flow *flow)
Definition: util-unittest-helper.c:487
AppLayerParserThreadCtxAlloc
AppLayerParserThreadCtx * AppLayerParserThreadCtxAlloc(void)
Gets a new app layer protocol's parser thread context.
Definition: app-layer-parser.c:279
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:792
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:1265
suricata-common.h
HTPCfgRec_::request
HTPCfgDir request
Definition: app-layer-htp.h:170
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:94
File_::next
struct File_ * next
Definition: util-file.h:92
FileSetInspectSizes
void FileSetInspectSizes(File *file, const uint32_t win, const uint32_t min)
Definition: util-file.c:860
FileSetRange
int FileSetRange(FileContainer *ffc, uint64_t start, uint64_t end)
Sets the offset range for a file.
Definition: util-file.c:876
HtpTxUserData_
Definition: app-layer-htp.h:206
app-layer-events.h
util-validate.h
StreamingBufferConfig_
Definition: util-streaming-buffer.h:65
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
HtpState_::events
uint16_t events
Definition: app-layer-htp.h:254
HttpRangeFreeBlock
void HttpRangeFreeBlock(HttpRangeContainerBlock *b)
Definition: app-layer-htp-range.c:607
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:1080
SCFree
#define SCFree(p)
Definition: util-mem.h:61
Flow_::alstate
void * alstate
Definition: flow.h:481
HTPFileOpenWithRange
int HTPFileOpenWithRange(HtpState *s, HtpTxUserData *txud, const uint8_t *filename, uint16_t filename_len, const uint8_t *data, uint32_t data_len, htp_tx_t *tx, bstr *rawvalue, HtpTxUserData *htud)
Sets range for a file.
Definition: app-layer-htp-file.c:149
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:234
AppLayerParserThreadCtx_
Definition: app-layer-parser.c:58
TcpSession_
Definition: stream-tcp-private.h:283
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:455
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:275
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:102