GNU libmicrohttpd 0.9.71
postprocessor.c
Go to the documentation of this file.
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007-2013 Daniel Pittman and Christian Grothoff
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19
26#include "internal.h"
27#include "mhd_str.h"
28#include "mhd_compat.h"
29
35#define XBUF_SIZE 512
36
41{
42 /* general states */
47
48 /* url encoding-states */
52
53 /* post encoding-states */
58
59 /* nested post-encoding states */
65
66};
67
68
70{
75
81
87
93
97 RN_Dash2 = 4
98};
99
100
107{
114
115
120struct MHD_PostProcessor
121{
122
127 struct MHD_Connection *connection;
128
133
137 void *cls;
138
142 const char *encoding;
143
147 const char *boundary;
148
152 char *nested_boundary;
153
157 char *content_name;
158
162 char *content_type;
163
167 char *content_filename;
168
172 char *content_transfer_encoding;
173
177 char xbuf[2];
178
182 size_t buffer_size;
183
187 size_t buffer_pos;
188
192 size_t xbuf_pos;
193
197 uint64_t value_offset;
198
202 size_t blen;
203
207 size_t nlen;
208
217 bool must_ikvi;
218
223 bool must_unescape_key;
224
228 enum PP_State state;
229
236 enum RN_State skip_rn;
237
242 enum PP_State dash_state;
243
248 enum NE_State have;
249
250};
251
252
278struct MHD_PostProcessor *
280 size_t buffer_size,
282 void *iter_cls)
283{
284 struct MHD_PostProcessor *ret;
285 const char *encoding;
286 const char *boundary;
287 size_t blen;
288
289 if ( (buffer_size < 256) ||
290 (NULL == connection) ||
291 (NULL == iter))
293 __FILE__,
294 __LINE__,
295 NULL);
296 if (MHD_NO == MHD_lookup_connection_value_n (connection,
301 &encoding,
302 NULL))
303 return NULL;
304 boundary = NULL;
306 encoding,
309 {
311 encoding,
314 return NULL;
315 boundary =
317 /* Q: should this be "strcasestr"? */
318 boundary = strstr (boundary, "boundary=");
319 if (NULL == boundary)
320 return NULL; /* failed to determine boundary */
321 boundary += MHD_STATICSTR_LEN_ ("boundary=");
322 blen = strlen (boundary);
323 if ( (blen == 0) ||
324 (blen * 2 + 2 > buffer_size) )
325 return NULL; /* (will be) out of memory or invalid boundary */
326 if ( (boundary[0] == '"') &&
327 (boundary[blen - 1] == '"') )
328 {
329 /* remove enclosing quotes */
330 ++boundary;
331 blen -= 2;
332 }
333 }
334 else
335 blen = 0;
336 buffer_size += 4; /* round up to get nice block sizes despite boundary search */
337
338 /* add +1 to ensure we ALWAYS have a zero-termination at the end */
339 if (NULL == (ret = MHD_calloc_ (1, sizeof (struct MHD_PostProcessor)
340 + buffer_size + 1)))
341 return NULL;
342 ret->connection = connection;
343 ret->ikvi = iter;
344 ret->cls = iter_cls;
345 ret->encoding = encoding;
346 ret->buffer_size = buffer_size;
347 ret->state = PP_Init;
348 ret->blen = blen;
349 ret->boundary = boundary;
350 ret->skip_rn = RN_Inactive;
351 return ret;
352}
353
354
376static void
377process_value (struct MHD_PostProcessor *pp,
378 const char *value_start,
379 const char *value_end,
380 const char *last_escape)
381{
382 char xbuf[XBUF_SIZE + 1];
383 size_t xoff;
384
385 mhd_assert (pp->xbuf_pos < sizeof (xbuf));
386 memcpy (xbuf,
387 pp->xbuf,
388 pp->xbuf_pos);
389 xoff = pp->xbuf_pos;
390 pp->xbuf_pos = 0;
391 if (NULL != last_escape)
392 {
393 if (((size_t) (value_end - last_escape)) < sizeof (pp->xbuf))
394 {
395 pp->xbuf_pos = value_end - last_escape;
396 memcpy (pp->xbuf,
397 last_escape,
398 value_end - last_escape);
399 value_end = last_escape;
400 }
401 }
402 while ( (value_start != value_end) ||
403 (pp->must_ikvi) ||
404 (xoff > 0) )
405 {
406 size_t delta = value_end - value_start;
407
408 if (delta > XBUF_SIZE - xoff)
409 delta = XBUF_SIZE - xoff;
410 /* move input into processing buffer */
411 memcpy (&xbuf[xoff],
412 value_start,
413 delta);
414 /* find if escape sequence is at the end of the processing buffer;
415 if so, exclude those from processing (reduce delta to point at
416 end of processed region) */
417 if (delta >= XBUF_SIZE - 2)
418 {
419 if ((xoff + delta > 0) &&
420 ('%' == xbuf[xoff + delta - 1]))
421 delta--;
422 else if ((xoff + delta > 1) &&
423 ('%' == xbuf[xoff + delta - 2]))
424 delta -= 2;
425 }
426 xoff += delta;
427 value_start += delta;
428 mhd_assert (xoff < sizeof (xbuf));
429 /* unescape */
430 xbuf[xoff] = '\0'; /* 0-terminate in preparation */
431 MHD_unescape_plus (xbuf);
432 xoff = MHD_http_unescape (xbuf);
433 /* finally: call application! */
434 pp->must_ikvi = false;
435 if (MHD_NO == pp->ikvi (pp->cls,
437 (const char *) &pp[1], /* key */
438 NULL,
439 NULL,
440 NULL,
441 xbuf,
442 pp->value_offset,
443 xoff))
444 {
445 pp->state = PP_Error;
446 return;
447 }
448 pp->value_offset += xoff;
449 xoff = 0;
450 }
451}
452
453
462static int
463post_process_urlencoded (struct MHD_PostProcessor *pp,
464 const char *post_data,
465 size_t post_data_len)
466{
467 char *kbuf = (char *) &pp[1];
468 size_t poff;
469 const char *start_key = NULL;
470 const char *end_key = NULL;
471 const char *start_value = NULL;
472 const char *end_value = NULL;
473 const char *last_escape = NULL;
474
475 poff = 0;
476 while ( ( (poff < post_data_len) ||
477 (pp->state == PP_Callback) ) &&
478 (pp->state != PP_Error) )
479 {
480 switch (pp->state)
481 {
482 case PP_Error:
483 /* clearly impossible as per while loop invariant */
484 abort ();
485 break;
486 case PP_Init:
487 /* key phase */
488 if (NULL == start_key)
489 start_key = &post_data[poff];
490 pp->must_ikvi = true;
491 switch (post_data[poff])
492 {
493 case '=':
494 /* Case: 'key=' */
495 end_key = &post_data[poff];
496 poff++;
497 pp->state = PP_ProcessValue;
498 break;
499 case '&':
500 /* Case: 'key&' */
501 end_key = &post_data[poff];
502 mhd_assert (NULL == start_value);
503 mhd_assert (NULL == end_value);
504 poff++;
505 pp->state = PP_Callback;
506 break;
507 case '\n':
508 case '\r':
509 /* Case: 'key\n' or 'key\r' */
510 end_key = &post_data[poff];
511 poff++;
512 pp->state = PP_Done;
513 break;
514 default:
515 /* normal character, advance! */
516 poff++;
517 continue;
518 }
519 break; /* end PP_Init */
520 case PP_ProcessValue:
521 if (NULL == start_value)
522 start_value = &post_data[poff];
523 switch (post_data[poff])
524 {
525 case '=':
526 /* case 'key==' */
527 pp->state = PP_Error;
528 continue;
529 case '&':
530 /* case 'value&' */
531 end_value = &post_data[poff];
532 poff++;
533 if (pp->must_ikvi ||
534 (start_value != end_value) )
535 {
536 pp->state = PP_Callback;
537 }
538 else
539 {
540 pp->buffer_pos = 0;
541 pp->value_offset = 0;
542 pp->state = PP_Init;
543 start_value = NULL;
544 }
545 continue;
546 case '\n':
547 case '\r':
548 /* Case: 'value\n' or 'value\r' */
549 end_value = &post_data[poff];
550 poff++;
551 if (pp->must_ikvi)
552 pp->state = PP_Callback;
553 else
554 pp->state = PP_Done;
555 break;
556 case '%':
557 last_escape = &post_data[poff];
558 poff++;
559 break;
560 case '0':
561 case '1':
562 case '2':
563 case '3':
564 case '4':
565 case '5':
566 case '6':
567 case '7':
568 case '8':
569 case '9':
570 /* character, may be part of escaping */
571 poff++;
572 continue;
573 default:
574 /* normal character, no more escaping! */
575 last_escape = NULL;
576 poff++;
577 continue;
578 }
579 break; /* end PP_ProcessValue */
580 case PP_Done:
581 switch (post_data[poff])
582 {
583 case '\n':
584 case '\r':
585 poff++;
586 continue;
587 }
588 /* unexpected data at the end, fail! */
589 pp->state = PP_Error;
590 break;
591 case PP_Callback:
592 if ( (pp->buffer_pos + (end_key - start_key) >=
593 pp->buffer_size) ||
594 (pp->buffer_pos + (end_key - start_key) <
595 pp->buffer_pos) )
596 {
597 /* key too long, cannot parse! */
598 pp->state = PP_Error;
599 continue;
600 }
601 /* compute key, if we have not already */
602 if (NULL != start_key)
603 {
604 memcpy (&kbuf[pp->buffer_pos],
605 start_key,
606 end_key - start_key);
607 pp->buffer_pos += end_key - start_key;
608 start_key = NULL;
609 end_key = NULL;
610 pp->must_unescape_key = true;
611 }
612 if (pp->must_unescape_key)
613 {
614 kbuf[pp->buffer_pos] = '\0'; /* 0-terminate key */
615 MHD_unescape_plus (kbuf);
616 MHD_http_unescape (kbuf);
617 pp->must_unescape_key = false;
618 }
619 process_value (pp,
620 start_value,
621 end_value,
622 NULL);
623 pp->value_offset = 0;
624 start_value = NULL;
625 end_value = NULL;
626 pp->buffer_pos = 0;
627 pp->state = PP_Init;
628 break;
629 default:
631 __FILE__,
632 __LINE__,
633 NULL); /* should never happen! */
634 }
635 }
636
637 /* save remaining data for next iteration */
638 if (NULL != start_key)
639 {
640 if (NULL == end_key)
641 end_key = &post_data[poff];
642 if (pp->buffer_pos + (end_key - start_key) >= pp->buffer_size)
643 {
644 pp->state = PP_Error;
645 return MHD_NO;
646 }
647 memcpy (&kbuf[pp->buffer_pos],
648 start_key,
649 end_key - start_key);
650 pp->buffer_pos += end_key - start_key;
651 pp->must_unescape_key = true;
652 start_key = NULL;
653 end_key = NULL;
654 }
655 if ( (NULL != start_value) &&
656 (PP_ProcessValue == pp->state) )
657 {
658 /* compute key, if we have not already */
659 if (pp->must_unescape_key)
660 {
661 kbuf[pp->buffer_pos] = '\0'; /* 0-terminate key */
662 MHD_unescape_plus (kbuf);
663 MHD_http_unescape (kbuf);
664 pp->must_unescape_key = false;
665 }
666 if (NULL == end_value)
667 end_value = &post_data[poff];
668 process_value (pp,
669 start_value,
670 end_value,
671 last_escape);
672 pp->must_ikvi = false;
673 }
674 if (PP_Error == pp->state)
675 {
676 /* State in error, returning failure */
677 return MHD_NO;
678 }
679 return MHD_YES;
680}
681
682
693static int
694try_match_header (const char *prefix,
695 size_t prefix_len,
696 char *line,
697 char **suffix)
698{
699 if (NULL != *suffix)
700 return MHD_NO;
701 while (0 != *line)
702 {
703 if (MHD_str_equal_caseless_n_ (prefix,
704 line,
705 prefix_len))
706 {
707 *suffix = strdup (&line[prefix_len]);
708 return MHD_YES;
709 }
710 ++line;
711 }
712 return MHD_NO;
713}
714
715
729static int
730find_boundary (struct MHD_PostProcessor *pp,
731 const char *boundary,
732 size_t blen,
733 size_t *ioffptr,
734 enum PP_State next_state,
735 enum PP_State next_dash_state)
736{
737 char *buf = (char *) &pp[1];
738 const char *dash;
739
740 if (pp->buffer_pos < 2 + blen)
741 {
742 if (pp->buffer_pos == pp->buffer_size)
743 pp->state = PP_Error; /* out of memory */
744 /* ++(*ioffptr); */
745 return MHD_NO; /* not enough data */
746 }
747 if ( (0 != memcmp ("--",
748 buf,
749 2)) ||
750 (0 != memcmp (&buf[2],
751 boundary,
752 blen)))
753 {
754 if (pp->state != PP_Init)
755 {
756 /* garbage not allowed */
757 pp->state = PP_Error;
758 }
759 else
760 {
761 /* skip over garbage (RFC 2046, 5.1.1) */
762 dash = memchr (buf,
763 '-',
764 pp->buffer_pos);
765 if (NULL == dash)
766 (*ioffptr) += pp->buffer_pos; /* skip entire buffer */
767 else if (dash == buf)
768 (*ioffptr)++; /* at least skip one byte */
769 else
770 (*ioffptr) += dash - buf; /* skip to first possible boundary */
771 }
772 return MHD_NO; /* expected boundary */
773 }
774 /* remove boundary from buffer */
775 (*ioffptr) += 2 + blen;
776 /* next: start with headers */
777 pp->skip_rn = RN_Dash;
778 pp->state = next_state;
779 pp->dash_state = next_dash_state;
780 return MHD_YES;
781}
782
783
790static void
791try_get_value (const char *buf,
792 const char *key,
793 char **destination)
794{
795 const char *spos;
796 const char *bpos;
797 const char *endv;
798 size_t klen;
799 size_t vlen;
800
801 if (NULL != *destination)
802 return;
803 bpos = buf;
804 klen = strlen (key);
805 while (NULL != (spos = strstr (bpos, key)))
806 {
807 if ( (spos[klen] != '=') ||
808 ( (spos != buf) &&
809 (spos[-1] != ' ') ) )
810 {
811 /* no match */
812 bpos = spos + 1;
813 continue;
814 }
815 if (spos[klen + 1] != '"')
816 return; /* not quoted */
817 if (NULL == (endv = strchr (&spos[klen + 2],
818 '\"')))
819 return; /* no end-quote */
820 vlen = endv - spos - klen - 1;
821 *destination = malloc (vlen);
822 if (NULL == *destination)
823 return; /* out of memory */
824 (*destination)[vlen - 1] = '\0';
825 memcpy (*destination,
826 &spos[klen + 2],
827 vlen - 1);
828 return; /* success */
829 }
830}
831
832
848static int
849process_multipart_headers (struct MHD_PostProcessor *pp,
850 size_t *ioffptr,
851 enum PP_State next_state)
852{
853 char *buf = (char *) &pp[1];
854 size_t newline;
855
856 newline = 0;
857 while ( (newline < pp->buffer_pos) &&
858 (buf[newline] != '\r') &&
859 (buf[newline] != '\n') )
860 newline++;
861 if (newline == pp->buffer_size)
862 {
863 pp->state = PP_Error;
864 return MHD_NO; /* out of memory */
865 }
866 if (newline == pp->buffer_pos)
867 return MHD_NO; /* will need more data */
868 if (0 == newline)
869 {
870 /* empty line - end of headers */
871 pp->skip_rn = RN_Full;
872 pp->state = next_state;
873 return MHD_YES;
874 }
875 /* got an actual header */
876 if (buf[newline] == '\r')
877 pp->skip_rn = RN_OptN;
878 buf[newline] = '\0';
879 if (MHD_str_equal_caseless_n_ ("Content-disposition: ",
880 buf,
881 MHD_STATICSTR_LEN_ ("Content-disposition: ")))
882 {
883 try_get_value (&buf[MHD_STATICSTR_LEN_ ("Content-disposition: ")],
884 "name",
885 &pp->content_name);
886 try_get_value (&buf[MHD_STATICSTR_LEN_ ("Content-disposition: ")],
887 "filename",
888 &pp->content_filename);
889 }
890 else
891 {
892 try_match_header ("Content-type: ",
893 MHD_STATICSTR_LEN_ ("Content-type: "),
894 buf,
895 &pp->content_type);
896 try_match_header ("Content-Transfer-Encoding: ",
897 MHD_STATICSTR_LEN_ ("Content-Transfer-Encoding: "),
898 buf,
899 &pp->content_transfer_encoding);
900 }
901 (*ioffptr) += newline + 1;
902 return MHD_YES;
903}
904
905
922static int
923process_value_to_boundary (struct MHD_PostProcessor *pp,
924 size_t *ioffptr,
925 const char *boundary,
926 size_t blen,
927 enum PP_State next_state,
928 enum PP_State next_dash_state)
929{
930 char *buf = (char *) &pp[1];
931 size_t newline;
932 const char *r;
933
934 /* all data in buf until the boundary
935 (\r\n--+boundary) is part of the value */
936 newline = 0;
937 while (1)
938 {
939 while (newline + 4 < pp->buffer_pos)
940 {
941 r = memchr (&buf[newline],
942 '\r',
943 pp->buffer_pos - newline - 4);
944 if (NULL == r)
945 {
946 newline = pp->buffer_pos - 4;
947 break;
948 }
949 newline = r - buf;
950 if (0 == memcmp ("\r\n--",
951 &buf[newline],
952 4))
953 break;
954 newline++;
955 }
956 if (newline + blen + 4 <= pp->buffer_pos)
957 {
958 /* can check boundary */
959 if (0 != memcmp (&buf[newline + 4],
960 boundary,
961 blen))
962 {
963 /* no boundary, "\r\n--" is part of content, skip */
964 newline += 4;
965 continue;
966 }
967 else
968 {
969 /* boundary found, process until newline then
970 skip boundary and go back to init */
971 pp->skip_rn = RN_Dash;
972 pp->state = next_state;
973 pp->dash_state = next_dash_state;
974 (*ioffptr) += blen + 4; /* skip boundary as well */
975 buf[newline] = '\0';
976 break;
977 }
978 }
979 else
980 {
981 /* cannot check for boundary, process content that
982 we have and check again later; except, if we have
983 no content, abort (out of memory) */
984 if ( (0 == newline) &&
985 (pp->buffer_pos == pp->buffer_size) )
986 {
987 pp->state = PP_Error;
988 return MHD_NO;
989 }
990 break;
991 }
992 }
993 /* newline is either at beginning of boundary or
994 at least at the last character that we are sure
995 is not part of the boundary */
996 if ( ( (pp->must_ikvi) ||
997 (0 != newline) ) &&
998 (MHD_NO == pp->ikvi (pp->cls,
1000 pp->content_name,
1001 pp->content_filename,
1002 pp->content_type,
1003 pp->content_transfer_encoding,
1004 buf,
1005 pp->value_offset,
1006 newline)) )
1007 {
1008 pp->state = PP_Error;
1009 return MHD_NO;
1010 }
1011 pp->must_ikvi = false;
1012 pp->value_offset += newline;
1013 (*ioffptr) += newline;
1014 return MHD_YES;
1015}
1016
1017
1022static void
1023free_unmarked (struct MHD_PostProcessor *pp)
1024{
1025 if ( (NULL != pp->content_name) &&
1026 (0 == (pp->have & NE_content_name)) )
1027 {
1028 free (pp->content_name);
1029 pp->content_name = NULL;
1030 }
1031 if ( (NULL != pp->content_type) &&
1032 (0 == (pp->have & NE_content_type)) )
1033 {
1034 free (pp->content_type);
1035 pp->content_type = NULL;
1036 }
1037 if ( (NULL != pp->content_filename) &&
1038 (0 == (pp->have & NE_content_filename)) )
1039 {
1040 free (pp->content_filename);
1041 pp->content_filename = NULL;
1042 }
1043 if ( (NULL != pp->content_transfer_encoding) &&
1044 (0 == (pp->have & NE_content_transfer_encoding)) )
1045 {
1046 free (pp->content_transfer_encoding);
1047 pp->content_transfer_encoding = NULL;
1048 }
1049}
1050
1051
1060static int
1061post_process_multipart (struct MHD_PostProcessor *pp,
1062 const char *post_data,
1063 size_t post_data_len)
1064{
1065 char *buf;
1066 size_t max;
1067 size_t ioff;
1068 size_t poff;
1069 int state_changed;
1070
1071 buf = (char *) &pp[1];
1072 ioff = 0;
1073 poff = 0;
1074 state_changed = 1;
1075 while ( (poff < post_data_len) ||
1076 ( (pp->buffer_pos > 0) &&
1077 (0 != state_changed) ) )
1078 {
1079 /* first, move as much input data
1080 as possible to our internal buffer */
1081 max = pp->buffer_size - pp->buffer_pos;
1082 if (max > post_data_len - poff)
1083 max = post_data_len - poff;
1084 memcpy (&buf[pp->buffer_pos],
1085 &post_data[poff],
1086 max);
1087 poff += max;
1088 pp->buffer_pos += max;
1089 if ( (0 == max) &&
1090 (0 == state_changed) &&
1091 (poff < post_data_len) )
1092 {
1093 pp->state = PP_Error;
1094 return MHD_NO; /* out of memory */
1095 }
1096 state_changed = 0;
1097
1098 /* first state machine for '\r'-'\n' and '--' handling */
1099 switch (pp->skip_rn)
1100 {
1101 case RN_Inactive:
1102 break;
1103 case RN_OptN:
1104 if (buf[0] == '\n')
1105 {
1106 ioff++;
1107 pp->skip_rn = RN_Inactive;
1108 goto AGAIN;
1109 }
1110 /* fall-through! */
1111 case RN_Dash:
1112 if (buf[0] == '-')
1113 {
1114 ioff++;
1115 pp->skip_rn = RN_Dash2;
1116 goto AGAIN;
1117 }
1118 pp->skip_rn = RN_Full;
1119 /* fall-through! */
1120 case RN_Full:
1121 if (buf[0] == '\r')
1122 {
1123 if ( (pp->buffer_pos > 1) &&
1124 ('\n' == buf[1]) )
1125 {
1126 pp->skip_rn = RN_Inactive;
1127 ioff += 2;
1128 }
1129 else
1130 {
1131 pp->skip_rn = RN_OptN;
1132 ioff++;
1133 }
1134 goto AGAIN;
1135 }
1136 if (buf[0] == '\n')
1137 {
1138 ioff++;
1139 pp->skip_rn = RN_Inactive;
1140 goto AGAIN;
1141 }
1142 pp->skip_rn = RN_Inactive;
1143 pp->state = PP_Error;
1144 return MHD_NO; /* no '\r\n' */
1145 case RN_Dash2:
1146 if (buf[0] == '-')
1147 {
1148 ioff++;
1149 pp->skip_rn = RN_Full;
1150 pp->state = pp->dash_state;
1151 goto AGAIN;
1152 }
1153 pp->state = PP_Error;
1154 break;
1155 }
1156
1157 /* main state engine */
1158 switch (pp->state)
1159 {
1160 case PP_Error:
1161 return MHD_NO;
1162 case PP_Done:
1163 /* did not expect to receive more data */
1164 pp->state = PP_Error;
1165 return MHD_NO;
1166 case PP_Init:(void) find_boundary (pp,
1178 pp->boundary,
1179 pp->blen,
1180 &ioff,
1182 PP_Done);
1183 break;
1184 case PP_NextBoundary:
1185 if (MHD_NO == find_boundary (pp,
1186 pp->boundary,
1187 pp->blen,
1188 &ioff,
1190 PP_Done))
1191 {
1192 if (pp->state == PP_Error)
1193 return MHD_NO;
1194 goto END;
1195 }
1196 break;
1198 pp->must_ikvi = true;
1199 if (MHD_NO ==
1201 &ioff,
1203 {
1204 if (pp->state == PP_Error)
1205 return MHD_NO;
1206 else
1207 goto END;
1208 }
1209 state_changed = 1;
1210 break;
1212 if ( (NULL != pp->content_type) &&
1213 (MHD_str_equal_caseless_n_ (pp->content_type,
1214 "multipart/mixed",
1215 MHD_STATICSTR_LEN_ ("multipart/mixed"))))
1216 {
1217 pp->nested_boundary = strstr (pp->content_type,
1218 "boundary=");
1219 if (NULL == pp->nested_boundary)
1220 {
1221 pp->state = PP_Error;
1222 return MHD_NO;
1223 }
1224 pp->nested_boundary =
1225 strdup (&pp->nested_boundary[MHD_STATICSTR_LEN_ ("boundary=")]);
1226 if (NULL == pp->nested_boundary)
1227 {
1228 /* out of memory */
1229 pp->state = PP_Error;
1230 return MHD_NO;
1231 }
1232 /* free old content type, we will need that field
1233 for the content type of the nested elements */
1234 free (pp->content_type);
1235 pp->content_type = NULL;
1236 pp->nlen = strlen (pp->nested_boundary);
1237 pp->state = PP_Nested_Init;
1238 state_changed = 1;
1239 break;
1240 }
1241 pp->state = PP_ProcessValueToBoundary;
1242 pp->value_offset = 0;
1243 state_changed = 1;
1244 break;
1247 &ioff,
1248 pp->boundary,
1249 pp->blen,
1251 PP_Done))
1252 {
1253 if (pp->state == PP_Error)
1254 return MHD_NO;
1255 break;
1256 }
1257 break;
1258 case PP_PerformCleanup:
1259 /* clean up state of one multipart form-data element! */
1260 pp->have = NE_none;
1261 free_unmarked (pp);
1262 if (NULL != pp->nested_boundary)
1263 {
1264 free (pp->nested_boundary);
1265 pp->nested_boundary = NULL;
1266 }
1267 pp->state = PP_ProcessEntryHeaders;
1268 state_changed = 1;
1269 break;
1270 case PP_Nested_Init:
1271 if (NULL == pp->nested_boundary)
1272 {
1273 pp->state = PP_Error;
1274 return MHD_NO;
1275 }
1276 if (MHD_NO == find_boundary (pp,
1277 pp->nested_boundary,
1278 pp->nlen,
1279 &ioff,
1281 PP_NextBoundary /* or PP_Error? */))
1282 {
1283 if (pp->state == PP_Error)
1284 return MHD_NO;
1285 goto END;
1286 }
1287 break;
1289 /* remember what headers were given
1290 globally */
1291 pp->have = NE_none;
1292 if (NULL != pp->content_name)
1293 pp->have |= NE_content_name;
1294 if (NULL != pp->content_type)
1295 pp->have |= NE_content_type;
1296 if (NULL != pp->content_filename)
1297 pp->have |= NE_content_filename;
1298 if (NULL != pp->content_transfer_encoding)
1299 pp->have |= NE_content_transfer_encoding;
1301 state_changed = 1;
1302 break;
1304 pp->value_offset = 0;
1305 if (MHD_NO ==
1307 &ioff,
1309 {
1310 if (pp->state == PP_Error)
1311 return MHD_NO;
1312 else
1313 goto END;
1314 }
1315 state_changed = 1;
1316 break;
1319 &ioff,
1320 pp->nested_boundary,
1321 pp->nlen,
1324 {
1325 if (pp->state == PP_Error)
1326 return MHD_NO;
1327 break;
1328 }
1329 break;
1331 free_unmarked (pp);
1333 state_changed = 1;
1334 break;
1335 default:
1337 __FILE__,
1338 __LINE__,
1339 NULL); /* should never happen! */
1340 }
1341AGAIN:
1342 if (ioff > 0)
1343 {
1344 memmove (buf,
1345 &buf[ioff],
1346 pp->buffer_pos - ioff);
1347 pp->buffer_pos -= ioff;
1348 ioff = 0;
1349 state_changed = 1;
1350 }
1351 }
1352END:
1353 if (0 != ioff)
1354 {
1355 memmove (buf,
1356 &buf[ioff],
1357 pp->buffer_pos - ioff);
1358 pp->buffer_pos -= ioff;
1359 }
1360 if (poff < post_data_len)
1361 {
1362 pp->state = PP_Error;
1363 return MHD_NO; /* serious error */
1364 }
1365 return MHD_YES;
1366}
1367
1368
1382enum MHD_Result
1383MHD_post_process (struct MHD_PostProcessor *pp,
1384 const char *post_data,
1385 size_t post_data_len)
1386{
1387 if (0 == post_data_len)
1388 return MHD_YES;
1389 if (NULL == pp)
1390 return MHD_NO;
1392 pp->encoding,
1395 return post_process_urlencoded (pp,
1396 post_data,
1397 post_data_len);
1399 pp->encoding,
1402 return post_process_multipart (pp,
1403 post_data,
1404 post_data_len);
1405 /* this should never be reached */
1406 return MHD_NO;
1407}
1408
1409
1420enum MHD_Result
1421MHD_destroy_post_processor (struct MHD_PostProcessor *pp)
1422{
1423 enum MHD_Result ret;
1424
1425 if (NULL == pp)
1426 return MHD_YES;
1427 if (PP_ProcessValue == pp->state)
1428 {
1429 /* key without terminated value left at the end of the
1430 buffer; fake receiving a termination character to
1431 ensure it is also processed */
1433 "\n",
1434 1);
1435 }
1436 /* These internal strings need cleaning up since
1437 the post-processing may have been interrupted
1438 at any stage */
1439 if ( (pp->xbuf_pos > 0) ||
1440 ( (pp->state != PP_Done) &&
1441 (pp->state != PP_Init) ) )
1442 ret = MHD_NO;
1443 else
1444 ret = MHD_YES;
1445 pp->have = NE_none;
1446 free_unmarked (pp);
1447 if (NULL != pp->nested_boundary)
1448 free (pp->nested_boundary);
1449 free (pp);
1450 return ret;
1451}
1452
1453
1454/* end of postprocessor.c */
#define MHD_HTTP_HEADER_CONTENT_TYPE
Definition: microhttpd.h:580
#define MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA
Definition: microhttpd.h:991
#define MHD_HTTP_POST_ENCODING_FORM_URLENCODED
Definition: microhttpd.h:989
_MHD_EXTERN enum MHD_Result MHD_post_process(struct MHD_PostProcessor *pp, const char *post_data, size_t post_data_len)
_MHD_EXTERN struct MHD_PostProcessor * MHD_create_post_processor(struct MHD_Connection *connection, size_t buffer_size, MHD_PostDataIterator iter, void *iter_cls)
_MHD_EXTERN enum MHD_Result MHD_destroy_post_processor(struct MHD_PostProcessor *pp)
_MHD_EXTERN enum MHD_Result MHD_lookup_connection_value_n(struct MHD_Connection *connection, enum MHD_ValueKind kind, const char *key, size_t key_size, const char **value_ptr, size_t *value_size_ptr)
Definition: connection.c:512
void MHD_unescape_plus(char *arg)
Definition: internal.c:123
MHD_PanicCallback mhd_panic
Definition: panic.c:31
void * mhd_panic_cls
Definition: panic.c:36
#define mhd_assert(CHK)
Definition: mhd_assert.h:39
void * MHD_calloc_(size_t nelem, size_t elsize)
Definition: mhd_compat.c:98
int MHD_str_equal_caseless_n_(const char *const str1, const char *const str2, size_t maxlen)
Definition: mhd_str.c:378
#define MHD_STATICSTR_LEN_(macro)
Definition: mhd_str.h:45
#define NULL
Definition: reason_phrase.c:30
internal shared structures
Header for platform missing functions.
Header for string manipulating helpers.
MHD_Result
Definition: microhttpd.h:141
@ MHD_YES
Definition: microhttpd.h:150
@ MHD_NO
Definition: microhttpd.h:145
_MHD_EXTERN size_t MHD_http_unescape(char *val)
Definition: internal.c:142
enum MHD_Result(* MHD_PostDataIterator)(void *cls, enum MHD_ValueKind kind, const char *key, const char *filename, const char *content_type, const char *transfer_encoding, const char *data, uint64_t off, size_t size)
Definition: microhttpd.h:2363
@ MHD_POSTDATA_KIND
Definition: microhttpd.h:1797
@ MHD_HEADER_KIND
Definition: microhttpd.h:1781
static int post_process_urlencoded(struct MHD_PostProcessor *pp, const char *post_data, size_t post_data_len)
static int try_match_header(const char *prefix, size_t prefix_len, char *line, char **suffix)
static int find_boundary(struct MHD_PostProcessor *pp, const char *boundary, size_t blen, size_t *ioffptr, enum PP_State next_state, enum PP_State next_dash_state)
RN_State
Definition: postprocessor.c:70
@ RN_Dash
Definition: postprocessor.c:92
@ RN_Inactive
Definition: postprocessor.c:74
@ RN_Full
Definition: postprocessor.c:86
@ RN_OptN
Definition: postprocessor.c:80
@ RN_Dash2
Definition: postprocessor.c:97
static int process_value_to_boundary(struct MHD_PostProcessor *pp, size_t *ioffptr, const char *boundary, size_t blen, enum PP_State next_state, enum PP_State next_dash_state)
#define XBUF_SIZE
Definition: postprocessor.c:35
NE_State
@ NE_content_name
@ NE_content_type
@ NE_content_transfer_encoding
@ NE_none
@ NE_content_filename
static int post_process_multipart(struct MHD_PostProcessor *pp, const char *post_data, size_t post_data_len)
static void process_value(struct MHD_PostProcessor *pp, const char *value_start, const char *value_end, const char *last_escape)
PP_State
Definition: postprocessor.c:41
@ PP_PerformCleanup
Definition: postprocessor.c:57
@ PP_Error
Definition: postprocessor.c:43
@ PP_Nested_PerformMarking
Definition: postprocessor.c:61
@ PP_Init
Definition: postprocessor.c:45
@ PP_PerformCheckMultipart
Definition: postprocessor.c:55
@ PP_Nested_Init
Definition: postprocessor.c:60
@ PP_ProcessValue
Definition: postprocessor.c:49
@ PP_ExpectNewLine
Definition: postprocessor.c:51
@ PP_Nested_ProcessEntryHeaders
Definition: postprocessor.c:62
@ PP_Nested_PerformCleanup
Definition: postprocessor.c:64
@ PP_NextBoundary
Definition: postprocessor.c:46
@ PP_ProcessEntryHeaders
Definition: postprocessor.c:54
@ PP_ProcessValueToBoundary
Definition: postprocessor.c:56
@ PP_Done
Definition: postprocessor.c:44
@ PP_Callback
Definition: postprocessor.c:50
@ PP_Nested_ProcessValueToBoundary
Definition: postprocessor.c:63
static void try_get_value(const char *buf, const char *key, char **destination)
static void free_unmarked(struct MHD_PostProcessor *pp)
static int process_multipart_headers(struct MHD_PostProcessor *pp, size_t *ioffptr, enum PP_State next_state)
enum MHD_CONNECTION_STATE state
Definition: internal.h:924