GNU libmicrohttpd  0.9.70
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 
80  RN_OptN = 1,
81 
86  RN_Full = 2,
87 
92  RN_Dash = 3,
93 
98 };
99 
100 
107 {
108  NE_none = 0,
113 };
114 
115 
120 struct MHD_PostProcessor
121 {
122 
127  struct MHD_Connection *connection;
128 
133 
137  void *cls;
138 
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 
279 struct MHD_PostProcessor *
281  size_t buffer_size,
283  void *iter_cls)
284 {
285  struct MHD_PostProcessor *ret;
286  const char *encoding;
287  const char *boundary;
288  size_t blen;
289 
290  if ( (buffer_size < 256) ||
291  (NULL == connection) ||
292  (NULL == iter))
294  __FILE__,
295  __LINE__,
296  NULL);
297  if (MHD_NO == MHD_lookup_connection_value_n (connection,
302  &encoding,
303  NULL))
304  return NULL;
305  boundary = NULL;
307  encoding,
310  {
312  encoding,
315  return NULL;
316  boundary =
318  /* Q: should this be "strcasestr"? */
319  boundary = strstr (boundary, "boundary=");
320  if (NULL == boundary)
321  return NULL; /* failed to determine boundary */
322  boundary += MHD_STATICSTR_LEN_ ("boundary=");
323  blen = strlen (boundary);
324  if ( (blen == 0) ||
325  (blen * 2 + 2 > buffer_size) )
326  return NULL; /* (will be) out of memory or invalid boundary */
327  if ( (boundary[0] == '"') &&
328  (boundary[blen - 1] == '"') )
329  {
330  /* remove enclosing quotes */
331  ++boundary;
332  blen -= 2;
333  }
334  }
335  else
336  blen = 0;
337  buffer_size += 4; /* round up to get nice block sizes despite boundary search */
338 
339  /* add +1 to ensure we ALWAYS have a zero-termination at the end */
340  if (NULL == (ret = MHD_calloc_ (1, sizeof (struct MHD_PostProcessor)
341  + buffer_size + 1)))
342  return NULL;
343  ret->connection = connection;
344  ret->ikvi = iter;
345  ret->cls = iter_cls;
346  ret->encoding = encoding;
347  ret->buffer_size = buffer_size;
348  ret->state = PP_Init;
349  ret->blen = blen;
350  ret->boundary = boundary;
351  ret->skip_rn = RN_Inactive;
352  return ret;
353 }
354 
355 
377 static void
378 process_value (struct MHD_PostProcessor *pp,
379  const char *value_start,
380  const char *value_end,
381  const char *last_escape)
382 {
383  char xbuf[XBUF_SIZE + 1];
384  size_t xoff;
385 
386  mhd_assert (pp->xbuf_pos < sizeof (xbuf));
387  memcpy (xbuf,
388  pp->xbuf,
389  pp->xbuf_pos);
390  xoff = pp->xbuf_pos;
391  pp->xbuf_pos = 0;
392  if (NULL != last_escape)
393  {
394  if (value_end - last_escape < sizeof (pp->xbuf))
395  {
396  pp->xbuf_pos = value_end - last_escape;
397  memcpy (pp->xbuf,
398  last_escape,
399  value_end - last_escape);
400  value_end = last_escape;
401  }
402  }
403  while ( (value_start != value_end) ||
404  (pp->must_ikvi) ||
405  (xoff > 0) )
406  {
407  size_t delta = value_end - value_start;
408 
409  if (delta > XBUF_SIZE - xoff)
410  delta = XBUF_SIZE - xoff;
411  /* move input into processing buffer */
412  memcpy (&xbuf[xoff],
413  value_start,
414  delta);
415  /* find if escape sequence is at the end of the processing buffer;
416  if so, exclude those from processing (reduce delta to point at
417  end of processed region) */
418  if (delta >= XBUF_SIZE - 2)
419  {
420  if ((xoff + delta > 0) &&
421  ('%' == xbuf[xoff + delta - 1]))
422  delta--;
423  else if ((xoff + delta > 1) &&
424  ('%' == xbuf[xoff + delta - 2]))
425  delta -= 2;
426  }
427  xoff += delta;
428  value_start += delta;
429  mhd_assert (xoff < sizeof (xbuf));
430  /* unescape */
431  xbuf[xoff] = '\0'; /* 0-terminate in preparation */
432  MHD_unescape_plus (xbuf);
433  xoff = MHD_http_unescape (xbuf);
434  /* finally: call application! */
435  pp->must_ikvi = false;
436  if (MHD_NO == pp->ikvi (pp->cls,
438  (const char *) &pp[1], /* key */
439  NULL,
440  NULL,
441  NULL,
442  xbuf,
443  pp->value_offset,
444  xoff))
445  {
446  pp->state = PP_Error;
447  return;
448  }
449  pp->value_offset += xoff;
450  xoff = 0;
451  }
452 }
453 
454 
463 static int
464 post_process_urlencoded (struct MHD_PostProcessor *pp,
465  const char *post_data,
466  size_t post_data_len)
467 {
468  char *kbuf = (char *) &pp[1];
469  size_t poff;
470  const char *start_key = NULL;
471  const char *end_key = NULL;
472  const char *start_value = NULL;
473  const char *end_value = NULL;
474  const char *last_escape = NULL;
475 
476  poff = 0;
477  while ( ( (poff < post_data_len) ||
478  (pp->state == PP_Callback) ) &&
479  (pp->state != PP_Error) )
480  {
481  switch (pp->state) {
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  case '=':
525  /* case 'key==' */
526  pp->state = PP_Error;
527  continue;
528  case '&':
529  /* case 'value&' */
530  end_value = &post_data[poff];
531  poff++;
532  if ( pp->must_ikvi ||
533  (start_value != end_value) )
534  {
535  pp->state = PP_Callback;
536  }
537  else
538  {
539  pp->buffer_pos = 0;
540  pp->value_offset = 0;
541  pp->state = PP_Init;
542  }
543  continue;
544  case '\n':
545  case '\r':
546  /* Case: 'value\n' or 'value\r' */
547  end_value = &post_data[poff];
548  poff++;
549  if (pp->must_ikvi)
550  pp->state = PP_Callback;
551  else
552  pp->state = PP_Done;
553  break;
554  case '%':
555  last_escape = &post_data[poff];
556  poff++;
557  break;
558  case '0':
559  case '1':
560  case '2':
561  case '3':
562  case '4':
563  case '5':
564  case '6':
565  case '7':
566  case '8':
567  case '9':
568  /* character, may be part of escaping */
569  poff++;
570  continue;
571  default:
572  /* normal character, no more escaping! */
573  last_escape = NULL;
574  poff++;
575  continue;
576  }
577  break; /* end PP_ProcessValue */
578  case PP_Done:
579  switch (post_data[poff]) {
580  case '\n':
581  case '\r':
582  poff++;
583  continue;
584  }
585  /* unexpected data at the end, fail! */
586  pp->state = PP_Error;
587  break;
588  case PP_Callback:
589  if ( (pp->buffer_pos + (end_key - start_key) >
590  pp->buffer_size) ||
591  (pp->buffer_pos + (end_key - start_key) <
592  pp->buffer_pos) )
593  {
594  /* key too long, cannot parse! */
595  pp->state = PP_Error;
596  continue;
597  }
598  /* compute key, if we have not already */
599  if (NULL != start_key)
600  {
601  memcpy (&kbuf[pp->buffer_pos],
602  start_key,
603  end_key - start_key);
604  pp->buffer_pos += end_key - start_key;
605  start_key = NULL;
606  end_key = NULL;
607  pp->must_unescape_key = true;
608  }
609  if (pp->must_unescape_key)
610  {
611  kbuf[pp->buffer_pos] = '\0'; /* 0-terminate key */
612  MHD_unescape_plus (kbuf);
613  MHD_http_unescape (kbuf);
614  pp->must_unescape_key = false;
615  }
616  process_value (pp,
617  start_value,
618  end_value,
619  NULL);
620  pp->value_offset = 0;
621  start_value = NULL;
622  end_value = NULL;
623  pp->buffer_pos = 0;
624  pp->state = PP_Init;
625  break;
626  default:
628  __FILE__,
629  __LINE__,
630  NULL); /* should never happen! */
631  }
632  }
633 
634  /* save remaining data for next iteration */
635  if (NULL != start_key)
636  {
637  if (NULL == end_key)
638  end_key = &post_data[poff];
639  memcpy (&kbuf[pp->buffer_pos],
640  start_key,
641  end_key - start_key);
642  pp->buffer_pos += end_key - start_key;
643  pp->must_unescape_key = true;
644  start_key = NULL;
645  end_key = NULL;
646  }
647  if ( (NULL != start_value) &&
648  (PP_ProcessValue == pp->state) )
649  {
650  /* compute key, if we have not already */
651  if (pp->must_unescape_key)
652  {
653  kbuf[pp->buffer_pos] = '\0'; /* 0-terminate key */
654  MHD_unescape_plus (kbuf);
655  MHD_http_unescape (kbuf);
656  pp->must_unescape_key = false;
657  }
658  if (NULL == end_value)
659  end_value = &post_data[poff];
660  process_value (pp,
661  start_value,
662  end_value,
663  last_escape);
664  pp->must_ikvi = false;
665  }
666  return MHD_YES;
667 }
668 
669 
680 static int
681 try_match_header (const char *prefix,
682  size_t prefix_len,
683  char *line,
684  char **suffix)
685 {
686  if (NULL != *suffix)
687  return MHD_NO;
688  while (0 != *line)
689  {
690  if (MHD_str_equal_caseless_n_ (prefix,
691  line,
692  prefix_len))
693  {
694  *suffix = strdup (&line[prefix_len]);
695  return MHD_YES;
696  }
697  ++line;
698  }
699  return MHD_NO;
700 }
701 
702 
716 static int
717 find_boundary (struct MHD_PostProcessor *pp,
718  const char *boundary,
719  size_t blen,
720  size_t *ioffptr,
721  enum PP_State next_state,
722  enum PP_State next_dash_state)
723 {
724  char *buf = (char *) &pp[1];
725  const char *dash;
726 
727  if (pp->buffer_pos < 2 + blen)
728  {
729  if (pp->buffer_pos == pp->buffer_size)
730  pp->state = PP_Error; /* out of memory */
731  /* ++(*ioffptr); */
732  return MHD_NO; /* not enough data */
733  }
734  if ( (0 != memcmp ("--",
735  buf,
736  2)) ||
737  (0 != memcmp (&buf[2],
738  boundary,
739  blen)))
740  {
741  if (pp->state != PP_Init)
742  {
743  /* garbage not allowed */
744  pp->state = PP_Error;
745  }
746  else
747  {
748  /* skip over garbage (RFC 2046, 5.1.1) */
749  dash = memchr (buf,
750  '-',
751  pp->buffer_pos);
752  if (NULL == dash)
753  (*ioffptr) += pp->buffer_pos; /* skip entire buffer */
754  else if (dash == buf)
755  (*ioffptr)++; /* at least skip one byte */
756  else
757  (*ioffptr) += dash - buf; /* skip to first possible boundary */
758  }
759  return MHD_NO; /* expected boundary */
760  }
761  /* remove boundary from buffer */
762  (*ioffptr) += 2 + blen;
763  /* next: start with headers */
764  pp->skip_rn = RN_Dash;
765  pp->state = next_state;
766  pp->dash_state = next_dash_state;
767  return MHD_YES;
768 }
769 
770 
777 static void
778 try_get_value (const char *buf,
779  const char *key,
780  char **destination)
781 {
782  const char *spos;
783  const char *bpos;
784  const char *endv;
785  size_t klen;
786  size_t vlen;
787 
788  if (NULL != *destination)
789  return;
790  bpos = buf;
791  klen = strlen (key);
792  while (NULL != (spos = strstr (bpos, key)))
793  {
794  if ( (spos[klen] != '=') ||
795  ( (spos != buf) &&
796  (spos[-1] != ' ') ) )
797  {
798  /* no match */
799  bpos = spos + 1;
800  continue;
801  }
802  if (spos[klen + 1] != '"')
803  return; /* not quoted */
804  if (NULL == (endv = strchr (&spos[klen + 2],
805  '\"')))
806  return; /* no end-quote */
807  vlen = endv - spos - klen - 1;
808  *destination = malloc (vlen);
809  if (NULL == *destination)
810  return; /* out of memory */
811  (*destination)[vlen - 1] = '\0';
812  memcpy (*destination,
813  &spos[klen + 2],
814  vlen - 1);
815  return; /* success */
816  }
817 }
818 
819 
835 static int
836 process_multipart_headers (struct MHD_PostProcessor *pp,
837  size_t *ioffptr,
838  enum PP_State next_state)
839 {
840  char *buf = (char *) &pp[1];
841  size_t newline;
842 
843  newline = 0;
844  while ( (newline < pp->buffer_pos) &&
845  (buf[newline] != '\r') &&
846  (buf[newline] != '\n') )
847  newline++;
848  if (newline == pp->buffer_size)
849  {
850  pp->state = PP_Error;
851  return MHD_NO; /* out of memory */
852  }
853  if (newline == pp->buffer_pos)
854  return MHD_NO; /* will need more data */
855  if (0 == newline)
856  {
857  /* empty line - end of headers */
858  pp->skip_rn = RN_Full;
859  pp->state = next_state;
860  return MHD_YES;
861  }
862  /* got an actual header */
863  if (buf[newline] == '\r')
864  pp->skip_rn = RN_OptN;
865  buf[newline] = '\0';
866  if (MHD_str_equal_caseless_n_ ("Content-disposition: ",
867  buf,
868  MHD_STATICSTR_LEN_ ("Content-disposition: ")))
869  {
870  try_get_value (&buf[MHD_STATICSTR_LEN_ ("Content-disposition: ")],
871  "name",
872  &pp->content_name);
873  try_get_value (&buf[MHD_STATICSTR_LEN_ ("Content-disposition: ")],
874  "filename",
875  &pp->content_filename);
876  }
877  else
878  {
879  try_match_header ("Content-type: ",
880  MHD_STATICSTR_LEN_ ("Content-type: "),
881  buf,
882  &pp->content_type);
883  try_match_header ("Content-Transfer-Encoding: ",
884  MHD_STATICSTR_LEN_ ("Content-Transfer-Encoding: "),
885  buf,
886  &pp->content_transfer_encoding);
887  }
888  (*ioffptr) += newline + 1;
889  return MHD_YES;
890 }
891 
892 
909 static int
910 process_value_to_boundary (struct MHD_PostProcessor *pp,
911  size_t *ioffptr,
912  const char *boundary,
913  size_t blen,
914  enum PP_State next_state,
915  enum PP_State next_dash_state)
916 {
917  char *buf = (char *) &pp[1];
918  size_t newline;
919  const char *r;
920 
921  /* all data in buf until the boundary
922  (\r\n--+boundary) is part of the value */
923  newline = 0;
924  while (1)
925  {
926  while (newline + 4 < pp->buffer_pos)
927  {
928  r = memchr (&buf[newline],
929  '\r',
930  pp->buffer_pos - newline - 4);
931  if (NULL == r)
932  {
933  newline = pp->buffer_pos - 4;
934  break;
935  }
936  newline = r - buf;
937  if (0 == memcmp ("\r\n--",
938  &buf[newline],
939  4))
940  break;
941  newline++;
942  }
943  if (newline + blen + 4 <= pp->buffer_pos)
944  {
945  /* can check boundary */
946  if (0 != memcmp (&buf[newline + 4],
947  boundary,
948  blen))
949  {
950  /* no boundary, "\r\n--" is part of content, skip */
951  newline += 4;
952  continue;
953  }
954  else
955  {
956  /* boundary found, process until newline then
957  skip boundary and go back to init */
958  pp->skip_rn = RN_Dash;
959  pp->state = next_state;
960  pp->dash_state = next_dash_state;
961  (*ioffptr) += blen + 4; /* skip boundary as well */
962  buf[newline] = '\0';
963  break;
964  }
965  }
966  else
967  {
968  /* cannot check for boundary, process content that
969  we have and check again later; except, if we have
970  no content, abort (out of memory) */
971  if ( (0 == newline) &&
972  (pp->buffer_pos == pp->buffer_size) )
973  {
974  pp->state = PP_Error;
975  return MHD_NO;
976  }
977  break;
978  }
979  }
980  /* newline is either at beginning of boundary or
981  at least at the last character that we are sure
982  is not part of the boundary */
983  if ( ( (pp->must_ikvi) ||
984  (0 != newline) ) &&
985  (MHD_NO == pp->ikvi (pp->cls,
987  pp->content_name,
988  pp->content_filename,
989  pp->content_type,
990  pp->content_transfer_encoding,
991  buf,
992  pp->value_offset,
993  newline)) )
994  {
995  pp->state = PP_Error;
996  return MHD_NO;
997  }
998  pp->must_ikvi = false;
999  pp->value_offset += newline;
1000  (*ioffptr) += newline;
1001  return MHD_YES;
1002 }
1003 
1004 
1009 static void
1010 free_unmarked (struct MHD_PostProcessor *pp)
1011 {
1012  if ( (NULL != pp->content_name) &&
1013  (0 == (pp->have & NE_content_name)) )
1014  {
1015  free (pp->content_name);
1016  pp->content_name = NULL;
1017  }
1018  if ( (NULL != pp->content_type) &&
1019  (0 == (pp->have & NE_content_type)) )
1020  {
1021  free (pp->content_type);
1022  pp->content_type = NULL;
1023  }
1024  if ( (NULL != pp->content_filename) &&
1025  (0 == (pp->have & NE_content_filename)) )
1026  {
1027  free (pp->content_filename);
1028  pp->content_filename = NULL;
1029  }
1030  if ( (NULL != pp->content_transfer_encoding) &&
1031  (0 == (pp->have & NE_content_transfer_encoding)) )
1032  {
1033  free (pp->content_transfer_encoding);
1034  pp->content_transfer_encoding = NULL;
1035  }
1036 }
1037 
1038 
1047 static int
1048 post_process_multipart (struct MHD_PostProcessor *pp,
1049  const char *post_data,
1050  size_t post_data_len)
1051 {
1052  char *buf;
1053  size_t max;
1054  size_t ioff;
1055  size_t poff;
1056  int state_changed;
1057 
1058  buf = (char *) &pp[1];
1059  ioff = 0;
1060  poff = 0;
1061  state_changed = 1;
1062  while ( (poff < post_data_len) ||
1063  ( (pp->buffer_pos > 0) &&
1064  (0 != state_changed) ) )
1065  {
1066  /* first, move as much input data
1067  as possible to our internal buffer */
1068  max = pp->buffer_size - pp->buffer_pos;
1069  if (max > post_data_len - poff)
1070  max = post_data_len - poff;
1071  memcpy (&buf[pp->buffer_pos],
1072  &post_data[poff],
1073  max);
1074  poff += max;
1075  pp->buffer_pos += max;
1076  if ( (0 == max) &&
1077  (0 == state_changed) &&
1078  (poff < post_data_len) )
1079  {
1080  pp->state = PP_Error;
1081  return MHD_NO; /* out of memory */
1082  }
1083  state_changed = 0;
1084 
1085  /* first state machine for '\r'-'\n' and '--' handling */
1086  switch (pp->skip_rn)
1087  {
1088  case RN_Inactive:
1089  break;
1090  case RN_OptN:
1091  if (buf[0] == '\n')
1092  {
1093  ioff++;
1094  pp->skip_rn = RN_Inactive;
1095  goto AGAIN;
1096  }
1097  /* fall-through! */
1098  case RN_Dash:
1099  if (buf[0] == '-')
1100  {
1101  ioff++;
1102  pp->skip_rn = RN_Dash2;
1103  goto AGAIN;
1104  }
1105  pp->skip_rn = RN_Full;
1106  /* fall-through! */
1107  case RN_Full:
1108  if (buf[0] == '\r')
1109  {
1110  if ( (pp->buffer_pos > 1) &&
1111  ('\n' == buf[1]) )
1112  {
1113  pp->skip_rn = RN_Inactive;
1114  ioff += 2;
1115  }
1116  else
1117  {
1118  pp->skip_rn = RN_OptN;
1119  ioff++;
1120  }
1121  goto AGAIN;
1122  }
1123  if (buf[0] == '\n')
1124  {
1125  ioff++;
1126  pp->skip_rn = RN_Inactive;
1127  goto AGAIN;
1128  }
1129  pp->skip_rn = RN_Inactive;
1130  pp->state = PP_Error;
1131  return MHD_NO; /* no '\r\n' */
1132  case RN_Dash2:
1133  if (buf[0] == '-')
1134  {
1135  ioff++;
1136  pp->skip_rn = RN_Full;
1137  pp->state = pp->dash_state;
1138  goto AGAIN;
1139  }
1140  pp->state = PP_Error;
1141  break;
1142  }
1143 
1144  /* main state engine */
1145  switch (pp->state)
1146  {
1147  case PP_Error:
1148  return MHD_NO;
1149  case PP_Done:
1150  /* did not expect to receive more data */
1151  pp->state = PP_Error;
1152  return MHD_NO;
1153  case PP_Init:(void) find_boundary (pp,
1165  pp->boundary,
1166  pp->blen,
1167  &ioff,
1169  PP_Done);
1170  break;
1171  case PP_NextBoundary:
1172  if (MHD_NO == find_boundary (pp,
1173  pp->boundary,
1174  pp->blen,
1175  &ioff,
1177  PP_Done))
1178  {
1179  if (pp->state == PP_Error)
1180  return MHD_NO;
1181  goto END;
1182  }
1183  break;
1185  pp->must_ikvi = true;
1186  if (MHD_NO ==
1188  &ioff,
1190  {
1191  if (pp->state == PP_Error)
1192  return MHD_NO;
1193  else
1194  goto END;
1195  }
1196  state_changed = 1;
1197  break;
1199  if ( (NULL != pp->content_type) &&
1200  (MHD_str_equal_caseless_n_ (pp->content_type,
1201  "multipart/mixed",
1202  MHD_STATICSTR_LEN_ ("multipart/mixed"))))
1203  {
1204  pp->nested_boundary = strstr (pp->content_type,
1205  "boundary=");
1206  if (NULL == pp->nested_boundary)
1207  {
1208  pp->state = PP_Error;
1209  return MHD_NO;
1210  }
1211  pp->nested_boundary =
1212  strdup (&pp->nested_boundary[MHD_STATICSTR_LEN_ ("boundary=")]);
1213  if (NULL == pp->nested_boundary)
1214  {
1215  /* out of memory */
1216  pp->state = PP_Error;
1217  return MHD_NO;
1218  }
1219  /* free old content type, we will need that field
1220  for the content type of the nested elements */
1221  free (pp->content_type);
1222  pp->content_type = NULL;
1223  pp->nlen = strlen (pp->nested_boundary);
1224  pp->state = PP_Nested_Init;
1225  state_changed = 1;
1226  break;
1227  }
1228  pp->state = PP_ProcessValueToBoundary;
1229  pp->value_offset = 0;
1230  state_changed = 1;
1231  break;
1233  if (MHD_NO == process_value_to_boundary (pp,
1234  &ioff,
1235  pp->boundary,
1236  pp->blen,
1238  PP_Done))
1239  {
1240  if (pp->state == PP_Error)
1241  return MHD_NO;
1242  break;
1243  }
1244  break;
1245  case PP_PerformCleanup:
1246  /* clean up state of one multipart form-data element! */
1247  pp->have = NE_none;
1248  free_unmarked (pp);
1249  if (NULL != pp->nested_boundary)
1250  {
1251  free (pp->nested_boundary);
1252  pp->nested_boundary = NULL;
1253  }
1254  pp->state = PP_ProcessEntryHeaders;
1255  state_changed = 1;
1256  break;
1257  case PP_Nested_Init:
1258  if (NULL == pp->nested_boundary)
1259  {
1260  pp->state = PP_Error;
1261  return MHD_NO;
1262  }
1263  if (MHD_NO == find_boundary (pp,
1264  pp->nested_boundary,
1265  pp->nlen,
1266  &ioff,
1268  PP_NextBoundary /* or PP_Error? */))
1269  {
1270  if (pp->state == PP_Error)
1271  return MHD_NO;
1272  goto END;
1273  }
1274  break;
1276  /* remember what headers were given
1277  globally */
1278  pp->have = NE_none;
1279  if (NULL != pp->content_name)
1280  pp->have |= NE_content_name;
1281  if (NULL != pp->content_type)
1282  pp->have |= NE_content_type;
1283  if (NULL != pp->content_filename)
1284  pp->have |= NE_content_filename;
1285  if (NULL != pp->content_transfer_encoding)
1286  pp->have |= NE_content_transfer_encoding;
1287  pp->state = PP_Nested_ProcessEntryHeaders;
1288  state_changed = 1;
1289  break;
1291  pp->value_offset = 0;
1292  if (MHD_NO ==
1294  &ioff,
1296  {
1297  if (pp->state == PP_Error)
1298  return MHD_NO;
1299  else
1300  goto END;
1301  }
1302  state_changed = 1;
1303  break;
1305  if (MHD_NO == process_value_to_boundary (pp,
1306  &ioff,
1307  pp->nested_boundary,
1308  pp->nlen,
1310  PP_NextBoundary))
1311  {
1312  if (pp->state == PP_Error)
1313  return MHD_NO;
1314  break;
1315  }
1316  break;
1318  free_unmarked (pp);
1319  pp->state = PP_Nested_ProcessEntryHeaders;
1320  state_changed = 1;
1321  break;
1322  default:
1324  __FILE__,
1325  __LINE__,
1326  NULL); /* should never happen! */
1327  }
1328 AGAIN:
1329  if (ioff > 0)
1330  {
1331  memmove (buf,
1332  &buf[ioff],
1333  pp->buffer_pos - ioff);
1334  pp->buffer_pos -= ioff;
1335  ioff = 0;
1336  state_changed = 1;
1337  }
1338  }
1339 END:
1340  if (0 != ioff)
1341  {
1342  memmove (buf,
1343  &buf[ioff],
1344  pp->buffer_pos - ioff);
1345  pp->buffer_pos -= ioff;
1346  }
1347  if (poff < post_data_len)
1348  {
1349  pp->state = PP_Error;
1350  return MHD_NO; /* serious error */
1351  }
1352  return MHD_YES;
1353 }
1354 
1355 
1369 int
1370 MHD_post_process (struct MHD_PostProcessor *pp,
1371  const char *post_data,
1372  size_t post_data_len)
1373 {
1374  if (0 == post_data_len)
1375  return MHD_YES;
1376  if (NULL == pp)
1377  return MHD_NO;
1379  pp->encoding,
1382  return post_process_urlencoded (pp,
1383  post_data,
1384  post_data_len);
1386  pp->encoding,
1389  return post_process_multipart (pp,
1390  post_data,
1391  post_data_len);
1392  /* this should never be reached */
1393  return MHD_NO;
1394 }
1395 
1396 
1407 int
1408 MHD_destroy_post_processor (struct MHD_PostProcessor *pp)
1409 {
1410  int ret;
1411 
1412  if (NULL == pp)
1413  return MHD_YES;
1414  if (PP_ProcessValue == pp->state)
1415  {
1416  /* key without terminated value left at the end of the
1417  buffer; fake receiving a termination character to
1418  ensure it is also processed */
1420  "\n",
1421  1);
1422  }
1423  /* These internal strings need cleaning up since
1424  the post-processing may have been interrupted
1425  at any stage */
1426  if ( (pp->xbuf_pos > 0) ||
1427  (pp->state != PP_Done) )
1428  ret = MHD_NO;
1429  else
1430  ret = MHD_YES;
1431  pp->have = NE_none;
1432  free_unmarked (pp);
1433  if (NULL != pp->nested_boundary)
1434  free (pp->nested_boundary);
1435  free (pp);
1436  return ret;
1437 }
1438 
1439 
1440 /* end of postprocessor.c */
RN_Full
@ RN_Full
Definition: postprocessor.c:86
mhd_compat.h
Header for platform missing functions.
NE_State
NE_State
Definition: postprocessor.c:106
PP_Nested_ProcessValueToBoundary
@ PP_Nested_ProcessValueToBoundary
Definition: postprocessor.c:63
process_multipart_headers
static int process_multipart_headers(struct MHD_PostProcessor *pp, size_t *ioffptr, enum PP_State next_state)
Definition: postprocessor.c:836
MHD_YES
#define MHD_YES
Definition: microhttpd.h:140
MHD_unescape_plus
void MHD_unescape_plus(char *arg)
Definition: internal.c:123
mhd_panic_cls
void * mhd_panic_cls
Definition: panic.c:36
MHD_post_process
_MHD_EXTERN int MHD_post_process(struct MHD_PostProcessor *pp, const char *post_data, size_t post_data_len)
Definition: postprocessor.c:1370
PP_Nested_ProcessEntryHeaders
@ PP_Nested_ProcessEntryHeaders
Definition: postprocessor.c:62
MHD_HTTP_POST_ENCODING_FORM_URLENCODED
#define MHD_HTTP_POST_ENCODING_FORM_URLENCODED
Definition: microhttpd.h:981
MHD_PostDataIterator
int(* 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:2354
NE_content_transfer_encoding
@ NE_content_transfer_encoding
Definition: postprocessor.c:112
MHD_calloc_
void * MHD_calloc_(size_t nelem, size_t elsize)
Definition: mhd_compat.c:98
PP_Init
@ PP_Init
Definition: postprocessor.c:45
PP_ExpectNewLine
@ PP_ExpectNewLine
Definition: postprocessor.c:51
RN_OptN
@ RN_OptN
Definition: postprocessor.c:80
NE_content_type
@ NE_content_type
Definition: postprocessor.c:110
PP_Nested_PerformMarking
@ PP_Nested_PerformMarking
Definition: postprocessor.c:61
internal.h
internal shared structures
MHD_lookup_connection_value_n
_MHD_EXTERN int 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:566
RN_Inactive
@ RN_Inactive
Definition: postprocessor.c:74
NULL
#define NULL
Definition: reason_phrase.c:30
PP_PerformCheckMultipart
@ PP_PerformCheckMultipart
Definition: postprocessor.c:55
MHD_HTTP_HEADER_CONTENT_TYPE
#define MHD_HTTP_HEADER_CONTENT_TYPE
Definition: microhttpd.h:572
free_unmarked
static void free_unmarked(struct MHD_PostProcessor *pp)
Definition: postprocessor.c:1010
PP_PerformCleanup
@ PP_PerformCleanup
Definition: postprocessor.c:57
find_boundary
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)
Definition: postprocessor.c:717
MHD_Connection::state
enum MHD_CONNECTION_STATE state
Definition: internal.h:924
NE_content_name
@ NE_content_name
Definition: postprocessor.c:109
NE_none
@ NE_none
Definition: postprocessor.c:108
try_match_header
static int try_match_header(const char *prefix, size_t prefix_len, char *line, char **suffix)
Definition: postprocessor.c:681
PP_Nested_PerformCleanup
@ PP_Nested_PerformCleanup
Definition: postprocessor.c:64
mhd_assert
#define mhd_assert(CHK)
Definition: mhd_assert.h:39
MHD_POSTDATA_KIND
@ MHD_POSTDATA_KIND
Definition: microhttpd.h:1789
MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA
#define MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA
Definition: microhttpd.h:983
MHD_http_unescape
_MHD_EXTERN size_t MHD_http_unescape(char *val)
Definition: internal.c:142
RN_State
RN_State
Definition: postprocessor.c:69
PP_ProcessEntryHeaders
@ PP_ProcessEntryHeaders
Definition: postprocessor.c:54
try_get_value
static void try_get_value(const char *buf, const char *key, char **destination)
Definition: postprocessor.c:778
MHD_STATICSTR_LEN_
#define MHD_STATICSTR_LEN_(macro)
Definition: mhd_str.h:45
mhd_str.h
Header for string manipulating helpers.
MHD_create_post_processor
_MHD_EXTERN struct MHD_PostProcessor * MHD_create_post_processor(struct MHD_Connection *connection, size_t buffer_size, MHD_PostDataIterator iter, void *iter_cls)
Definition: postprocessor.c:280
MHD_destroy_post_processor
_MHD_EXTERN int MHD_destroy_post_processor(struct MHD_PostProcessor *pp)
Definition: postprocessor.c:1408
PP_NextBoundary
@ PP_NextBoundary
Definition: postprocessor.c:46
MHD_HEADER_KIND
@ MHD_HEADER_KIND
Definition: microhttpd.h:1773
XBUF_SIZE
#define XBUF_SIZE
Definition: postprocessor.c:35
PP_Error
@ PP_Error
Definition: postprocessor.c:43
post_process_multipart
static int post_process_multipart(struct MHD_PostProcessor *pp, const char *post_data, size_t post_data_len)
Definition: postprocessor.c:1048
PP_Nested_Init
@ PP_Nested_Init
Definition: postprocessor.c:60
MHD_Connection
Definition: internal.h:633
PP_ProcessValue
@ PP_ProcessValue
Definition: postprocessor.c:49
post_process_urlencoded
static int post_process_urlencoded(struct MHD_PostProcessor *pp, const char *post_data, size_t post_data_len)
Definition: postprocessor.c:464
RN_Dash
@ RN_Dash
Definition: postprocessor.c:92
PP_State
PP_State
Definition: postprocessor.c:40
MHD_NO
#define MHD_NO
Definition: microhttpd.h:145
PP_ProcessValueToBoundary
@ PP_ProcessValueToBoundary
Definition: postprocessor.c:56
PP_Callback
@ PP_Callback
Definition: postprocessor.c:50
RN_Dash2
@ RN_Dash2
Definition: postprocessor.c:97
process_value
static void process_value(struct MHD_PostProcessor *pp, const char *value_start, const char *value_end, const char *last_escape)
Definition: postprocessor.c:378
NE_content_filename
@ NE_content_filename
Definition: postprocessor.c:111
mhd_panic
MHD_PanicCallback mhd_panic
Definition: panic.c:31
MHD_str_equal_caseless_n_
int MHD_str_equal_caseless_n_(const char *const str1, const char *const str2, size_t maxlen)
Definition: mhd_str.c:378
PP_Done
@ PP_Done
Definition: postprocessor.c:44
process_value_to_boundary
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)
Definition: postprocessor.c:910