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