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, const uint8_t *filename, uint16_t filename_len,
80  const uint8_t *data, uint32_t data_len,
81  uint64_t txid, uint8_t direction)
82 {
83  int retval = 0;
84  uint16_t flags = 0;
85  FileContainer *files = NULL;
86  const StreamingBufferConfig *sbcfg = NULL;
87 
88  SCLogDebug("data %p data_len %"PRIu32, data, data_len);
89 
90  if (s == NULL) {
91  SCReturnInt(-1);
92  }
93 
94  if (direction & STREAM_TOCLIENT) {
95  if (s->files_tc == NULL) {
97  if (s->files_tc == NULL) {
98  retval = -1;
99  goto end;
100  }
101  }
102 
103  files = s->files_tc;
104 
105  flags = FileFlowToFlags(s->f, STREAM_TOCLIENT);
106 
107  if ((s->flags & HTP_FLAG_STORE_FILES_TS) ||
108  ((s->flags & HTP_FLAG_STORE_FILES_TX_TS) && txid == s->store_tx_id)) {
109  flags |= FILE_STORE;
110  flags &= ~FILE_NOSTORE;
111  } else if (!(flags & FILE_STORE) && (s->f->file_flags & FLOWFILE_NO_STORE_TC)) {
112  flags |= FILE_NOSTORE;
113  }
114 
115  sbcfg = &s->cfg->response.sbcfg;
116 
117  } else {
118  if (s->files_ts == NULL) {
120  if (s->files_ts == NULL) {
121  retval = -1;
122  goto end;
123  }
124  }
125 
126  files = s->files_ts;
127 
128  flags = FileFlowToFlags(s->f, STREAM_TOSERVER);
129  if ((s->flags & HTP_FLAG_STORE_FILES_TC) ||
130  ((s->flags & HTP_FLAG_STORE_FILES_TX_TC) && txid == s->store_tx_id)) {
131  flags |= FILE_STORE;
132  flags &= ~FILE_NOSTORE;
133  } else if (!(flags & FILE_STORE) && (s->f->file_flags & FLOWFILE_NO_STORE_TS)) {
134  flags |= FILE_NOSTORE;
135  }
136 
137  sbcfg = &s->cfg->request.sbcfg;
138  }
139 
140  if (FileOpenFileWithId(files, sbcfg, s->file_track_id++,
141  filename, filename_len,
142  data, data_len, flags) != 0)
143  {
144  retval = -1;
145  }
146 
147  FileSetTx(files->tail, txid);
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_HTTP;
386 
388 
389  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
390  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
391  STREAM_TOSERVER | STREAM_START, httpbuf1,
392  httplen1);
393  FAIL_IF_NOT(r == 0);
394 
395  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
396  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
397  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
398  FAIL_IF_NOT(r == 0);
399 
400  http_state = f->alstate;
401  FAIL_IF_NULL(http_state);
402 
403  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, http_state, 0);
404  FAIL_IF_NULL(tx);
405  FAIL_IF_NULL(tx->request_method);
406 
407  FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0);
408 
409  AppLayerParserThreadCtxFree(alp_tctx);
411  UTHFreeFlow(f);
412  PASS;
413 }
414 
415 static int HTPFileParserTest02(void)
416 {
417  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
418  "Host: www.server.lan\r\n"
419  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
420  "Content-Length: 337\r\n"
421  "\r\n";
422  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
423 
424  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
425  "Content-Disposition: form-data; name=\"email\"\r\n"
426  "\r\n"
427  "someaddress@somedomain.lan\r\n";
428  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
429 
430  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
431  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
432  "Content-Type: image/jpeg\r\n"
433  "\r\n";
434  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
435 
436  uint8_t httpbuf4[] = "filecontent\r\n"
437  "-----------------------------277531038314945--";
438  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
439 
440  TcpSession ssn;
441  HtpState *http_state = NULL;
443 
444  memset(&ssn, 0, sizeof(ssn));
445 
446  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
447  FAIL_IF_NULL(f);
448  f->protoctx = &ssn;
449  f->proto = IPPROTO_TCP;
450  f->alproto = ALPROTO_HTTP;
451 
453 
454  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
455  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
456  STREAM_TOSERVER | STREAM_START, httpbuf1,
457  httplen1);
458  FAIL_IF_NOT(r == 0);
459 
460  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
461  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
462  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
463  FAIL_IF_NOT(r == 0);
464 
465  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
466  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
467  STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
468  FAIL_IF_NOT(r == 0);
469 
470  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
471  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
472  STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
473  FAIL_IF_NOT(r == 0);
474 
475  http_state = f->alstate;
476  FAIL_IF_NULL(http_state);
477 
478  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, http_state, 0);
479  FAIL_IF_NULL(tx);
480  FAIL_IF_NULL(tx->request_method);
481  FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0);
482  FAIL_IF_NULL(http_state->files_ts);
483  FAIL_IF_NULL(http_state->files_ts->tail);
484  FAIL_IF(http_state->files_ts->tail->state != FILE_STATE_CLOSED);
485 
486  AppLayerParserThreadCtxFree(alp_tctx);
488  UTHFreeFlow(f);
489  PASS;
490 }
491 
492 static int HTPFileParserTest03(void)
493 {
494  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
495  "Host: www.server.lan\r\n"
496  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
497  "Content-Length: 337\r\n"
498  "\r\n";
499  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
500 
501  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
502  "Content-Disposition: form-data; name=\"email\"\r\n"
503  "\r\n"
504  "someaddress@somedomain.lan\r\n";
505  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
506 
507  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
508  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
509  "Content-Type: image/jpeg\r\n"
510  "\r\n";
511  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
512 
513  uint8_t httpbuf4[] = "file";
514  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
515 
516  uint8_t httpbuf5[] = "content\r\n";
517  uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
518 
519  uint8_t httpbuf6[] = "-----------------------------277531038314945--";
520  uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
521 
522  TcpSession ssn;
523  HtpState *http_state = NULL;
525 
526  memset(&ssn, 0, sizeof(ssn));
527 
528  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
529  FAIL_IF_NULL(f);
530  f->protoctx = &ssn;
531  f->proto = IPPROTO_TCP;
532  f->alproto = ALPROTO_HTTP;
533 
535 
536  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
537  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
538  STREAM_TOSERVER | STREAM_START, httpbuf1,
539  httplen1);
540  FAIL_IF_NOT(r == 0);
541 
542  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
543  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
544  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
545  FAIL_IF_NOT(r == 0);
546 
547  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
548  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
549  STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
550  FAIL_IF_NOT(r == 0);
551 
552  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
553  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
554  STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
555  FAIL_IF_NOT(r == 0);
556 
557  SCLogDebug("\n>>>> processing chunk 5 size %u <<<<\n", httplen5);
558  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
559  STREAM_TOSERVER | STREAM_EOF, httpbuf5, httplen5);
560  FAIL_IF_NOT(r == 0);
561 
562  SCLogDebug("\n>>>> processing chunk 6 size %u <<<<\n", httplen6);
563  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
564  STREAM_TOSERVER | STREAM_EOF, httpbuf6, httplen6);
565  FAIL_IF_NOT(r == 0);
566 
567  http_state = f->alstate;
568  FAIL_IF_NULL(http_state);
569 
570  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, http_state, 0);
571  FAIL_IF_NULL(tx);
572  FAIL_IF_NULL(tx->request_method);
573 
574  FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0);
575 
576  FAIL_IF_NULL(http_state->files_ts);
577  FAIL_IF_NULL(http_state->files_ts->head);
578  FAIL_IF_NULL(http_state->files_ts->tail);
579  FAIL_IF(http_state->files_ts->tail->state != FILE_STATE_CLOSED);
580  FAIL_IF(FileDataSize(http_state->files_ts->head) != 11);
581 
582  AppLayerParserThreadCtxFree(alp_tctx);
584  UTHFreeFlow(f);
585  PASS;
586 }
587 
588 static int HTPFileParserTest04(void)
589 {
590  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
591  "Host: www.server.lan\r\n"
592  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
593  "Content-Length: 373\r\n"
594  "\r\n";
595  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
596 
597  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
598  "Content-Disposition: form-data; name=\"email\"\r\n"
599  "\r\n"
600  "someaddress@somedomain.lan\r\n";
601  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
602 
603  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
604  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
605  "Content-Type: image/jpeg\r\n"
606  "\r\n";
607  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
608 
609  uint8_t httpbuf4[] = "file0123456789abcdefghijklmnopqrstuvwxyz";
610  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
611 
612  uint8_t httpbuf5[] = "content\r\n";
613  uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
614 
615  uint8_t httpbuf6[] = "-----------------------------277531038314945--";
616  uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
617 
618  TcpSession ssn;
619  HtpState *http_state = NULL;
621 
622  memset(&ssn, 0, sizeof(ssn));
623 
624  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
625  FAIL_IF_NULL(f);
626  f->protoctx = &ssn;
627  f->proto = IPPROTO_TCP;
628  f->alproto = ALPROTO_HTTP;
629 
631 
632  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
633  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
634  STREAM_TOSERVER | STREAM_START, httpbuf1,
635  httplen1);
636  FAIL_IF_NOT(r == 0);
637 
638  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
639  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
640  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
641  FAIL_IF_NOT(r == 0);
642 
643  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
644  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
645  STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
646  FAIL_IF_NOT(r == 0);
647 
648  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
649  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
650  STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
651  FAIL_IF_NOT(r == 0);
652 
653  SCLogDebug("\n>>>> processing chunk 5 size %u <<<<\n", httplen5);
654  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
655  STREAM_TOSERVER | STREAM_EOF, httpbuf5, httplen5);
656  FAIL_IF_NOT(r == 0);
657 
658  SCLogDebug("\n>>>> processing chunk 6 size %u <<<<\n", httplen6);
659  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
660  STREAM_TOSERVER | STREAM_EOF, httpbuf6, httplen6);
661  FAIL_IF_NOT(r == 0);
662 
663  http_state = f->alstate;
664  FAIL_IF_NULL(http_state);
665 
666  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, http_state, 0);
667  FAIL_IF_NULL(tx);
668  FAIL_IF_NULL(tx->request_method);
669 
670  FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0);
671 
672  FAIL_IF_NULL(http_state->files_ts);
673  FAIL_IF_NULL(http_state->files_ts->head);
674  FAIL_IF_NULL(http_state->files_ts->tail);
675  FAIL_IF(http_state->files_ts->tail->state != FILE_STATE_CLOSED);
676 
677  AppLayerParserThreadCtxFree(alp_tctx);
679  UTHFreeFlow(f);
680  PASS;
681 }
682 
683 static int HTPFileParserTest05(void)
684 {
685  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
686  "Host: www.server.lan\r\n"
687  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
688  "Content-Length: 544\r\n"
689  "\r\n"
690  "-----------------------------277531038314945\r\n"
691  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
692  "Content-Type: image/jpeg\r\n"
693  "\r\n"
694  "filecontent\r\n"
695  "-----------------------------277531038314945\r\n";
696  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
697  uint8_t httpbuf2[] = "Content-Disposition: form-data; name=\"uploadfile_1\"; filename=\"somepicture2.jpg\"\r\n"
698  "Content-Type: image/jpeg\r\n"
699  "\r\n"
700  "FILECONTENT\r\n"
701  "-----------------------------277531038314945--";
702  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
703 
704  TcpSession ssn;
705  HtpState *http_state = NULL;
707 
708  memset(&ssn, 0, sizeof(ssn));
709 
710  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
711  FAIL_IF_NULL(f);
712  f->protoctx = &ssn;
713  f->proto = IPPROTO_TCP;
714  f->alproto = ALPROTO_HTTP;
715 
717 
718  SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1);
719  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
720  STREAM_TOSERVER | STREAM_START, httpbuf1,
721  httplen1);
722  FAIL_IF_NOT(r == 0);
723 
724  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
725  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
726  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
727  FAIL_IF_NOT(r == 0);
728 
729  http_state = f->alstate;
730  FAIL_IF_NULL(http_state);
731 
732  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, http_state, 0);
733  FAIL_IF_NULL(tx);
734  FAIL_IF_NULL(tx->request_method);
735 
736  FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0);
737 
738  FAIL_IF_NULL(http_state->files_ts);
739  FAIL_IF_NULL(http_state->files_ts->head);
740  FAIL_IF_NULL(http_state->files_ts->tail);
741  FAIL_IF(http_state->files_ts->tail->state != FILE_STATE_CLOSED);
742 
743  FAIL_IF(http_state->files_ts->head == http_state->files_ts->tail);
744  FAIL_IF(http_state->files_ts->head->next != http_state->files_ts->tail);
745 
747  (uint8_t *)"filecontent", 11) != 1);
748 
750  (uint8_t *)"FILECONTENT", 11) != 1);
751  AppLayerParserThreadCtxFree(alp_tctx);
753  UTHFreeFlow(f);
754  PASS;
755 }
756 
757 /** \test first multipart part contains file but doesn't end in first chunk */
758 static int HTPFileParserTest06(void)
759 {
760  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
761  "Host: www.server.lan\r\n"
762  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
763  "Content-Length: 544\r\n"
764  "\r\n"
765  "-----------------------------277531038314945\r\n"
766  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
767  "Content-Type: image/jpeg\r\n"
768  "\r\n"
769  "filecontent\r\n"
770  "-----------------------------27753103831494";
771  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
772  uint8_t httpbuf2[] = "5\r\nContent-Disposition: form-data; name=\"uploadfile_1\"; filename=\"somepicture2.jpg\"\r\n"
773  "Content-Type: image/jpeg\r\n"
774  "\r\n"
775  "FILECONTENT\r\n"
776  "-----------------------------277531038314945--";
777  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
778 
779  TcpSession ssn;
780  HtpState *http_state = NULL;
782 
783  memset(&ssn, 0, sizeof(ssn));
784 
785  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
786  FAIL_IF_NULL(f);
787  f->protoctx = &ssn;
788  f->proto = IPPROTO_TCP;
789  f->alproto = ALPROTO_HTTP;
790 
792 
793  SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1);
794  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
795  STREAM_TOSERVER | STREAM_START, httpbuf1,
796  httplen1);
797  FAIL_IF_NOT(r == 0);
798 
799  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
800  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
801  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
802  FAIL_IF_NOT(r == 0);
803 
804  http_state = f->alstate;
805  FAIL_IF_NULL(http_state);
806 
807  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, http_state, 0);
808  FAIL_IF_NULL(tx);
809  FAIL_IF_NULL(tx->request_method);
810 
811  FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0);
812 
813  FAIL_IF_NULL(http_state->files_ts);
814  FAIL_IF_NULL(http_state->files_ts->head);
815  FAIL_IF_NULL(http_state->files_ts->tail);
816  FAIL_IF(http_state->files_ts->tail->state != FILE_STATE_CLOSED);
817 
818  FAIL_IF(http_state->files_ts->head == http_state->files_ts->tail);
819  FAIL_IF(http_state->files_ts->head->next != http_state->files_ts->tail);
820 
822  (uint8_t *)"filecontent", 11) != 1);
823 
825  (uint8_t *)"FILECONTENT", 11) != 1);
826 
827  AppLayerParserThreadCtxFree(alp_tctx);
829  UTHFreeFlow(f);
830  PASS;
831 }
832 
833 /** \test POST, but not multipart */
834 static int HTPFileParserTest07(void)
835 {
836  uint8_t httpbuf1[] = "POST /filename HTTP/1.1\r\n"
837  "Host: www.server.lan\r\n"
838  "Content-Length: 11\r\n"
839  "\r\n";
840  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
841  uint8_t httpbuf2[] = "FILECONTENT";
842  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
843 
844  TcpSession ssn;
845  HtpState *http_state = NULL;
847 
848  memset(&ssn, 0, sizeof(ssn));
849 
850  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
851  FAIL_IF_NULL(f);
852  f->protoctx = &ssn;
853  f->proto = IPPROTO_TCP;
854  f->alproto = ALPROTO_HTTP;
855 
857 
858  SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1);
859  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
860  STREAM_TOSERVER | STREAM_START, httpbuf1,
861  httplen1);
862  FAIL_IF_NOT(r == 0);
863 
864  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
865  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
866  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
867  FAIL_IF_NOT(r == 0);
868 
869  http_state = f->alstate;
870  FAIL_IF_NULL(http_state);
871 
872  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, http_state, 0);
873  FAIL_IF_NULL(tx);
874  FAIL_IF_NULL(tx->request_method);
875  FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0);
876 
877  FAIL_IF_NULL(http_state->files_ts);
878  FAIL_IF_NULL(http_state->files_ts->tail);
879  FAIL_IF(http_state->files_ts->tail->state != FILE_STATE_CLOSED);
880 
882  (uint8_t *)"FILECONTENT", 11) != 1);
883 
884  AppLayerParserThreadCtxFree(alp_tctx);
886  UTHFreeFlow(f);
887  PASS;
888 }
889 
890 static int HTPFileParserTest08(void)
891 {
892  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
893  "Host: www.server.lan\r\n"
894  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
895  "Content-Length: 215\r\n"
896  "\r\n"
897  "-----------------------------277531038314945\r\n"
898  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
899  "Content-Type: image/jpeg\r\n";
900 
901  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
902  uint8_t httpbuf2[] = "filecontent\r\n\r\n"
903  "-----------------------------277531038314945--";
904  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
905 
906  TcpSession ssn;
908  HtpState *http_state = NULL;
909  memset(&ssn, 0, sizeof(ssn));
910 
911  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
912  FAIL_IF_NULL(f);
913  f->protoctx = &ssn;
914  f->proto = IPPROTO_TCP;
915  f->alproto = ALPROTO_HTTP;
916 
918 
919  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
920  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
921  STREAM_TOSERVER | STREAM_START, httpbuf1,
922  httplen1);
923  FAIL_IF_NOT(r == 0);
924 
925  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
926  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
927  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
928  FAIL_IF_NOT(r == 0);
929 
930  http_state = f->alstate;
931  FAIL_IF_NULL(http_state);
932 
933  void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0);
934  FAIL_IF_NULL(tx);
935 
936  AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP, tx);
937  FAIL_IF_NULL(decoder_events);
938 
939  FAIL_IF(decoder_events->cnt != 2);
940 
941  AppLayerParserThreadCtxFree(alp_tctx);
943  UTHFreeFlow(f);
944  PASS;
945 }
946 
947 /** \test invalid header: Somereallylongheaderstr: has no value */
948 static int HTPFileParserTest09(void)
949 {
950  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
951  "Host: www.server.lan\r\n"
952  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
953  "Content-Length: 337\r\n"
954  "\r\n";
955  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
956 
957  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
958  "Content-Disposition: form-data; name=\"email\"\r\n"
959  "\r\n"
960  "someaddress@somedomain.lan\r\n";
961  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
962 
963  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
964  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
965  "Somereallylongheaderstr:\r\n"
966  "\r\n";
967  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
968 
969  uint8_t httpbuf4[] = "filecontent\r\n"
970  "-----------------------------277531038314945--";
971  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
972 
973  TcpSession ssn;
974  HtpState *http_state = NULL;
976 
977  memset(&ssn, 0, sizeof(ssn));
978 
979  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
980  FAIL_IF_NULL(f);
981  f->protoctx = &ssn;
982  f->proto = IPPROTO_TCP;
983  f->alproto = ALPROTO_HTTP;
984 
986 
987  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
988  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
989  STREAM_TOSERVER | STREAM_START, httpbuf1,
990  httplen1);
991  FAIL_IF_NOT(r == 0);
992 
993  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
994  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
995  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
996  FAIL_IF_NOT(r == 0);
997 
998  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
999  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1000  STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
1001  FAIL_IF_NOT(r == 0);
1002 
1003  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
1004  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1005  STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1006  FAIL_IF_NOT(r == 0);
1007 
1008  http_state = f->alstate;
1009  FAIL_IF_NULL(http_state);
1010 
1011  void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0);
1012  FAIL_IF_NULL(tx);
1013 
1014  AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP, tx);
1015  FAIL_IF_NULL(decoder_events);
1016 
1017  FAIL_IF(decoder_events->cnt != 1);
1018 
1019  AppLayerParserThreadCtxFree(alp_tctx);
1021  UTHFreeFlow(f);
1022  PASS;
1023 }
1024 
1025 /** \test empty entries */
1026 static int HTPFileParserTest10(void)
1027 {
1028  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
1029  "Host: www.server.lan\r\n"
1030  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
1031  "Content-Length: 337\r\n"
1032  "\r\n";
1033  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1034 
1035  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
1036  "\r\n";
1037  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1038 
1039  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
1040  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
1041  "Somereallylongheaderstr: with a good value\r\n"
1042  "\r\n";
1043  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1044 
1045  uint8_t httpbuf4[] = "filecontent\r\n"
1046  "-----------------------------277531038314945--";
1047  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1048 
1049  TcpSession ssn;
1050  HtpState *http_state = NULL;
1052 
1053  memset(&ssn, 0, sizeof(ssn));
1054 
1055  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1056  FAIL_IF_NULL(f);
1057  f->protoctx = &ssn;
1058  f->proto = IPPROTO_TCP;
1059  f->alproto = ALPROTO_HTTP;
1060 
1062 
1063  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
1064  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1065  STREAM_TOSERVER | STREAM_START, httpbuf1,
1066  httplen1);
1067  FAIL_IF_NOT(r == 0);
1068 
1069  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
1070  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1071  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
1072  FAIL_IF_NOT(r == 0);
1073 
1074  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
1075  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1076  STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
1077  FAIL_IF_NOT(r == 0);
1078 
1079  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
1080  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1081  STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1082  FAIL_IF_NOT(r == 0);
1083 
1084  http_state = f->alstate;
1085  FAIL_IF_NULL(http_state);
1086 
1087  void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0);
1088  FAIL_IF_NULL(tx);
1089  AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP, tx);
1090  FAIL_IF_NOT_NULL(decoder_events);
1091 
1092  AppLayerParserThreadCtxFree(alp_tctx);
1094  UTHFreeFlow(f);
1095  PASS;
1096 }
1097 
1098 /** \test filedata cut in two pieces */
1099 static int HTPFileParserTest11(void)
1100 {
1101  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
1102  "Host: www.server.lan\r\n"
1103  "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1104  "Content-Length: 1102\r\n"
1105  "\r\n";
1106  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1107 
1108  uint8_t httpbuf2[] = "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n";
1109  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1110 
1111  uint8_t httpbuf3[] = "Content-Disposition: form-data; name=\"PROGRESS_URL\"\r\n"
1112  "\r\n"
1113  "http://somserver.com/progress.php?UPLOAD_IDENTIFIER=XXXXXXXXX.XXXXXXXXXX.XXXXXXXX.XX.X\r\n"
1114  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1115  "Content-Disposition: form-data; name=\"DESTINATION_DIR\"\r\n"
1116  "\r\n"
1117  "10\r\n"
1118  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1119  "Content-Disposition: form-data; name=\"js_enabled\"\r\n"
1120  "\r\n"
1121  "1"
1122  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1123  "Content-Disposition: form-data; name=\"signature\"\r\n"
1124  "\r\n"
1125  "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n"
1126  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1127  "Content-Disposition: form-data; name=\"upload_files\"\r\n"
1128  "\r\n"
1129  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1130  "Content-Disposition: form-data; name=\"terms\"\r\n"
1131  "\r\n"
1132  "1"
1133  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1134  "Content-Disposition: form-data; name=\"file[]\"\r\n"
1135  "\r\n"
1136  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1137  "Content-Disposition: form-data; name=\"description[]\"\r\n"
1138  "\r\n"
1139  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1140  "Content-Disposition: form-data; name=\"upload_file[]\"; filename=\"filename.doc\"\r\n"
1141  "Content-Type: application/msword\r\n"
1142  "\r\n"
1143  "FILE";
1144  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1145 
1146  uint8_t httpbuf4[] = "CONTENT\r\n"
1147  "------WebKitFormBoundaryBRDbP74mBhBxsIdo--";
1148  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1149 
1150  TcpSession ssn;
1151  HtpState *http_state = NULL;
1153 
1154  memset(&ssn, 0, sizeof(ssn));
1155 
1156  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1157  FAIL_IF_NULL(f);
1158  f->protoctx = &ssn;
1159  f->proto = IPPROTO_TCP;
1160  f->alproto = ALPROTO_HTTP;
1161 
1163 
1164  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
1165  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1166  STREAM_TOSERVER | STREAM_START, httpbuf1,
1167  httplen1);
1168  FAIL_IF_NOT(r == 0);
1169 
1170  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
1171  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER,
1172  httpbuf2, httplen2);
1173  FAIL_IF_NOT(r == 0);
1174 
1175  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
1176  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER,
1177  httpbuf3, httplen3);
1178  FAIL_IF_NOT(r == 0);
1179 
1180  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
1181  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1182  STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1183  FAIL_IF_NOT(r == 0);
1184 
1185  http_state = f->alstate;
1186  FAIL_IF_NULL(http_state);
1187 
1188  void *txtmp = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0);
1189  FAIL_IF_NULL(txtmp);
1190 
1191  AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP, txtmp);
1192  FAIL_IF_NOT_NULL(decoder_events);
1193 
1194  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, http_state, 0);
1195  FAIL_IF_NULL(tx);
1196  FAIL_IF_NULL(tx->request_method);
1197 
1198  FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0);
1199 
1200  FAIL_IF_NULL(http_state->files_ts);
1201  FAIL_IF_NULL(http_state->files_ts->tail);
1202  FAIL_IF(http_state->files_ts->tail->state != FILE_STATE_CLOSED);
1203 
1205  (uint8_t *)"FILECONTENT", 11) != 1);
1206 
1207  AppLayerParserThreadCtxFree(alp_tctx);
1209  UTHFreeFlow(f);
1210  PASS;
1211 }
1212 
1213 void AppLayerHtpFileRegisterTests (void);
1214 #include "tests/app-layer-htp-file.c"
1215 #endif /* UNITTESTS */
1216 
1218 {
1219 #ifdef UNITTESTS
1220  UtRegisterTest("HTPFileParserTest01", HTPFileParserTest01);
1221  UtRegisterTest("HTPFileParserTest02", HTPFileParserTest02);
1222  UtRegisterTest("HTPFileParserTest03", HTPFileParserTest03);
1223  UtRegisterTest("HTPFileParserTest04", HTPFileParserTest04);
1224  UtRegisterTest("HTPFileParserTest05", HTPFileParserTest05);
1225  UtRegisterTest("HTPFileParserTest06", HTPFileParserTest06);
1226  UtRegisterTest("HTPFileParserTest07", HTPFileParserTest07);
1227  UtRegisterTest("HTPFileParserTest08", HTPFileParserTest08);
1228  UtRegisterTest("HTPFileParserTest09", HTPFileParserTest09);
1229  UtRegisterTest("HTPFileParserTest10", HTPFileParserTest10);
1230  UtRegisterTest("HTPFileParserTest11", HTPFileParserTest11);
1231 #endif /* UNITTESTS */
1232 }
uint16_t flags
void AppLayerHtpFileRegisterTests(void)
this function registers unit tests for AppLayerHtpFile
int StreamingBufferCompareRawData(const StreamingBuffer *sb, const uint8_t *rawdata, uint32_t rawdata_len)
#define SCLogDebug(...)
Definition: util-debug.h:335
uint16_t flags
uint8_t proto
Definition: flow.h:344
FileContainer * FileContainerAlloc(void)
allocate a FileContainer
Definition: util-file.c:411
HTPCfgDir response
#define PASS
Pass the test.
const struct HTPCfgRec_ * cfg
uint64_t FileDataSize(const File *file)
get the size of the file data
Definition: util-file.c:279
int HTPFileClose(HtpState *s, const uint8_t *data, uint32_t data_len, uint8_t flags, uint8_t direction)
Close the file in the flow.
#define FAIL_IF(expr)
Fail a test if expression evaluates to false.
Definition: util-unittest.h:71
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
Destroys the app layer parser thread context obtained using AppLayerParserThreadCtxAlloc().
void StreamTcpFreeConfig(char quiet)
Definition: stream-tcp.c:668
#define HTP_FLAG_STORE_FILES_TX_TC
Definition: app-layer-htp.h:74
#define HTP_FLAG_STORE_FILES_TX_TS
Definition: app-layer-htp.h:73
AppLayerDecoderEvents * AppLayerParserGetEventsByTx(uint8_t ipproto, AppProto alproto, void *tx)
#define FILE_STORE
Definition: util-file.h:46
struct File_ * next
Definition: util-file.h:77
#define TRUE
void * protoctx
Definition: flow.h:400
StreamingBuffer * sb
Definition: util-file.h:67
void * alstate
Definition: flow.h:438
Flow * UTHBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp)
Data structure to store app layer decoder events.
void * AppLayerParserGetTx(uint8_t ipproto, AppProto alproto, void *alstate, uint64_t tx_id)
HTPCfgDir request
Data structures and function prototypes for keeping state for the detection engine.
uint32_t file_track_id
#define STREAM_EOF
Definition: stream.h:30
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
#define SCEnter(...)
Definition: util-debug.h:337
void StreamTcpInitConfig(char)
To initialize the stream global configuration data.
Definition: stream-tcp.c:364
int FileSetRange(FileContainer *ffc, uint64_t start, uint64_t end)
Sets the offset range for a file.
Definition: util-file.c:789
#define STREAM_TOCLIENT
Definition: stream.h:32
AppLayerParserThreadCtx * AppLayerParserThreadCtxAlloc(void)
Gets a new app layer protocol&#39;s parser thread context.
#define HTP_FLAG_STORE_FILES_TC
Definition: app-layer-htp.h:72
#define FAIL_IF_NOT_NULL(expr)
Fail a test if expression evaluates to non-NULL.
Definition: util-unittest.h:96
#define SCReturnInt(x)
Definition: util-debug.h:341
int HTPParseContentRange(bstr *rawvalue, HtpContentRange *range)
int HTPFileOpen(HtpState *s, 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.
int HTPFileStoreChunk(HtpState *s, const uint8_t *data, uint32_t data_len, uint8_t direction)
Store a chunk of data in the flow.
FileContainer * files_ts
StreamingBufferConfig sbcfg
FileContainer * files_tc
#define FLOWFILE_NO_STORE_TS
Definition: flow.h:115
int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, uint8_t flags, const uint8_t *input, uint32_t input_len)
#define STREAM_START
Definition: stream.h:29
#define STREAM_TOSERVER
Definition: stream.h:31
FileState state
Definition: util-file.h:66
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:906
int FileCloseFile(FileContainer *ffc, const uint8_t *data, uint32_t data_len, uint16_t flags)
Close a File.
Definition: util-file.c:1000
int FileSetTx(File *ff, uint64_t txid)
Set the TX id for a file.
Definition: util-file.c:554
uint16_t FileFlowToFlags(const Flow *flow, uint8_t direction)
Definition: util-file.c:219
uint64_t store_tx_id
void HTPFileParserRegisterTests(void)
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
uint8_t len
uint16_t file_flags
Definition: flow.h:381
AppProto alproto
application level protocol
Definition: flow.h:409
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:695
#define HTP_FLAG_STORE_FILES_TS
Definition: app-layer-htp.h:71
#define FILE_NOSTORE
Definition: util-file.h:45
#define FLOWFILE_NO_STORE_TC
Definition: flow.h:116
Flow data structure.
Definition: flow.h:325
int HTPFileSetRange(HtpState *s, bstr *rawvalue)
Sets range for a file.
#define FAIL_IF_NOT(expr)
Fail a test if expression to true.
Definition: util-unittest.h:82
void UTHFreeFlow(Flow *flow)