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 /**
264  * \brief Close the file in the flow
265  *
266  * \param tx HtpTxUserData
267  * \param data data chunk if any
268  * \param data_len length of the data portion
269  * \param flags flags to indicate events
270  * \param direction flow direction
271  *
272  * Currently on the FLOW_FILE_TRUNCATED flag is implemented, indicating
273  * that the file isn't complete but we're stopping storing it.
274  *
275  * \retval 0 ok
276  * \retval -1 error
277  * \retval -2 not storing files on this flow/tx
278  */
280  HtpTxUserData *tx, const uint8_t *data, uint32_t data_len, uint8_t flags, uint8_t direction)
281 {
282  SCEnter();
283 
284  SCLogDebug("flags %04x FILE_TRUNCATED %s", flags, (flags & FILE_TRUNCATED) ? "true" : "false");
285 
286  int retval = 0;
287  int result = 0;
288  FileContainer *files = NULL;
289 
290  if (direction & STREAM_TOCLIENT) {
291  files = &tx->files_tc;
292  } else {
293  files = &tx->files_ts;
294  }
295 
296  SCLogDebug("files %p data %p data_len %" PRIu32, files, data, data_len);
297 
298  if (files == NULL) {
299  retval = -1;
300  goto end;
301  }
302 
303  result = FileCloseFile(files, &htp_sbcfg, data, data_len, flags);
304  if (result == -1) {
305  retval = -1;
306  } else if (result == -2) {
307  retval = -2;
308  }
309  SCLogDebug("result %u", result);
310 
311  if (tx->file_range != NULL) {
312  bool added =
313  SCHTPFileCloseHandleRange(&htp_sbcfg, files, flags, tx->file_range, data, data_len);
314  if (added) {
315  tx->tx_data.files_opened++;
316  }
318  tx->file_range = NULL;
319  }
320 
321 end:
322  SCReturnInt(retval);
323 }
324 
325 #ifdef UNITTESTS
326 #include "stream-tcp.h"
327 #include "app-layer-parser.h"
328 #include "util-unittest-helper.h"
329 
330 static int HTPFileParserTest01(void)
331 {
332  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
333  "Host: www.server.lan\r\n"
334  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
335  "Content-Length: 215\r\n"
336  "\r\n"
337  "-----------------------------277531038314945\r\n"
338  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
339  "Content-Type: image/jpeg\r\n"
340  "\r\n";
341 
342  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
343  uint8_t httpbuf2[] = "filecontent\r\n"
344  "-----------------------------277531038314945--";
345  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
346 
347  TcpSession ssn;
349  HtpState *http_state = NULL;
350  memset(&ssn, 0, sizeof(ssn));
351 
352  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
353  FAIL_IF_NULL(f);
354  f->protoctx = &ssn;
355  f->proto = IPPROTO_TCP;
356  f->alproto = ALPROTO_HTTP1;
357 
358  StreamTcpInitConfig(true);
359 
360  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
361  int r = AppLayerParserParse(
362  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
363  FAIL_IF_NOT(r == 0);
364 
365  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
367  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
368  FAIL_IF_NOT(r == 0);
369 
370  http_state = f->alstate;
371  FAIL_IF_NULL(http_state);
372 
373  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
374  FAIL_IF_NULL(tx);
375  FAIL_IF_NULL(htp_tx_request_method(tx));
376 
377  char *m = bstr_util_strdup_to_c(htp_tx_request_method(tx));
378  FAIL_IF(memcmp(m, "POST", 4) != 0);
379  SCFree(m);
380 
382  StreamTcpFreeConfig(true);
383  UTHFreeFlow(f);
384  PASS;
385 }
386 
387 static int HTPFileParserTest02(void)
388 {
389  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
390  "Host: www.server.lan\r\n"
391  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
392  "Content-Length: 337\r\n"
393  "\r\n";
394  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
395 
396  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
397  "Content-Disposition: form-data; name=\"email\"\r\n"
398  "\r\n"
399  "someaddress@somedomain.lan\r\n";
400  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
401 
402  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
403  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
404  "Content-Type: image/jpeg\r\n"
405  "\r\n";
406  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
407 
408  uint8_t httpbuf4[] = "filecontent\r\n"
409  "-----------------------------277531038314945--";
410  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
411 
412  TcpSession ssn;
413  HtpState *http_state = NULL;
415 
416  memset(&ssn, 0, sizeof(ssn));
417 
418  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
419  FAIL_IF_NULL(f);
420  f->protoctx = &ssn;
421  f->proto = IPPROTO_TCP;
422  f->alproto = ALPROTO_HTTP1;
423 
424  StreamTcpInitConfig(true);
425 
426  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
427  int r = AppLayerParserParse(
428  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
429  FAIL_IF_NOT(r == 0);
430 
431  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
433  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
434  FAIL_IF_NOT(r == 0);
435 
436  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
438  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
439  FAIL_IF_NOT(r == 0);
440 
441  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
443  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
444  FAIL_IF_NOT(r == 0);
445 
446  http_state = f->alstate;
447  FAIL_IF_NULL(http_state);
448 
449  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
450  FAIL_IF_NULL(tx);
451  FAIL_IF_NULL(htp_tx_request_method(tx));
452  char *m = bstr_util_strdup_to_c(htp_tx_request_method(tx));
453  FAIL_IF(memcmp(m, "POST", 4) != 0);
454  SCFree(m);
455  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
456  FAIL_IF_NULL(tx_ud);
457  FAIL_IF_NULL(tx_ud->files_ts.tail);
459 
461  StreamTcpFreeConfig(true);
462  UTHFreeFlow(f);
463  PASS;
464 }
465 
466 static int HTPFileParserTest03(void)
467 {
468  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
469  "Host: www.server.lan\r\n"
470  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
471  "Content-Length: 337\r\n"
472  "\r\n";
473  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
474 
475  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
476  "Content-Disposition: form-data; name=\"email\"\r\n"
477  "\r\n"
478  "someaddress@somedomain.lan\r\n";
479  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
480 
481  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
482  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
483  "Content-Type: image/jpeg\r\n"
484  "\r\n";
485  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
486 
487  uint8_t httpbuf4[] = "file";
488  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
489 
490  uint8_t httpbuf5[] = "content\r\n";
491  uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
492 
493  uint8_t httpbuf6[] = "-----------------------------277531038314945--";
494  uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
495 
496  TcpSession ssn;
497  HtpState *http_state = NULL;
499 
500  memset(&ssn, 0, sizeof(ssn));
501 
502  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
503  FAIL_IF_NULL(f);
504  f->protoctx = &ssn;
505  f->proto = IPPROTO_TCP;
506  f->alproto = ALPROTO_HTTP1;
507 
508  StreamTcpInitConfig(true);
509 
510  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
511  int r = AppLayerParserParse(
512  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
513  FAIL_IF_NOT(r == 0);
514 
515  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
517  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
518  FAIL_IF_NOT(r == 0);
519 
520  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
522  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
523  FAIL_IF_NOT(r == 0);
524 
525  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
527  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
528  FAIL_IF_NOT(r == 0);
529 
530  SCLogDebug("\n>>>> processing chunk 5 size %u <<<<\n", httplen5);
532  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf5, httplen5);
533  FAIL_IF_NOT(r == 0);
534 
535  SCLogDebug("\n>>>> processing chunk 6 size %u <<<<\n", httplen6);
537  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf6, httplen6);
538  FAIL_IF_NOT(r == 0);
539 
540  http_state = f->alstate;
541  FAIL_IF_NULL(http_state);
542 
543  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
544  FAIL_IF_NULL(tx);
545  FAIL_IF_NULL(htp_tx_request_method(tx));
546 
547  char *m = bstr_util_strdup_to_c(htp_tx_request_method(tx));
548  FAIL_IF(memcmp(m, "POST", 4) != 0);
549  SCFree(m);
550 
551  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
552  FAIL_IF_NULL(tx_ud);
553  FAIL_IF_NULL(tx_ud->files_ts.head);
554  FAIL_IF_NULL(tx_ud->files_ts.tail);
556  FAIL_IF(FileDataSize(tx_ud->files_ts.head) != 11);
557 
559  StreamTcpFreeConfig(true);
560  UTHFreeFlow(f);
561  PASS;
562 }
563 
564 static int HTPFileParserTest04(void)
565 {
566  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
567  "Host: www.server.lan\r\n"
568  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
569  "Content-Length: 373\r\n"
570  "\r\n";
571  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
572 
573  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
574  "Content-Disposition: form-data; name=\"email\"\r\n"
575  "\r\n"
576  "someaddress@somedomain.lan\r\n";
577  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
578 
579  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
580  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
581  "Content-Type: image/jpeg\r\n"
582  "\r\n";
583  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
584 
585  uint8_t httpbuf4[] = "file0123456789abcdefghijklmnopqrstuvwxyz";
586  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
587 
588  uint8_t httpbuf5[] = "content\r\n";
589  uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
590 
591  uint8_t httpbuf6[] = "-----------------------------277531038314945--";
592  uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
593 
594  TcpSession ssn;
595  HtpState *http_state = NULL;
597 
598  memset(&ssn, 0, sizeof(ssn));
599 
600  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
601  FAIL_IF_NULL(f);
602  f->protoctx = &ssn;
603  f->proto = IPPROTO_TCP;
604  f->alproto = ALPROTO_HTTP1;
605 
606  StreamTcpInitConfig(true);
607 
608  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
609  int r = AppLayerParserParse(
610  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
611  FAIL_IF_NOT(r == 0);
612 
613  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
615  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
616  FAIL_IF_NOT(r == 0);
617 
618  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
620  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
621  FAIL_IF_NOT(r == 0);
622 
623  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
625  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
626  FAIL_IF_NOT(r == 0);
627 
628  SCLogDebug("\n>>>> processing chunk 5 size %u <<<<\n", httplen5);
630  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf5, httplen5);
631  FAIL_IF_NOT(r == 0);
632 
633  SCLogDebug("\n>>>> processing chunk 6 size %u <<<<\n", httplen6);
635  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf6, httplen6);
636  FAIL_IF_NOT(r == 0);
637 
638  http_state = f->alstate;
639  FAIL_IF_NULL(http_state);
640 
641  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
642  FAIL_IF_NULL(tx);
643  FAIL_IF_NULL(htp_tx_request_method(tx));
644 
645  char *m = bstr_util_strdup_to_c(htp_tx_request_method(tx));
646  FAIL_IF(memcmp(m, "POST", 4) != 0);
647  SCFree(m);
648 
649  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
650  FAIL_IF_NULL(tx_ud);
651  FAIL_IF_NULL(tx_ud->files_ts.head);
652  FAIL_IF_NULL(tx_ud->files_ts.tail);
654 
656  StreamTcpFreeConfig(true);
657  UTHFreeFlow(f);
658  PASS;
659 }
660 
661 static int HTPFileParserTest05(void)
662 {
663  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
664  "Host: www.server.lan\r\n"
665  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
666  "Content-Length: 544\r\n"
667  "\r\n"
668  "-----------------------------277531038314945\r\n"
669  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
670  "Content-Type: image/jpeg\r\n"
671  "\r\n"
672  "filecontent\r\n"
673  "-----------------------------277531038314945\r\n";
674  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
675  uint8_t httpbuf2[] = "Content-Disposition: form-data; name=\"uploadfile_1\"; filename=\"somepicture2.jpg\"\r\n"
676  "Content-Type: image/jpeg\r\n"
677  "\r\n"
678  "FILECONTENT\r\n"
679  "-----------------------------277531038314945--";
680  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
681 
682  TcpSession ssn;
683  HtpState *http_state = NULL;
685 
686  memset(&ssn, 0, sizeof(ssn));
687 
688  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
689  FAIL_IF_NULL(f);
690  f->protoctx = &ssn;
691  f->proto = IPPROTO_TCP;
692  f->alproto = ALPROTO_HTTP1;
693 
694  StreamTcpInitConfig(true);
695 
696  SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1);
697  int r = AppLayerParserParse(
698  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
699  FAIL_IF_NOT(r == 0);
700 
701  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
703  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
704  FAIL_IF_NOT(r == 0);
705 
706  http_state = f->alstate;
707  FAIL_IF_NULL(http_state);
708 
709  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
710  FAIL_IF_NULL(tx);
711  FAIL_IF_NULL(htp_tx_request_method(tx));
712 
713  char *m = bstr_util_strdup_to_c(htp_tx_request_method(tx));
714  FAIL_IF(memcmp(m, "POST", 4) != 0);
715  SCFree(m);
716 
717  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
718  FAIL_IF_NULL(tx_ud);
719  FAIL_IF_NULL(tx_ud->files_ts.head);
720  FAIL_IF_NULL(tx_ud->files_ts.tail);
722 
723  FAIL_IF(tx_ud->files_ts.head == tx_ud->files_ts.tail);
724  FAIL_IF(tx_ud->files_ts.head->next != tx_ud->files_ts.tail);
725 
726  FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.head->sb, (uint8_t *)"filecontent", 11) !=
727  1);
728 
729  FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.tail->sb, (uint8_t *)"FILECONTENT", 11) !=
730  1);
732  StreamTcpFreeConfig(true);
733  UTHFreeFlow(f);
734  PASS;
735 }
736 
737 /** \test first multipart part contains file but doesn't end in first chunk */
738 static int HTPFileParserTest06(void)
739 {
740  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
741  "Host: www.server.lan\r\n"
742  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
743  "Content-Length: 544\r\n"
744  "\r\n"
745  "-----------------------------277531038314945\r\n"
746  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
747  "Content-Type: image/jpeg\r\n"
748  "\r\n"
749  "filecontent\r\n"
750  "-----------------------------27753103831494";
751  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
752  uint8_t httpbuf2[] = "5\r\nContent-Disposition: form-data; name=\"uploadfile_1\"; filename=\"somepicture2.jpg\"\r\n"
753  "Content-Type: image/jpeg\r\n"
754  "\r\n"
755  "FILECONTENT\r\n"
756  "-----------------------------277531038314945--";
757  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
758 
759  TcpSession ssn;
760  HtpState *http_state = NULL;
762 
763  memset(&ssn, 0, sizeof(ssn));
764 
765  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
766  FAIL_IF_NULL(f);
767  f->protoctx = &ssn;
768  f->proto = IPPROTO_TCP;
769  f->alproto = ALPROTO_HTTP1;
770 
771  StreamTcpInitConfig(true);
772 
773  SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1);
774  int r = AppLayerParserParse(
775  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
776  FAIL_IF_NOT(r == 0);
777 
778  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
780  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
781  FAIL_IF_NOT(r == 0);
782 
783  http_state = f->alstate;
784  FAIL_IF_NULL(http_state);
785 
786  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
787  FAIL_IF_NULL(tx);
788  FAIL_IF_NULL(htp_tx_request_method(tx));
789 
790  char *m = bstr_util_strdup_to_c(htp_tx_request_method(tx));
791  FAIL_IF(memcmp(m, "POST", 4) != 0);
792  SCFree(m);
793 
794  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
795  FAIL_IF_NULL(tx_ud);
796  FAIL_IF_NULL(tx_ud->files_ts.head);
797  FAIL_IF_NULL(tx_ud->files_ts.tail);
799 
800  FAIL_IF(tx_ud->files_ts.head == tx_ud->files_ts.tail);
801  FAIL_IF(tx_ud->files_ts.head->next != tx_ud->files_ts.tail);
802 
803  FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.head->sb, (uint8_t *)"filecontent", 11) !=
804  1);
805 
806  FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.tail->sb, (uint8_t *)"FILECONTENT", 11) !=
807  1);
808 
810  StreamTcpFreeConfig(true);
811  UTHFreeFlow(f);
812  PASS;
813 }
814 
815 /** \test POST, but not multipart */
816 static int HTPFileParserTest07(void)
817 {
818  uint8_t httpbuf1[] = "POST /filename HTTP/1.1\r\n"
819  "Host: www.server.lan\r\n"
820  "Content-Length: 11\r\n"
821  "\r\n";
822  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
823  uint8_t httpbuf2[] = "FILECONTENT";
824  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
825 
826  TcpSession ssn;
827  HtpState *http_state = NULL;
829 
830  memset(&ssn, 0, sizeof(ssn));
831 
832  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
833  FAIL_IF_NULL(f);
834  f->protoctx = &ssn;
835  f->proto = IPPROTO_TCP;
836  f->alproto = ALPROTO_HTTP1;
837 
838  StreamTcpInitConfig(true);
839 
840  SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1);
841  int r = AppLayerParserParse(
842  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
843  FAIL_IF_NOT(r == 0);
844 
845  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
847  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
848  FAIL_IF_NOT(r == 0);
849 
850  http_state = f->alstate;
851  FAIL_IF_NULL(http_state);
852 
853  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
854  FAIL_IF_NULL(tx);
855  FAIL_IF_NULL(htp_tx_request_method(tx));
856  char *m = bstr_util_strdup_to_c(htp_tx_request_method(tx));
857  FAIL_IF(memcmp(m, "POST", 4) != 0);
858  SCFree(m);
859 
860  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
861  FAIL_IF_NULL(tx_ud);
862  FAIL_IF_NULL(tx_ud->files_ts.head);
863  FAIL_IF_NULL(tx_ud->files_ts.tail);
865 
866  FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.tail->sb, (uint8_t *)"FILECONTENT", 11) !=
867  1);
868 
870  StreamTcpFreeConfig(true);
871  UTHFreeFlow(f);
872  PASS;
873 }
874 
875 static int HTPFileParserTest08(void)
876 {
877  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
878  "Host: www.server.lan\r\n"
879  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
880  "Content-Length: 215\r\n"
881  "\r\n"
882  "-----------------------------277531038314945\r\n"
883  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
884  "Content-Type: image/jpeg\r\n";
885 
886  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
887  uint8_t httpbuf2[] = "filecontent\r\n\r\n"
888  "-----------------------------277531038314945--";
889  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
890 
891  TcpSession ssn;
893  HtpState *http_state = NULL;
894  memset(&ssn, 0, sizeof(ssn));
895 
896  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
897  FAIL_IF_NULL(f);
898  f->protoctx = &ssn;
899  f->proto = IPPROTO_TCP;
900  f->alproto = ALPROTO_HTTP1;
901 
902  StreamTcpInitConfig(true);
903 
904  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
905  int r = AppLayerParserParse(
906  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
907  FAIL_IF_NOT(r == 0);
908 
909  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
911  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
912  FAIL_IF_NOT(r == 0);
913 
914  http_state = f->alstate;
915  FAIL_IF_NULL(http_state);
916 
917  void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
918  FAIL_IF_NULL(tx);
919 
920  AppLayerDecoderEvents *decoder_events =
921  AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, tx);
922  FAIL_IF_NULL(decoder_events);
923 
924  FAIL_IF(decoder_events->cnt != 2);
925 
927  StreamTcpFreeConfig(true);
928  UTHFreeFlow(f);
929  PASS;
930 }
931 
932 /** \test invalid header: Somereallylongheaderstr: has no value */
933 static int HTPFileParserTest09(void)
934 {
935  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
936  "Host: www.server.lan\r\n"
937  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
938  "Content-Length: 337\r\n"
939  "\r\n";
940  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
941 
942  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
943  "Content-Disposition: form-data; name=\"email\"\r\n"
944  "\r\n"
945  "someaddress@somedomain.lan\r\n";
946  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
947 
948  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
949  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
950  "Somereallylongheaderstr:\r\n"
951  "\r\n";
952  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
953 
954  uint8_t httpbuf4[] = "filecontent\r\n"
955  "-----------------------------277531038314945--";
956  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
957 
958  TcpSession ssn;
959  HtpState *http_state = NULL;
961 
962  memset(&ssn, 0, sizeof(ssn));
963 
964  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
965  FAIL_IF_NULL(f);
966  f->protoctx = &ssn;
967  f->proto = IPPROTO_TCP;
968  f->alproto = ALPROTO_HTTP1;
969 
970  StreamTcpInitConfig(true);
971 
972  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
973  int r = AppLayerParserParse(
974  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
975  FAIL_IF_NOT(r == 0);
976 
977  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
979  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
980  FAIL_IF_NOT(r == 0);
981 
982  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
984  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
985  FAIL_IF_NOT(r == 0);
986 
987  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
989  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
990  FAIL_IF_NOT(r == 0);
991 
992  http_state = f->alstate;
993  FAIL_IF_NULL(http_state);
994 
995  void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
996  FAIL_IF_NULL(tx);
997 
998  AppLayerDecoderEvents *decoder_events =
999  AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, tx);
1000  FAIL_IF_NULL(decoder_events);
1001 
1002  FAIL_IF(decoder_events->cnt != 1);
1003 
1005  StreamTcpFreeConfig(true);
1006  UTHFreeFlow(f);
1007  PASS;
1008 }
1009 
1010 /** \test empty entries */
1011 static int HTPFileParserTest10(void)
1012 {
1013  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
1014  "Host: www.server.lan\r\n"
1015  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
1016  "Content-Length: 337\r\n"
1017  "\r\n";
1018  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1019 
1020  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
1021  "\r\n";
1022  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1023 
1024  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
1025  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
1026  "Somereallylongheaderstr: with a good value\r\n"
1027  "\r\n";
1028  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1029 
1030  uint8_t httpbuf4[] = "filecontent\r\n"
1031  "-----------------------------277531038314945--";
1032  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1033 
1034  TcpSession ssn;
1035  HtpState *http_state = NULL;
1037 
1038  memset(&ssn, 0, sizeof(ssn));
1039 
1040  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1041  FAIL_IF_NULL(f);
1042  f->protoctx = &ssn;
1043  f->proto = IPPROTO_TCP;
1044  f->alproto = ALPROTO_HTTP1;
1045 
1046  StreamTcpInitConfig(true);
1047 
1048  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
1049  int r = AppLayerParserParse(
1050  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
1051  FAIL_IF_NOT(r == 0);
1052 
1053  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
1054  r = AppLayerParserParse(
1055  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
1056  FAIL_IF_NOT(r == 0);
1057 
1058  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
1059  r = AppLayerParserParse(
1060  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
1061  FAIL_IF_NOT(r == 0);
1062 
1063  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
1064  r = AppLayerParserParse(
1065  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1066  FAIL_IF_NOT(r == 0);
1067 
1068  http_state = f->alstate;
1069  FAIL_IF_NULL(http_state);
1070 
1071  void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
1072  FAIL_IF_NULL(tx);
1073  AppLayerDecoderEvents *decoder_events =
1074  AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, tx);
1075  FAIL_IF_NOT_NULL(decoder_events);
1076 
1078  StreamTcpFreeConfig(true);
1079  UTHFreeFlow(f);
1080  PASS;
1081 }
1082 
1083 /** \test filedata cut in two pieces */
1084 static int HTPFileParserTest11(void)
1085 {
1086  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
1087  "Host: www.server.lan\r\n"
1088  "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1089  "Content-Length: 1102\r\n"
1090  "\r\n";
1091  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1092 
1093  uint8_t httpbuf2[] = "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n";
1094  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1095 
1096  uint8_t httpbuf3[] = "Content-Disposition: form-data; name=\"PROGRESS_URL\"\r\n"
1097  "\r\n"
1098  "http://somserver.com/progress.php?UPLOAD_IDENTIFIER=XXXXXXXXX.XXXXXXXXXX.XXXXXXXX.XX.X\r\n"
1099  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1100  "Content-Disposition: form-data; name=\"DESTINATION_DIR\"\r\n"
1101  "\r\n"
1102  "10\r\n"
1103  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1104  "Content-Disposition: form-data; name=\"js_enabled\"\r\n"
1105  "\r\n"
1106  "1"
1107  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1108  "Content-Disposition: form-data; name=\"signature\"\r\n"
1109  "\r\n"
1110  "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n"
1111  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1112  "Content-Disposition: form-data; name=\"upload_files\"\r\n"
1113  "\r\n"
1114  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1115  "Content-Disposition: form-data; name=\"terms\"\r\n"
1116  "\r\n"
1117  "1"
1118  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1119  "Content-Disposition: form-data; name=\"file[]\"\r\n"
1120  "\r\n"
1121  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1122  "Content-Disposition: form-data; name=\"description[]\"\r\n"
1123  "\r\n"
1124  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1125  "Content-Disposition: form-data; name=\"upload_file[]\"; filename=\"filename.doc\"\r\n"
1126  "Content-Type: application/msword\r\n"
1127  "\r\n"
1128  "FILE";
1129  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1130 
1131  uint8_t httpbuf4[] = "CONTENT\r\n"
1132  "------WebKitFormBoundaryBRDbP74mBhBxsIdo--";
1133  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1134 
1135  TcpSession ssn;
1136  HtpState *http_state = NULL;
1138 
1139  memset(&ssn, 0, sizeof(ssn));
1140 
1141  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1142  FAIL_IF_NULL(f);
1143  f->protoctx = &ssn;
1144  f->proto = IPPROTO_TCP;
1145  f->alproto = ALPROTO_HTTP1;
1146 
1147  StreamTcpInitConfig(true);
1148 
1149  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
1150  int r = AppLayerParserParse(
1151  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
1152  FAIL_IF_NOT(r == 0);
1153 
1154  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
1155  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
1156  FAIL_IF_NOT(r == 0);
1157 
1158  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
1159  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf3, httplen3);
1160  FAIL_IF_NOT(r == 0);
1161 
1162  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
1163  r = AppLayerParserParse(
1164  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1165  FAIL_IF_NOT(r == 0);
1166 
1167  http_state = f->alstate;
1168  FAIL_IF_NULL(http_state);
1169 
1170  void *txtmp = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
1171  FAIL_IF_NULL(txtmp);
1172 
1173  AppLayerDecoderEvents *decoder_events =
1174  AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, txtmp);
1175  FAIL_IF_NOT_NULL(decoder_events);
1176 
1177  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
1178  FAIL_IF_NULL(tx);
1179  FAIL_IF_NULL(htp_tx_request_method(tx));
1180 
1181  char *m = bstr_util_strdup_to_c(htp_tx_request_method(tx));
1182  FAIL_IF(memcmp(m, "POST", 4) != 0);
1183  SCFree(m);
1184 
1185  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
1186  FAIL_IF_NULL(tx_ud);
1187  FAIL_IF_NULL(tx_ud->files_ts.head);
1188  FAIL_IF_NULL(tx_ud->files_ts.tail);
1190 
1191  FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.tail->sb, (uint8_t *)"FILECONTENT", 11) !=
1192  1);
1193 
1195  StreamTcpFreeConfig(true);
1196  UTHFreeFlow(f);
1197  PASS;
1198 }
1199 
1200 void AppLayerHtpFileRegisterTests (void);
1201 #include "tests/app-layer-htp-file.c"
1202 #endif /* UNITTESTS */
1203 
1205 {
1206 #ifdef UNITTESTS
1207  UtRegisterTest("HTPFileParserTest01", HTPFileParserTest01);
1208  UtRegisterTest("HTPFileParserTest02", HTPFileParserTest02);
1209  UtRegisterTest("HTPFileParserTest03", HTPFileParserTest03);
1210  UtRegisterTest("HTPFileParserTest04", HTPFileParserTest04);
1211  UtRegisterTest("HTPFileParserTest05", HTPFileParserTest05);
1212  UtRegisterTest("HTPFileParserTest06", HTPFileParserTest06);
1213  UtRegisterTest("HTPFileParserTest07", HTPFileParserTest07);
1214  UtRegisterTest("HTPFileParserTest08", HTPFileParserTest08);
1215  UtRegisterTest("HTPFileParserTest09", HTPFileParserTest09);
1216  UtRegisterTest("HTPFileParserTest10", HTPFileParserTest10);
1217  UtRegisterTest("HTPFileParserTest11", HTPFileParserTest11);
1219 #endif /* UNITTESTS */
1220 }
HtpState_::cfg
const struct HTPCfgRec_ * cfg
Definition: app-layer-htp.h:188
FILE_TRUNCATED
#define FILE_TRUNCATED
Definition: util-file.h:105
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
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:843
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:142
HtpState_::f
Flow * f
Definition: app-layer-htp.h:186
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:143
app-layer-htp-file.h
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:496
UTHBuildFlow
Flow * UTHBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp)
Definition: util-unittest-helper.c:497
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
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:1204
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:1095
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
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
FILE_STATE_CLOSED
@ FILE_STATE_CLOSED
Definition: util-file.h:131
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:867
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:1277
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:152
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:1050
SCFree
#define SCFree(p)
Definition: util-mem.h:61
Flow_::alstate
void * alstate
Definition: flow.h:471
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-range.c:635
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:279
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