GNU libmicrohttpd 0.9.73
Loading...
Searching...
No Matches
postprocessor.c
Go to the documentation of this file.
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007-2021 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#include "mhd_assert.h"
30
36#define XBUF_SIZE 512
37
42{
43 /* general states */
48
49 /* url encoding-states */
53
54 /* post encoding-states */
59
60 /* nested post-encoding states */
66
67};
68
69
71{
76
82
88
94
98 RN_Dash2 = 4
99};
100
101
108{
115
116
121struct MHD_PostProcessor
122{
123
128 struct MHD_Connection *connection;
129
134
138 void *cls;
139
143 const char *encoding;
144
148 const char *boundary;
149
153 char *nested_boundary;
154
158 char *content_name;
159
163 char *content_type;
164
168 char *content_filename;
169
173 char *content_transfer_encoding;
174
178 char xbuf[2];
179
183 size_t buffer_size;
184
188 size_t buffer_pos;
189
193 size_t xbuf_pos;
194
198 uint64_t value_offset;
199
203 size_t blen;
204
208 size_t nlen;
209
218 bool must_ikvi;
219
224 bool must_unescape_key;
225
229 enum PP_State state;
230
237 enum RN_State skip_rn;
238
243 enum PP_State dash_state;
244
249 enum NE_State have;
250
251};
252
253
254struct MHD_PostProcessor *
256 size_t buffer_size,
258 void *iter_cls)
259{
260 struct MHD_PostProcessor *ret;
261 const char *encoding;
262 const char *boundary;
263 size_t blen;
264
265 if ( (buffer_size < 256) ||
266 (NULL == connection) ||
267 (NULL == iter))
269 __FILE__,
270 __LINE__,
271 NULL);
272 if (MHD_NO == MHD_lookup_connection_value_n (connection,
277 &encoding,
278 NULL))
279 return NULL;
280 boundary = NULL;
282 encoding,
285 {
287 encoding,
290 return NULL;
291 boundary =
293 /* Q: should this be "strcasestr"? */
294 boundary = strstr (boundary, "boundary=");
295 if (NULL == boundary)
296 return NULL; /* failed to determine boundary */
297 boundary += MHD_STATICSTR_LEN_ ("boundary=");
298 blen = strlen (boundary);
299 if ( (blen == 0) ||
300 (blen * 2 + 2 > buffer_size) )
301 return NULL; /* (will be) out of memory or invalid boundary */
302 if ( (boundary[0] == '"') &&
303 (boundary[blen - 1] == '"') )
304 {
305 /* remove enclosing quotes */
306 ++boundary;
307 blen -= 2;
308 }
309 }
310 else
311 blen = 0;
312 buffer_size += 4; /* round up to get nice block sizes despite boundary search */
313
314 /* add +1 to ensure we ALWAYS have a zero-termination at the end */
315 if (NULL == (ret = MHD_calloc_ (1, sizeof (struct MHD_PostProcessor)
316 + buffer_size + 1)))
317 return NULL;
318 ret->connection = connection;
319 ret->ikvi = iter;
320 ret->cls = iter_cls;
321 ret->encoding = encoding;
322 ret->buffer_size = buffer_size;
323 ret->state = PP_Init;
324 ret->blen = blen;
325 ret->boundary = boundary;
326 ret->skip_rn = RN_Inactive;
327 return ret;
328}
329
330
348static void
349process_value (struct MHD_PostProcessor *pp,
350 const char *value_start,
351 const char *value_end,
352 const char *last_escape)
353{
354 char xbuf[XBUF_SIZE + 1];
355 size_t xoff;
356
357 mhd_assert (pp->xbuf_pos < sizeof (xbuf));
358 /* move remaining input from previous round into processing buffer */
359 memcpy (xbuf,
360 pp->xbuf,
361 pp->xbuf_pos);
362 xoff = pp->xbuf_pos;
363 pp->xbuf_pos = 0;
364 if ( (NULL != last_escape) &&
365 (((size_t) (value_end - last_escape)) < sizeof (pp->xbuf)) )
366 {
367 pp->xbuf_pos = value_end - last_escape;
368 memcpy (pp->xbuf,
369 last_escape,
370 value_end - last_escape);
371 value_end = last_escape;
372 }
373 while ( (value_start != value_end) ||
374 (pp->must_ikvi) ||
375 (xoff > 0) )
376 {
377 size_t delta = value_end - value_start;
378 bool cut = false;
379 size_t clen = 0;
380
381 if (delta > XBUF_SIZE - xoff)
382 delta = XBUF_SIZE - xoff;
383 /* move (additional) input into processing buffer */
384 memcpy (&xbuf[xoff],
385 value_start,
386 delta);
387 xoff += delta;
388 value_start += delta;
389 /* find if escape sequence is at the end of the processing buffer;
390 if so, exclude those from processing (reduce delta to point at
391 end of processed region) */
392 if ( (xoff > 0) &&
393 ('%' == xbuf[xoff - 1]) )
394 {
395 cut = (xoff != XBUF_SIZE);
396 xoff--;
397 if (cut)
398 {
399 /* move escape sequence into buffer for next function invocation */
400 pp->xbuf[0] = '%';
401 pp->xbuf_pos = 1;
402 }
403 else
404 {
405 /* just skip escape sequence for next loop iteration */
406 delta = xoff;
407 clen = 1;
408 }
409 }
410 else if ( (xoff > 1) &&
411 ('%' == xbuf[xoff - 2]) )
412 {
413 cut = (xoff != XBUF_SIZE);
414 xoff -= 2;
415 if (cut)
416 {
417 /* move escape sequence into buffer for next function invocation */
418 memcpy (pp->xbuf,
419 &xbuf[xoff],
420 2);
421 pp->xbuf_pos = 2;
422 }
423 else
424 {
425 /* just skip escape sequence for next loop iteration */
426 delta = xoff;
427 clen = 2;
428 }
429 }
430 mhd_assert (xoff < sizeof (xbuf));
431 /* unescape */
432 xbuf[xoff] = '\0'; /* 0-terminate in preparation */
433 MHD_unescape_plus (xbuf);
434 xoff = MHD_http_unescape (xbuf);
435 /* finally: call application! */
436 if (pp->must_ikvi || (0 != xoff) )
437 {
438 pp->must_ikvi = false;
439 if (MHD_NO == pp->ikvi (pp->cls,
441 (const char *) &pp[1], /* key */
442 NULL,
443 NULL,
444 NULL,
445 xbuf,
446 pp->value_offset,
447 xoff))
448 {
449 pp->state = PP_Error;
450 return;
451 }
452 }
453 pp->value_offset += xoff;
454 if (cut)
455 break;
456 xbuf[delta] = '%'; /* undo 0-termination */
457 memmove (xbuf,
458 &xbuf[delta],
459 clen);
460 xoff = clen;
461 }
462}
463
464
473static int
474post_process_urlencoded (struct MHD_PostProcessor *pp,
475 const char *post_data,
476 size_t post_data_len)
477{
478 char *kbuf = (char *) &pp[1];
479 size_t poff;
480 const char *start_key = NULL;
481 const char *end_key = NULL;
482 const char *start_value = NULL;
483 const char *end_value = NULL;
484 const char *last_escape = NULL;
485
486 mhd_assert (PP_Callback != pp->state);
487
488 poff = 0;
489 while ( ( (poff < post_data_len) ||
490 (pp->state == PP_Callback) ) &&
491 (pp->state != PP_Error) )
492 {
493 switch (pp->state)
494 {
495 case PP_Error:
496 /* clearly impossible as per while loop invariant */
497 abort ();
498 break;
499 case PP_Init:
500 /* key phase */
501 if (NULL == start_key)
502 start_key = &post_data[poff];
503 pp->must_ikvi = true;
504 switch (post_data[poff])
505 {
506 case '=':
507 /* Case: 'key=' */
508 end_key = &post_data[poff];
509 poff++;
510 pp->state = PP_ProcessValue;
511 break;
512 case '&':
513 /* Case: 'key&' */
514 end_key = &post_data[poff];
515 mhd_assert (NULL == start_value);
516 mhd_assert (NULL == end_value);
517 poff++;
518 pp->state = PP_Callback;
519 break;
520 case '\n':
521 case '\r':
522 /* Case: 'key\n' or 'key\r' */
523 end_key = &post_data[poff];
524 poff++;
525 pp->state = PP_Done;
526 break;
527 default:
528 /* normal character, advance! */
529 poff++;
530 continue;
531 }
532 break; /* end PP_Init */
533 case PP_ProcessValue:
534 if (NULL == start_value)
535 start_value = &post_data[poff];
536 switch (post_data[poff])
537 {
538 case '=':
539 /* case 'key==' */
540 pp->state = PP_Error;
541 continue;
542 case '&':
543 /* case 'value&' */
544 end_value = &post_data[poff];
545 poff++;
546 if (pp->must_ikvi ||
547 (start_value != end_value) )
548 {
549 pp->state = PP_Callback;
550 }
551 else
552 {
553 pp->buffer_pos = 0;
554 pp->value_offset = 0;
555 pp->state = PP_Init;
556 start_value = NULL;
557 end_value = NULL;
558 }
559 continue;
560 case '\n':
561 case '\r':
562 /* Case: 'value\n' or 'value\r' */
563 end_value = &post_data[poff];
564 poff++;
565 if (pp->must_ikvi)
566 pp->state = PP_Callback;
567 else
568 pp->state = PP_Done;
569 break;
570 case '%':
571 last_escape = &post_data[poff];
572 poff++;
573 break;
574 case '0':
575 case '1':
576 case '2':
577 case '3':
578 case '4':
579 case '5':
580 case '6':
581 case '7':
582 case '8':
583 case '9':
584 /* character, may be part of escaping */
585 poff++;
586 continue;
587 default:
588 /* normal character, no more escaping! */
589 last_escape = NULL;
590 poff++;
591 continue;
592 }
593 break; /* end PP_ProcessValue */
594 case PP_Done:
595 switch (post_data[poff])
596 {
597 case '\n':
598 case '\r':
599 poff++;
600 continue;
601 }
602 /* unexpected data at the end, fail! */
603 pp->state = PP_Error;
604 break;
605 case PP_Callback:
606 if ( (pp->buffer_pos + (end_key - start_key) >=
607 pp->buffer_size) ||
608 (pp->buffer_pos + (end_key - start_key) <
609 pp->buffer_pos) )
610 {
611 /* key too long, cannot parse! */
612 pp->state = PP_Error;
613 continue;
614 }
615 /* compute key, if we have not already */
616 if (NULL != start_key)
617 {
618 memcpy (&kbuf[pp->buffer_pos],
619 start_key,
620 end_key - start_key);
621 pp->buffer_pos += end_key - start_key;
622 start_key = NULL;
623 end_key = NULL;
624 pp->must_unescape_key = true;
625 }
626 if (pp->must_unescape_key)
627 {
628 kbuf[pp->buffer_pos] = '\0'; /* 0-terminate key */
629 MHD_unescape_plus (kbuf);
630 MHD_http_unescape (kbuf);
631 pp->must_unescape_key = false;
632 }
633 process_value (pp,
634 start_value,
635 end_value,
636 NULL);
637 if (PP_Error == pp->state)
638 continue;
639 pp->value_offset = 0;
640 start_value = NULL;
641 end_value = NULL;
642 pp->buffer_pos = 0;
643 pp->state = PP_Init;
644 break;
645 default:
647 __FILE__,
648 __LINE__,
649 NULL); /* should never happen! */
650 }
651 }
652
653 /* save remaining data for next iteration */
654 if (NULL != start_key)
655 {
656 if (NULL == end_key)
657 end_key = &post_data[poff];
658 if (pp->buffer_pos + (end_key - start_key) >= pp->buffer_size)
659 {
660 pp->state = PP_Error;
661 return MHD_NO;
662 }
663 memcpy (&kbuf[pp->buffer_pos],
664 start_key,
665 end_key - start_key);
666 pp->buffer_pos += end_key - start_key;
667 pp->must_unescape_key = true;
668 start_key = NULL;
669 end_key = NULL;
670 }
671 if ( (NULL != start_value) &&
672 (PP_ProcessValue == pp->state) )
673 {
674 /* compute key, if we have not already */
675 if (pp->must_unescape_key)
676 {
677 kbuf[pp->buffer_pos] = '\0'; /* 0-terminate key */
678 MHD_unescape_plus (kbuf);
679 MHD_http_unescape (kbuf);
680 pp->must_unescape_key = false;
681 }
682 if (NULL == end_value)
683 end_value = &post_data[poff];
684 process_value (pp,
685 start_value,
686 end_value,
687 last_escape);
688 pp->must_ikvi = false;
689 }
690 if (PP_Error == pp->state)
691 {
692 /* State in error, returning failure */
693 return MHD_NO;
694 }
695 return MHD_YES;
696}
697
698
709static int
710try_match_header (const char *prefix,
711 size_t prefix_len,
712 char *line,
713 char **suffix)
714{
715 if (NULL != *suffix)
716 return MHD_NO;
717 while (0 != *line)
718 {
719 if (MHD_str_equal_caseless_n_ (prefix,
720 line,
721 prefix_len))
722 {
723 *suffix = strdup (&line[prefix_len]);
724 return MHD_YES;
725 }
726 ++line;
727 }
728 return MHD_NO;
729}
730
731
745static int
746find_boundary (struct MHD_PostProcessor *pp,
747 const char *boundary,
748 size_t blen,
749 size_t *ioffptr,
750 enum PP_State next_state,
751 enum PP_State next_dash_state)
752{
753 char *buf = (char *) &pp[1];
754 const char *dash;
755
756 if (pp->buffer_pos < 2 + blen)
757 {
758 if (pp->buffer_pos == pp->buffer_size)
759 pp->state = PP_Error; /* out of memory */
760 /* ++(*ioffptr); */
761 return MHD_NO; /* not enough data */
762 }
763 if ( (0 != memcmp ("--",
764 buf,
765 2)) ||
766 (0 != memcmp (&buf[2],
767 boundary,
768 blen)))
769 {
770 if (pp->state != PP_Init)
771 {
772 /* garbage not allowed */
773 pp->state = PP_Error;
774 }
775 else
776 {
777 /* skip over garbage (RFC 2046, 5.1.1) */
778 dash = memchr (buf,
779 '-',
780 pp->buffer_pos);
781 if (NULL == dash)
782 (*ioffptr) += pp->buffer_pos; /* skip entire buffer */
783 else if (dash == buf)
784 (*ioffptr)++; /* at least skip one byte */
785 else
786 (*ioffptr) += dash - buf; /* skip to first possible boundary */
787 }
788 return MHD_NO; /* expected boundary */
789 }
790 /* remove boundary from buffer */
791 (*ioffptr) += 2 + blen;
792 /* next: start with headers */
793 pp->skip_rn = RN_Dash;
794 pp->state = next_state;
795 pp->dash_state = next_dash_state;
796 return MHD_YES;
797}
798
799
806static void
807try_get_value (const char *buf,
808 const char *key,
809 char **destination)
810{
811 const char *spos;
812 const char *bpos;
813 const char *endv;
814 size_t klen;
815 size_t vlen;
816
817 if (NULL != *destination)
818 return;
819 bpos = buf;
820 klen = strlen (key);
821 while (NULL != (spos = strstr (bpos, key)))
822 {
823 if ( (spos[klen] != '=') ||
824 ( (spos != buf) &&
825 (spos[-1] != ' ') ) )
826 {
827 /* no match */
828 bpos = spos + 1;
829 continue;
830 }
831 if (spos[klen + 1] != '"')
832 return; /* not quoted */
833 if (NULL == (endv = strchr (&spos[klen + 2],
834 '\"')))
835 return; /* no end-quote */
836 vlen = endv - spos - klen - 1;
837 *destination = malloc (vlen);
838 if (NULL == *destination)
839 return; /* out of memory */
840 (*destination)[vlen - 1] = '\0';
841 memcpy (*destination,
842 &spos[klen + 2],
843 vlen - 1);
844 return; /* success */
845 }
846}
847
848
864static int
865process_multipart_headers (struct MHD_PostProcessor *pp,
866 size_t *ioffptr,
867 enum PP_State next_state)
868{
869 char *buf = (char *) &pp[1];
870 size_t newline;
871
872 newline = 0;
873 while ( (newline < pp->buffer_pos) &&
874 (buf[newline] != '\r') &&
875 (buf[newline] != '\n') )
876 newline++;
877 if (newline == pp->buffer_size)
878 {
879 pp->state = PP_Error;
880 return MHD_NO; /* out of memory */
881 }
882 if (newline == pp->buffer_pos)
883 return MHD_NO; /* will need more data */
884 if (0 == newline)
885 {
886 /* empty line - end of headers */
887 pp->skip_rn = RN_Full;
888 pp->state = next_state;
889 return MHD_YES;
890 }
891 /* got an actual header */
892 if (buf[newline] == '\r')
893 pp->skip_rn = RN_OptN;
894 buf[newline] = '\0';
895 if (MHD_str_equal_caseless_n_ ("Content-disposition: ",
896 buf,
897 MHD_STATICSTR_LEN_ ("Content-disposition: ")))
898 {
899 try_get_value (&buf[MHD_STATICSTR_LEN_ ("Content-disposition: ")],
900 "name",
901 &pp->content_name);
902 try_get_value (&buf[MHD_STATICSTR_LEN_ ("Content-disposition: ")],
903 "filename",
904 &pp->content_filename);
905 }
906 else
907 {
908 try_match_header ("Content-type: ",
909 MHD_STATICSTR_LEN_ ("Content-type: "),
910 buf,
911 &pp->content_type);
912 try_match_header ("Content-Transfer-Encoding: ",
913 MHD_STATICSTR_LEN_ ("Content-Transfer-Encoding: "),
914 buf,
915 &pp->content_transfer_encoding);
916 }
917 (*ioffptr) += newline + 1;
918 return MHD_YES;
919}
920
921
938static int
939process_value_to_boundary (struct MHD_PostProcessor *pp,
940 size_t *ioffptr,
941 const char *boundary,
942 size_t blen,
943 enum PP_State next_state,
944 enum PP_State next_dash_state)
945{
946 char *buf = (char *) &pp[1];
947 size_t newline;
948 const char *r;
949
950 /* all data in buf until the boundary
951 (\r\n--+boundary) is part of the value */
952 newline = 0;
953 while (1)
954 {
955 while (newline + 4 < pp->buffer_pos)
956 {
957 r = memchr (&buf[newline],
958 '\r',
959 pp->buffer_pos - newline - 4);
960 if (NULL == r)
961 {
962 newline = pp->buffer_pos - 4;
963 break;
964 }
965 newline = r - buf;
966 if (0 == memcmp ("\r\n--",
967 &buf[newline],
968 4))
969 break;
970 newline++;
971 }
972 if (newline + blen + 4 <= pp->buffer_pos)
973 {
974 /* can check boundary */
975 if (0 != memcmp (&buf[newline + 4],
976 boundary,
977 blen))
978 {
979 /* no boundary, "\r\n--" is part of content, skip */
980 newline += 4;
981 continue;
982 }
983 else
984 {
985 /* boundary found, process until newline then
986 skip boundary and go back to init */
987 pp->skip_rn = RN_Dash;
988 pp->state = next_state;
989 pp->dash_state = next_dash_state;
990 (*ioffptr) += blen + 4; /* skip boundary as well */
991 buf[newline] = '\0';
992 break;
993 }
994 }
995 else
996 {
997 /* cannot check for boundary, process content that
998 we have and check again later; except, if we have
999 no content, abort (out of memory) */
1000 if ( (0 == newline) &&
1001 (pp->buffer_pos == pp->buffer_size) )
1002 {
1003 pp->state = PP_Error;
1004 return MHD_NO;
1005 }
1006 break;
1007 }
1008 }
1009 /* newline is either at beginning of boundary or
1010 at least at the last character that we are sure
1011 is not part of the boundary */
1012 if ( ( (pp->must_ikvi) ||
1013 (0 != newline) ) &&
1014 (MHD_NO == pp->ikvi (pp->cls,
1016 pp->content_name,
1017 pp->content_filename,
1018 pp->content_type,
1019 pp->content_transfer_encoding,
1020 buf,
1021 pp->value_offset,
1022 newline)) )
1023 {
1024 pp->state = PP_Error;
1025 return MHD_NO;
1026 }
1027 pp->must_ikvi = false;
1028 pp->value_offset += newline;
1029 (*ioffptr) += newline;
1030 return MHD_YES;
1031}
1032
1033
1038static void
1039free_unmarked (struct MHD_PostProcessor *pp)
1040{
1041 if ( (NULL != pp->content_name) &&
1042 (0 == (pp->have & NE_content_name)) )
1043 {
1044 free (pp->content_name);
1045 pp->content_name = NULL;
1046 }
1047 if ( (NULL != pp->content_type) &&
1048 (0 == (pp->have & NE_content_type)) )
1049 {
1050 free (pp->content_type);
1051 pp->content_type = NULL;
1052 }
1053 if ( (NULL != pp->content_filename) &&
1054 (0 == (pp->have & NE_content_filename)) )
1055 {
1056 free (pp->content_filename);
1057 pp->content_filename = NULL;
1058 }
1059 if ( (NULL != pp->content_transfer_encoding) &&
1060 (0 == (pp->have & NE_content_transfer_encoding)) )
1061 {
1062 free (pp->content_transfer_encoding);
1063 pp->content_transfer_encoding = NULL;
1064 }
1065}
1066
1067
1076static int
1077post_process_multipart (struct MHD_PostProcessor *pp,
1078 const char *post_data,
1079 size_t post_data_len)
1080{
1081 char *buf;
1082 size_t max;
1083 size_t ioff;
1084 size_t poff;
1085 int state_changed;
1086
1087 buf = (char *) &pp[1];
1088 ioff = 0;
1089 poff = 0;
1090 state_changed = 1;
1091 while ( (poff < post_data_len) ||
1092 ( (pp->buffer_pos > 0) &&
1093 (0 != state_changed) ) )
1094 {
1095 /* first, move as much input data
1096 as possible to our internal buffer */
1097 max = pp->buffer_size - pp->buffer_pos;
1098 if (max > post_data_len - poff)
1099 max = post_data_len - poff;
1100 memcpy (&buf[pp->buffer_pos],
1101 &post_data[poff],
1102 max);
1103 poff += max;
1104 pp->buffer_pos += max;
1105 if ( (0 == max) &&
1106 (0 == state_changed) &&
1107 (poff < post_data_len) )
1108 {
1109 pp->state = PP_Error;
1110 return MHD_NO; /* out of memory */
1111 }
1112 state_changed = 0;
1113
1114 /* first state machine for '\r'-'\n' and '--' handling */
1115 switch (pp->skip_rn)
1116 {
1117 case RN_Inactive:
1118 break;
1119 case RN_OptN:
1120 if (buf[0] == '\n')
1121 {
1122 ioff++;
1123 pp->skip_rn = RN_Inactive;
1124 goto AGAIN;
1125 }
1126 /* fall-through! */
1127 case RN_Dash:
1128 if (buf[0] == '-')
1129 {
1130 ioff++;
1131 pp->skip_rn = RN_Dash2;
1132 goto AGAIN;
1133 }
1134 pp->skip_rn = RN_Full;
1135 /* fall-through! */
1136 case RN_Full:
1137 if (buf[0] == '\r')
1138 {
1139 if ( (pp->buffer_pos > 1) &&
1140 ('\n' == buf[1]) )
1141 {
1142 pp->skip_rn = RN_Inactive;
1143 ioff += 2;
1144 }
1145 else
1146 {
1147 pp->skip_rn = RN_OptN;
1148 ioff++;
1149 }
1150 goto AGAIN;
1151 }
1152 if (buf[0] == '\n')
1153 {
1154 ioff++;
1155 pp->skip_rn = RN_Inactive;
1156 goto AGAIN;
1157 }
1158 pp->skip_rn = RN_Inactive;
1159 pp->state = PP_Error;
1160 return MHD_NO; /* no '\r\n' */
1161 case RN_Dash2:
1162 if (buf[0] == '-')
1163 {
1164 ioff++;
1165 pp->skip_rn = RN_Full;
1166 pp->state = pp->dash_state;
1167 goto AGAIN;
1168 }
1169 pp->state = PP_Error;
1170 break;
1171 }
1172
1173 /* main state engine */
1174 switch (pp->state)
1175 {
1176 case PP_Error:
1177 return MHD_NO;
1178 case PP_Done:
1179 /* did not expect to receive more data */
1180 pp->state = PP_Error;
1181 return MHD_NO;
1182 case PP_Init:
1194 (void) find_boundary (pp,
1195 pp->boundary,
1196 pp->blen,
1197 &ioff,
1199 PP_Done);
1200 break;
1201 case PP_NextBoundary:
1202 if (MHD_NO == find_boundary (pp,
1203 pp->boundary,
1204 pp->blen,
1205 &ioff,
1207 PP_Done))
1208 {
1209 if (pp->state == PP_Error)
1210 return MHD_NO;
1211 goto END;
1212 }
1213 break;
1215 pp->must_ikvi = true;
1216 if (MHD_NO ==
1218 &ioff,
1220 {
1221 if (pp->state == PP_Error)
1222 return MHD_NO;
1223 else
1224 goto END;
1225 }
1226 state_changed = 1;
1227 break;
1229 if ( (NULL != pp->content_type) &&
1230 (MHD_str_equal_caseless_n_ (pp->content_type,
1231 "multipart/mixed",
1232 MHD_STATICSTR_LEN_ ("multipart/mixed"))))
1233 {
1234 pp->nested_boundary = strstr (pp->content_type,
1235 "boundary=");
1236 if (NULL == pp->nested_boundary)
1237 {
1238 pp->state = PP_Error;
1239 return MHD_NO;
1240 }
1241 pp->nested_boundary =
1242 strdup (&pp->nested_boundary[MHD_STATICSTR_LEN_ ("boundary=")]);
1243 if (NULL == pp->nested_boundary)
1244 {
1245 /* out of memory */
1246 pp->state = PP_Error;
1247 return MHD_NO;
1248 }
1249 /* free old content type, we will need that field
1250 for the content type of the nested elements */
1251 free (pp->content_type);
1252 pp->content_type = NULL;
1253 pp->nlen = strlen (pp->nested_boundary);
1254 pp->state = PP_Nested_Init;
1255 state_changed = 1;
1256 break;
1257 }
1258 pp->state = PP_ProcessValueToBoundary;
1259 pp->value_offset = 0;
1260 state_changed = 1;
1261 break;
1264 &ioff,
1265 pp->boundary,
1266 pp->blen,
1268 PP_Done))
1269 {
1270 if (pp->state == PP_Error)
1271 return MHD_NO;
1272 break;
1273 }
1274 break;
1275 case PP_PerformCleanup:
1276 /* clean up state of one multipart form-data element! */
1277 pp->have = NE_none;
1278 free_unmarked (pp);
1279 if (NULL != pp->nested_boundary)
1280 {
1281 free (pp->nested_boundary);
1282 pp->nested_boundary = NULL;
1283 }
1284 pp->state = PP_ProcessEntryHeaders;
1285 state_changed = 1;
1286 break;
1287 case PP_Nested_Init:
1288 if (NULL == pp->nested_boundary)
1289 {
1290 pp->state = PP_Error;
1291 return MHD_NO;
1292 }
1293 if (MHD_NO == find_boundary (pp,
1294 pp->nested_boundary,
1295 pp->nlen,
1296 &ioff,
1298 PP_NextBoundary /* or PP_Error? */))
1299 {
1300 if (pp->state == PP_Error)
1301 return MHD_NO;
1302 goto END;
1303 }
1304 break;
1306 /* remember what headers were given
1307 globally */
1308 pp->have = NE_none;
1309 if (NULL != pp->content_name)
1310 pp->have |= NE_content_name;
1311 if (NULL != pp->content_type)
1312 pp->have |= NE_content_type;
1313 if (NULL != pp->content_filename)
1314 pp->have |= NE_content_filename;
1315 if (NULL != pp->content_transfer_encoding)
1316 pp->have |= NE_content_transfer_encoding;
1318 state_changed = 1;
1319 break;
1321 pp->value_offset = 0;
1322 if (MHD_NO ==
1324 &ioff,
1326 {
1327 if (pp->state == PP_Error)
1328 return MHD_NO;
1329 else
1330 goto END;
1331 }
1332 state_changed = 1;
1333 break;
1336 &ioff,
1337 pp->nested_boundary,
1338 pp->nlen,
1341 {
1342 if (pp->state == PP_Error)
1343 return MHD_NO;
1344 break;
1345 }
1346 break;
1348 free_unmarked (pp);
1350 state_changed = 1;
1351 break;
1352 default:
1354 __FILE__,
1355 __LINE__,
1356 NULL); /* should never happen! */
1357 }
1358AGAIN:
1359 if (ioff > 0)
1360 {
1361 memmove (buf,
1362 &buf[ioff],
1363 pp->buffer_pos - ioff);
1364 pp->buffer_pos -= ioff;
1365 ioff = 0;
1366 state_changed = 1;
1367 }
1368 }
1369END:
1370 if (0 != ioff)
1371 {
1372 memmove (buf,
1373 &buf[ioff],
1374 pp->buffer_pos - ioff);
1375 pp->buffer_pos -= ioff;
1376 }
1377 if (poff < post_data_len)
1378 {
1379 pp->state = PP_Error;
1380 return MHD_NO; /* serious error */
1381 }
1382 return MHD_YES;
1383}
1384
1385
1386enum MHD_Result
1387MHD_post_process (struct MHD_PostProcessor *pp,
1388 const char *post_data,
1389 size_t post_data_len)
1390{
1391 if (0 == post_data_len)
1392 return MHD_YES;
1393 if (NULL == pp)
1394 return MHD_NO;
1396 pp->encoding,
1399 return post_process_urlencoded (pp,
1400 post_data,
1401 post_data_len);
1403 pp->encoding,
1406 return post_process_multipart (pp,
1407 post_data,
1408 post_data_len);
1409 /* this should never be reached */
1410 return MHD_NO;
1411}
1412
1413
1414enum MHD_Result
1415MHD_destroy_post_processor (struct MHD_PostProcessor *pp)
1416{
1417 enum MHD_Result ret;
1418
1419 if (NULL == pp)
1420 return MHD_YES;
1421 if (PP_ProcessValue == pp->state)
1422 {
1423 /* key without terminated value left at the end of the
1424 buffer; fake receiving a termination character to
1425 ensure it is also processed */
1427 "\n",
1428 1);
1429 }
1430 /* These internal strings need cleaning up since
1431 the post-processing may have been interrupted
1432 at any stage */
1433 if ( (pp->xbuf_pos > 0) ||
1434 ( (pp->state != PP_Done) &&
1435 (pp->state != PP_Init) ) )
1436 ret = MHD_NO;
1437 else
1438 ret = MHD_YES;
1439 pp->have = NE_none;
1440 free_unmarked (pp);
1441 if (NULL != pp->nested_boundary)
1442 free (pp->nested_boundary);
1443 free (pp);
1444 return ret;
1445}
1446
1447
1448/* end of postprocessor.c */
#define MHD_HTTP_HEADER_CONTENT_TYPE
Definition: microhttpd.h:578
#define MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA
Definition: microhttpd.h:1003
#define MHD_HTTP_POST_ENCODING_FORM_URLENCODED
Definition: microhttpd.h:1001
enum MHD_Result MHD_destroy_post_processor(struct MHD_PostProcessor *pp)
enum MHD_Result MHD_post_process(struct MHD_PostProcessor *pp, const char *post_data, size_t post_data_len)
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_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
macros for mhd_assert()
Header for platform missing functions.
Header for string manipulating helpers.
MHD_Result
Definition: microhttpd.h:139
@ MHD_YES
Definition: microhttpd.h:148
@ MHD_NO
Definition: microhttpd.h:143
_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:2415
@ MHD_POSTDATA_KIND
Definition: microhttpd.h:1831
@ MHD_HEADER_KIND
Definition: microhttpd.h:1815
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:71
@ RN_Dash
Definition: postprocessor.c:93
@ RN_Inactive
Definition: postprocessor.c:75
@ RN_Full
Definition: postprocessor.c:87
@ RN_OptN
Definition: postprocessor.c:81
@ RN_Dash2
Definition: postprocessor.c:98
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:36
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:42
@ PP_PerformCleanup
Definition: postprocessor.c:58
@ PP_Error
Definition: postprocessor.c:44
@ PP_Nested_PerformMarking
Definition: postprocessor.c:62
@ PP_Init
Definition: postprocessor.c:46
@ PP_PerformCheckMultipart
Definition: postprocessor.c:56
@ PP_Nested_Init
Definition: postprocessor.c:61
@ PP_ProcessValue
Definition: postprocessor.c:50
@ PP_ExpectNewLine
Definition: postprocessor.c:52
@ PP_Nested_ProcessEntryHeaders
Definition: postprocessor.c:63
@ PP_Nested_PerformCleanup
Definition: postprocessor.c:65
@ PP_NextBoundary
Definition: postprocessor.c:47
@ PP_ProcessEntryHeaders
Definition: postprocessor.c:55
@ PP_ProcessValueToBoundary
Definition: postprocessor.c:57
@ PP_Done
Definition: postprocessor.c:45
@ PP_Callback
Definition: postprocessor.c:51
@ PP_Nested_ProcessValueToBoundary
Definition: postprocessor.c:64
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)