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 
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 
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 
278 struct 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 
376 static void
377 process_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 
462 static int
463 post_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 
693 static int
694 try_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 
729 static int
730 find_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 
790 static void
791 try_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 
848 static int
849 process_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 
922 static int
923 process_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 
1022 static void
1023 free_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 
1060 static int
1061 post_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;
1246  if (MHD_NO == process_value_to_boundary (pp,
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;
1300  pp->state = PP_Nested_ProcessEntryHeaders;
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;
1318  if (MHD_NO == process_value_to_boundary (pp,
1319  &ioff,
1320  pp->nested_boundary,
1321  pp->nlen,
1323  PP_NextBoundary))
1324  {
1325  if (pp->state == PP_Error)
1326  return MHD_NO;
1327  break;
1328  }
1329  break;
1331  free_unmarked (pp);
1332  pp->state = PP_Nested_ProcessEntryHeaders;
1333  state_changed = 1;
1334  break;
1335  default:
1337  __FILE__,
1338  __LINE__,
1339  NULL); /* should never happen! */
1340  }
1341 AGAIN:
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  }
1352 END:
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 
1382 enum MHD_Result
1383 MHD_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 
1420 enum MHD_Result
1421 MHD_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 */
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
int MHD_str_equal_caseless_n_(const char *const str1, const char *const str2, size_t maxlen)
Definition: mhd_str.c:378
Header for platform missing functions.
enum MHD_CONNECTION_STATE state
Definition: internal.h:924
void * mhd_panic_cls
Definition: panic.c:36
MHD_PanicCallback mhd_panic
Definition: panic.c:31
_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_calloc_(size_t nelem, size_t elsize)
Definition: mhd_compat.c:98
PP_State
Definition: postprocessor.c:40
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)
static int process_multipart_headers(struct MHD_PostProcessor *pp, size_t *ioffptr, enum PP_State next_state)
_MHD_EXTERN struct MHD_PostProcessor * MHD_create_post_processor(struct MHD_Connection *connection, size_t buffer_size, MHD_PostDataIterator iter, void *iter_cls)
static int try_match_header(const char *prefix, size_t prefix_len, char *line, char **suffix)
internal shared structures
_MHD_EXTERN enum MHD_Result MHD_destroy_post_processor(struct MHD_PostProcessor *pp)
_MHD_EXTERN enum MHD_Result MHD_post_process(struct MHD_PostProcessor *pp, const char *post_data, size_t post_data_len)
#define NULL
Definition: reason_phrase.c:30
Header for string manipulating helpers.
#define MHD_STATICSTR_LEN_(macro)
Definition: mhd_str.h:45
static int post_process_urlencoded(struct MHD_PostProcessor *pp, const char *post_data, size_t post_data_len)
MHD_Result
Definition: microhttpd.h:140
#define mhd_assert(CHK)
Definition: mhd_assert.h:39
static int post_process_multipart(struct MHD_PostProcessor *pp, const char *post_data, size_t post_data_len)
#define MHD_HTTP_POST_ENCODING_FORM_URLENCODED
Definition: microhttpd.h:989
NE_State
static void free_unmarked(struct MHD_PostProcessor *pp)
static void process_value(struct MHD_PostProcessor *pp, const char *value_start, const char *value_end, const char *last_escape)
RN_State
Definition: postprocessor.c:69
#define MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA
Definition: microhttpd.h:991
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 MHD_HTTP_HEADER_CONTENT_TYPE
Definition: microhttpd.h:580
void MHD_unescape_plus(char *arg)
Definition: internal.c:123
_MHD_EXTERN size_t MHD_http_unescape(char *val)
Definition: internal.c:142
#define XBUF_SIZE
Definition: postprocessor.c:35
static void try_get_value(const char *buf, const char *key, char **destination)