GNU libmicrohttpd  0.9.65
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 */
51 
52  /* post encoding-states */
57 
58  /* nested post-encoding states */
64 
65 };
66 
67 
69 {
74 
79  RN_OptN = 1,
80 
85  RN_Full = 2,
86 
91  RN_Dash = 3,
92 
97 };
98 
99 
106 {
107  NE_none = 0,
112 };
113 
114 
119 struct MHD_PostProcessor
120 {
121 
126  struct MHD_Connection *connection;
127 
132 
136  void *cls;
137 
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 
178  char xbuf[8];
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  int must_ikvi;
219 
223  enum PP_State state;
224 
231  enum RN_State skip_rn;
232 
237  enum PP_State dash_state;
238 
243  enum NE_State have;
244 
245 };
246 
247 
273 struct MHD_PostProcessor *
275  size_t buffer_size,
277  void *iter_cls)
278 {
279  struct MHD_PostProcessor *ret;
280  const char *encoding;
281  const char *boundary;
282  size_t blen;
283 
284  if ( (buffer_size < 256) ||
285  (NULL == connection) ||
286  (NULL == iter))
288  __FILE__,
289  __LINE__,
290  NULL);
291  if (MHD_NO == MHD_lookup_connection_value_n (connection,
295  &encoding,
296  NULL))
297  return NULL;
298  boundary = NULL;
300  encoding,
302  {
304  encoding,
306  return NULL;
307  boundary =
309  /* Q: should this be "strcasestr"? */
310  boundary = strstr (boundary, "boundary=");
311  if (NULL == boundary)
312  return NULL; /* failed to determine boundary */
313  boundary += MHD_STATICSTR_LEN_ ("boundary=");
314  blen = strlen (boundary);
315  if ( (blen == 0) ||
316  (blen * 2 + 2 > buffer_size) )
317  return NULL; /* (will be) out of memory or invalid boundary */
318  if ( (boundary[0] == '"') &&
319  (boundary[blen - 1] == '"') )
320  {
321  /* remove enclosing quotes */
322  ++boundary;
323  blen -= 2;
324  }
325  }
326  else
327  blen = 0;
328  buffer_size += 4; /* round up to get nice block sizes despite boundary search */
329 
330  /* add +1 to ensure we ALWAYS have a zero-termination at the end */
331  if (NULL == (ret = MHD_calloc_ (1, sizeof (struct MHD_PostProcessor) + buffer_size + 1)))
332  return NULL;
333  ret->connection = connection;
334  ret->ikvi = iter;
335  ret->cls = iter_cls;
336  ret->encoding = encoding;
337  ret->buffer_size = buffer_size;
338  ret->state = PP_Init;
339  ret->blen = blen;
340  ret->boundary = boundary;
341  ret->skip_rn = RN_Inactive;
342  return ret;
343 }
344 
345 
354 static int
355 post_process_urlencoded (struct MHD_PostProcessor *pp,
356  const char *post_data,
357  size_t post_data_len)
358 {
359  size_t equals;
360  size_t amper;
361  size_t poff;
362  size_t xoff;
363  size_t delta;
364  int end_of_value_found;
365  char *buf;
366  char xbuf[XBUF_SIZE + 1];
367 
368  buf = (char *) &pp[1];
369  poff = 0;
370  while (poff < post_data_len)
371  {
372  switch (pp->state)
373  {
374  case PP_Error:
375  return MHD_NO;
376  case PP_Done:
377  /* did not expect to receive more data */
378  pp->state = PP_Error;
379  return MHD_NO;
380  case PP_Init:
381  equals = 0;
382  while ((equals + poff < post_data_len) &&
383  (post_data[equals + poff] != '='))
384  equals++;
385  if (equals + pp->buffer_pos > pp->buffer_size)
386  {
387  pp->state = PP_Error; /* out of memory */
388  return MHD_NO;
389  }
390  memcpy (&buf[pp->buffer_pos], &post_data[poff], equals);
391  pp->buffer_pos += equals;
392  if (equals + poff == post_data_len)
393  return MHD_YES; /* no '=' yet */
394  buf[pp->buffer_pos] = '\0'; /* 0-terminate key */
395  pp->buffer_pos = 0; /* reset for next key */
396  MHD_unescape_plus (buf);
397  MHD_http_unescape (buf);
398  poff += equals + 1;
399  pp->state = PP_ProcessValue;
400  pp->value_offset = 0;
401  break;
402  case PP_ProcessValue:
403  /* obtain rest of value from previous iteration */
404  memcpy (xbuf, pp->xbuf, pp->xbuf_pos);
405  xoff = pp->xbuf_pos;
406  pp->xbuf_pos = 0;
407 
408  /* find last position in input buffer that is part of the value */
409  amper = 0;
410  while ((amper + poff < post_data_len) &&
411  (amper < XBUF_SIZE) &&
412  (post_data[amper + poff] != '&') &&
413  (post_data[amper + poff] != '\n') &&
414  (post_data[amper + poff] != '\r'))
415  amper++;
416  end_of_value_found = ((amper + poff < post_data_len) &&
417  ((post_data[amper + poff] == '&') ||
418  (post_data[amper + poff] == '\n') ||
419  (post_data[amper + poff] == '\r')));
420  /* compute delta, the maximum number of bytes that we will be able to
421  process right now (either amper-limited of xbuf-size limited) */
422  delta = amper;
423  if (delta > XBUF_SIZE - xoff)
424  delta = XBUF_SIZE - xoff;
425 
426  /* move input into processing buffer */
427  memcpy (&xbuf[xoff], &post_data[poff], delta);
428  xoff += delta;
429  poff += delta;
430 
431  /* find if escape sequence is at the end of the processing buffer;
432  if so, exclude those from processing (reduce delta to point at
433  end of processed region) */
434  delta = xoff;
435  if ((delta > 0) &&
436  ('%' == xbuf[delta - 1]))
437  delta--;
438  else if ((delta > 1) &&
439  ('%' == xbuf[delta - 2]))
440  delta -= 2;
441 
442  /* if we have an incomplete escape sequence, save it to
443  pp->xbuf for later */
444  if (delta < xoff)
445  {
446  memcpy (pp->xbuf,
447  &xbuf[delta],
448  xoff - delta);
449  pp->xbuf_pos = xoff - delta;
450  xoff = delta;
451  }
452 
453  /* If we have nothing to do (delta == 0) and
454  not just because the value is empty (are
455  waiting for more data), go for next iteration */
456  if ( (0 == xoff) &&
457  (poff == post_data_len))
458  continue;
459 
460  /* unescape */
461  xbuf[xoff] = '\0'; /* 0-terminate in preparation */
462  MHD_unescape_plus (xbuf);
463  xoff = MHD_http_unescape (xbuf);
464  /* finally: call application! */
465  pp->must_ikvi = MHD_NO;
466  if (MHD_NO == pp->ikvi (pp->cls,
468  (const char *) &pp[1], /* key */
469  NULL,
470  NULL,
471  NULL,
472  xbuf,
473  pp->value_offset,
474  xoff))
475  {
476  pp->state = PP_Error;
477  return MHD_NO;
478  }
479  pp->value_offset += xoff;
480 
481  /* are we done with the value? */
482  if (end_of_value_found)
483  {
484  /* we found the end of the value! */
485  if ( ('\n' == post_data[poff]) ||
486  ('\r' == post_data[poff]) )
487  {
488  pp->state = PP_ExpectNewLine;
489  }
490  else if ('&' == post_data[poff])
491  {
492  poff++; /* skip '&' */
493  pp->state = PP_Init;
494  }
495  }
496  break;
497  case PP_ExpectNewLine:
498  if ( ('\n' == post_data[poff]) ||
499  ('\r' == post_data[poff]) )
500  {
501  poff++;
502  /* we are done, report error if we receive any more... */
503  pp->state = PP_Done;
504  return MHD_YES;
505  }
506  return MHD_NO;
507  default:
509  __FILE__,
510  __LINE__,
511  NULL); /* should never happen! */
512  }
513  }
514  return MHD_YES;
515 }
516 
517 
528 static int
529 try_match_header (const char *prefix,
530  size_t prefix_len,
531  char *line,
532  char **suffix)
533 {
534  if (NULL != *suffix)
535  return MHD_NO;
536  while (0 != *line)
537  {
538  if (MHD_str_equal_caseless_n_ (prefix,
539  line,
540  prefix_len))
541  {
542  *suffix = strdup (&line[prefix_len]);
543  return MHD_YES;
544  }
545  ++line;
546  }
547  return MHD_NO;
548 }
549 
550 
564 static int
565 find_boundary (struct MHD_PostProcessor *pp,
566  const char *boundary,
567  size_t blen,
568  size_t *ioffptr,
569  enum PP_State next_state,
570  enum PP_State next_dash_state)
571 {
572  char *buf = (char *) &pp[1];
573  const char *dash;
574 
575  if (pp->buffer_pos < 2 + blen)
576  {
577  if (pp->buffer_pos == pp->buffer_size)
578  pp->state = PP_Error; /* out of memory */
579  /* ++(*ioffptr); */
580  return MHD_NO; /* not enough data */
581  }
582  if ( (0 != memcmp ("--",
583  buf,
584  2)) ||
585  (0 != memcmp (&buf[2],
586  boundary,
587  blen)))
588  {
589  if (pp->state != PP_Init)
590  {
591  /* garbage not allowed */
592  pp->state = PP_Error;
593  }
594  else
595  {
596  /* skip over garbage (RFC 2046, 5.1.1) */
597  dash = memchr (buf,
598  '-',
599  pp->buffer_pos);
600  if (NULL == dash)
601  (*ioffptr) += pp->buffer_pos; /* skip entire buffer */
602  else
603  if (dash == buf)
604  (*ioffptr)++; /* at least skip one byte */
605  else
606  (*ioffptr) += dash - buf; /* skip to first possible boundary */
607  }
608  return MHD_NO; /* expected boundary */
609  }
610  /* remove boundary from buffer */
611  (*ioffptr) += 2 + blen;
612  /* next: start with headers */
613  pp->skip_rn = RN_Dash;
614  pp->state = next_state;
615  pp->dash_state = next_dash_state;
616  return MHD_YES;
617 }
618 
619 
626 static void
627 try_get_value (const char *buf,
628  const char *key,
629  char **destination)
630 {
631  const char *spos;
632  const char *bpos;
633  const char *endv;
634  size_t klen;
635  size_t vlen;
636 
637  if (NULL != *destination)
638  return;
639  bpos = buf;
640  klen = strlen (key);
641  while (NULL != (spos = strstr (bpos, key)))
642  {
643  if ( (spos[klen] != '=') ||
644  ( (spos != buf) &&
645  (spos[-1] != ' ') ) )
646  {
647  /* no match */
648  bpos = spos + 1;
649  continue;
650  }
651  if (spos[klen + 1] != '"')
652  return; /* not quoted */
653  if (NULL == (endv = strchr (&spos[klen + 2],
654  '\"')))
655  return; /* no end-quote */
656  vlen = endv - spos - klen - 1;
657  *destination = malloc (vlen);
658  if (NULL == *destination)
659  return; /* out of memory */
660  (*destination)[vlen - 1] = '\0';
661  memcpy (*destination,
662  &spos[klen + 2],
663  vlen - 1);
664  return; /* success */
665  }
666 }
667 
668 
684 static int
685 process_multipart_headers (struct MHD_PostProcessor *pp,
686  size_t *ioffptr,
687  enum PP_State next_state)
688 {
689  char *buf = (char *) &pp[1];
690  size_t newline;
691 
692  newline = 0;
693  while ( (newline < pp->buffer_pos) &&
694  (buf[newline] != '\r') &&
695  (buf[newline] != '\n') )
696  newline++;
697  if (newline == pp->buffer_size)
698  {
699  pp->state = PP_Error;
700  return MHD_NO; /* out of memory */
701  }
702  if (newline == pp->buffer_pos)
703  return MHD_NO; /* will need more data */
704  if (0 == newline)
705  {
706  /* empty line - end of headers */
707  pp->skip_rn = RN_Full;
708  pp->state = next_state;
709  return MHD_YES;
710  }
711  /* got an actual header */
712  if (buf[newline] == '\r')
713  pp->skip_rn = RN_OptN;
714  buf[newline] = '\0';
715  if (MHD_str_equal_caseless_n_ ("Content-disposition: ",
716  buf,
717  MHD_STATICSTR_LEN_ ("Content-disposition: ")))
718  {
719  try_get_value (&buf[MHD_STATICSTR_LEN_ ("Content-disposition: ")],
720  "name",
721  &pp->content_name);
722  try_get_value (&buf[MHD_STATICSTR_LEN_ ("Content-disposition: ")],
723  "filename",
724  &pp->content_filename);
725  }
726  else
727  {
728  try_match_header ("Content-type: ",
729  MHD_STATICSTR_LEN_("Content-type: "),
730  buf,
731  &pp->content_type);
732  try_match_header ("Content-Transfer-Encoding: ",
733  MHD_STATICSTR_LEN_("Content-Transfer-Encoding: "),
734  buf,
735  &pp->content_transfer_encoding);
736  }
737  (*ioffptr) += newline + 1;
738  return MHD_YES;
739 }
740 
741 
758 static int
759 process_value_to_boundary (struct MHD_PostProcessor *pp,
760  size_t *ioffptr,
761  const char *boundary,
762  size_t blen,
763  enum PP_State next_state,
764  enum PP_State next_dash_state)
765 {
766  char *buf = (char *) &pp[1];
767  size_t newline;
768  const char *r;
769 
770  /* all data in buf until the boundary
771  (\r\n--+boundary) is part of the value */
772  newline = 0;
773  while (1)
774  {
775  while (newline + 4 < pp->buffer_pos)
776  {
777  r = memchr (&buf[newline],
778  '\r',
779  pp->buffer_pos - newline - 4);
780  if (NULL == r)
781  {
782  newline = pp->buffer_pos - 4;
783  break;
784  }
785  newline = r - buf;
786  if (0 == memcmp ("\r\n--",
787  &buf[newline],
788  4))
789  break;
790  newline++;
791  }
792  if (newline + blen + 4 <= pp->buffer_pos)
793  {
794  /* can check boundary */
795  if (0 != memcmp (&buf[newline + 4],
796  boundary,
797  blen))
798  {
799  /* no boundary, "\r\n--" is part of content, skip */
800  newline += 4;
801  continue;
802  }
803  else
804  {
805  /* boundary found, process until newline then
806  skip boundary and go back to init */
807  pp->skip_rn = RN_Dash;
808  pp->state = next_state;
809  pp->dash_state = next_dash_state;
810  (*ioffptr) += blen + 4; /* skip boundary as well */
811  buf[newline] = '\0';
812  break;
813  }
814  }
815  else
816  {
817  /* cannot check for boundary, process content that
818  we have and check again later; except, if we have
819  no content, abort (out of memory) */
820  if ( (0 == newline) &&
821  (pp->buffer_pos == pp->buffer_size) )
822  {
823  pp->state = PP_Error;
824  return MHD_NO;
825  }
826  break;
827  }
828  }
829  /* newline is either at beginning of boundary or
830  at least at the last character that we are sure
831  is not part of the boundary */
832  if ( ( (MHD_YES == pp->must_ikvi) ||
833  (0 != newline) ) &&
834  (MHD_NO == pp->ikvi (pp->cls,
836  pp->content_name,
837  pp->content_filename,
838  pp->content_type,
839  pp->content_transfer_encoding,
840  buf,
841  pp->value_offset,
842  newline)) )
843  {
844  pp->state = PP_Error;
845  return MHD_NO;
846  }
847  pp->must_ikvi = MHD_NO;
848  pp->value_offset += newline;
849  (*ioffptr) += newline;
850  return MHD_YES;
851 }
852 
853 
858 static void
859 free_unmarked (struct MHD_PostProcessor *pp)
860 {
861  if ( (NULL != pp->content_name) &&
862  (0 == (pp->have & NE_content_name)) )
863  {
864  free (pp->content_name);
865  pp->content_name = NULL;
866  }
867  if ( (NULL != pp->content_type) &&
868  (0 == (pp->have & NE_content_type)) )
869  {
870  free (pp->content_type);
871  pp->content_type = NULL;
872  }
873  if ( (NULL != pp->content_filename) &&
874  (0 == (pp->have & NE_content_filename)) )
875  {
876  free (pp->content_filename);
877  pp->content_filename = NULL;
878  }
879  if ( (NULL != pp->content_transfer_encoding) &&
880  (0 == (pp->have & NE_content_transfer_encoding)) )
881  {
882  free (pp->content_transfer_encoding);
883  pp->content_transfer_encoding = NULL;
884  }
885 }
886 
887 
896 static int
897 post_process_multipart (struct MHD_PostProcessor *pp,
898  const char *post_data,
899  size_t post_data_len)
900 {
901  char *buf;
902  size_t max;
903  size_t ioff;
904  size_t poff;
905  int state_changed;
906 
907  buf = (char *) &pp[1];
908  ioff = 0;
909  poff = 0;
910  state_changed = 1;
911  while ( (poff < post_data_len) ||
912  ( (pp->buffer_pos > 0) &&
913  (0 != state_changed) ) )
914  {
915  /* first, move as much input data
916  as possible to our internal buffer */
917  max = pp->buffer_size - pp->buffer_pos;
918  if (max > post_data_len - poff)
919  max = post_data_len - poff;
920  memcpy (&buf[pp->buffer_pos],
921  &post_data[poff],
922  max);
923  poff += max;
924  pp->buffer_pos += max;
925  if ( (0 == max) &&
926  (0 == state_changed) &&
927  (poff < post_data_len) )
928  {
929  pp->state = PP_Error;
930  return MHD_NO; /* out of memory */
931  }
932  state_changed = 0;
933 
934  /* first state machine for '\r'-'\n' and '--' handling */
935  switch (pp->skip_rn)
936  {
937  case RN_Inactive:
938  break;
939  case RN_OptN:
940  if (buf[0] == '\n')
941  {
942  ioff++;
943  pp->skip_rn = RN_Inactive;
944  goto AGAIN;
945  }
946  /* fall-through! */
947  case RN_Dash:
948  if (buf[0] == '-')
949  {
950  ioff++;
951  pp->skip_rn = RN_Dash2;
952  goto AGAIN;
953  }
954  pp->skip_rn = RN_Full;
955  /* fall-through! */
956  case RN_Full:
957  if (buf[0] == '\r')
958  {
959  if ( (pp->buffer_pos > 1) &&
960  ('\n' == buf[1]) )
961  {
962  pp->skip_rn = RN_Inactive;
963  ioff += 2;
964  }
965  else
966  {
967  pp->skip_rn = RN_OptN;
968  ioff++;
969  }
970  goto AGAIN;
971  }
972  if (buf[0] == '\n')
973  {
974  ioff++;
975  pp->skip_rn = RN_Inactive;
976  goto AGAIN;
977  }
978  pp->skip_rn = RN_Inactive;
979  pp->state = PP_Error;
980  return MHD_NO; /* no '\r\n' */
981  case RN_Dash2:
982  if (buf[0] == '-')
983  {
984  ioff++;
985  pp->skip_rn = RN_Full;
986  pp->state = pp->dash_state;
987  goto AGAIN;
988  }
989  pp->state = PP_Error;
990  break;
991  }
992 
993  /* main state engine */
994  switch (pp->state)
995  {
996  case PP_Error:
997  return MHD_NO;
998  case PP_Done:
999  /* did not expect to receive more data */
1000  pp->state = PP_Error;
1001  return MHD_NO;
1002  case PP_Init:
1014  (void) find_boundary (pp,
1015  pp->boundary,
1016  pp->blen,
1017  &ioff,
1019  PP_Done);
1020  break;
1021  case PP_NextBoundary:
1022  if (MHD_NO == find_boundary (pp,
1023  pp->boundary,
1024  pp->blen,
1025  &ioff,
1027  PP_Done))
1028  {
1029  if (pp->state == PP_Error)
1030  return MHD_NO;
1031  goto END;
1032  }
1033  break;
1035  pp->must_ikvi = MHD_YES;
1036  if (MHD_NO ==
1038  &ioff,
1040  {
1041  if (pp->state == PP_Error)
1042  return MHD_NO;
1043  else
1044  goto END;
1045  }
1046  state_changed = 1;
1047  break;
1049  if ( (NULL != pp->content_type) &&
1050  (MHD_str_equal_caseless_n_ (pp->content_type,
1051  "multipart/mixed",
1052  MHD_STATICSTR_LEN_ ("multipart/mixed"))))
1053  {
1054  pp->nested_boundary = strstr (pp->content_type,
1055  "boundary=");
1056  if (NULL == pp->nested_boundary)
1057  {
1058  pp->state = PP_Error;
1059  return MHD_NO;
1060  }
1061  pp->nested_boundary =
1062  strdup (&pp->nested_boundary[MHD_STATICSTR_LEN_ ("boundary=")]);
1063  if (NULL == pp->nested_boundary)
1064  {
1065  /* out of memory */
1066  pp->state = PP_Error;
1067  return MHD_NO;
1068  }
1069  /* free old content type, we will need that field
1070  for the content type of the nested elements */
1071  free (pp->content_type);
1072  pp->content_type = NULL;
1073  pp->nlen = strlen (pp->nested_boundary);
1074  pp->state = PP_Nested_Init;
1075  state_changed = 1;
1076  break;
1077  }
1078  pp->state = PP_ProcessValueToBoundary;
1079  pp->value_offset = 0;
1080  state_changed = 1;
1081  break;
1083  if (MHD_NO == process_value_to_boundary (pp,
1084  &ioff,
1085  pp->boundary,
1086  pp->blen,
1088  PP_Done))
1089  {
1090  if (pp->state == PP_Error)
1091  return MHD_NO;
1092  break;
1093  }
1094  break;
1095  case PP_PerformCleanup:
1096  /* clean up state of one multipart form-data element! */
1097  pp->have = NE_none;
1098  free_unmarked (pp);
1099  if (NULL != pp->nested_boundary)
1100  {
1101  free (pp->nested_boundary);
1102  pp->nested_boundary = NULL;
1103  }
1104  pp->state = PP_ProcessEntryHeaders;
1105  state_changed = 1;
1106  break;
1107  case PP_Nested_Init:
1108  if (NULL == pp->nested_boundary)
1109  {
1110  pp->state = PP_Error;
1111  return MHD_NO;
1112  }
1113  if (MHD_NO == find_boundary (pp,
1114  pp->nested_boundary,
1115  pp->nlen,
1116  &ioff,
1118  PP_NextBoundary /* or PP_Error? */ ))
1119  {
1120  if (pp->state == PP_Error)
1121  return MHD_NO;
1122  goto END;
1123  }
1124  break;
1126  /* remember what headers were given
1127  globally */
1128  pp->have = NE_none;
1129  if (NULL != pp->content_name)
1130  pp->have |= NE_content_name;
1131  if (NULL != pp->content_type)
1132  pp->have |= NE_content_type;
1133  if (NULL != pp->content_filename)
1134  pp->have |= NE_content_filename;
1135  if (NULL != pp->content_transfer_encoding)
1136  pp->have |= NE_content_transfer_encoding;
1137  pp->state = PP_Nested_ProcessEntryHeaders;
1138  state_changed = 1;
1139  break;
1141  pp->value_offset = 0;
1142  if (MHD_NO ==
1144  &ioff,
1146  {
1147  if (pp->state == PP_Error)
1148  return MHD_NO;
1149  else
1150  goto END;
1151  }
1152  state_changed = 1;
1153  break;
1155  if (MHD_NO == process_value_to_boundary (pp,
1156  &ioff,
1157  pp->nested_boundary,
1158  pp->nlen,
1160  PP_NextBoundary))
1161  {
1162  if (pp->state == PP_Error)
1163  return MHD_NO;
1164  break;
1165  }
1166  break;
1168  free_unmarked (pp);
1169  pp->state = PP_Nested_ProcessEntryHeaders;
1170  state_changed = 1;
1171  break;
1172  default:
1174  __FILE__,
1175  __LINE__,
1176  NULL); /* should never happen! */
1177  }
1178  AGAIN:
1179  if (ioff > 0)
1180  {
1181  memmove (buf,
1182  &buf[ioff],
1183  pp->buffer_pos - ioff);
1184  pp->buffer_pos -= ioff;
1185  ioff = 0;
1186  state_changed = 1;
1187  }
1188  }
1189 END:
1190  if (0 != ioff)
1191  {
1192  memmove (buf,
1193  &buf[ioff],
1194  pp->buffer_pos - ioff);
1195  pp->buffer_pos -= ioff;
1196  }
1197  if (poff < post_data_len)
1198  {
1199  pp->state = PP_Error;
1200  return MHD_NO; /* serious error */
1201  }
1202  return MHD_YES;
1203 }
1204 
1205 
1219 int
1220 MHD_post_process (struct MHD_PostProcessor *pp,
1221  const char *post_data,
1222  size_t post_data_len)
1223 {
1224  if (0 == post_data_len)
1225  return MHD_YES;
1226  if (NULL == pp)
1227  return MHD_NO;
1229  pp->encoding,
1231  return post_process_urlencoded (pp,
1232  post_data,
1233  post_data_len);
1235  pp->encoding,
1237  return post_process_multipart (pp,
1238  post_data,
1239  post_data_len);
1240  /* this should never be reached */
1241  return MHD_NO;
1242 }
1243 
1244 
1255 int
1256 MHD_destroy_post_processor (struct MHD_PostProcessor *pp)
1257 {
1258  int ret;
1259 
1260  if (NULL == pp)
1261  return MHD_YES;
1262  if (PP_ProcessValue == pp->state)
1263  {
1264  /* key without terminated value left at the end of the
1265  buffer; fake receiving a termination character to
1266  ensure it is also processed */
1268  "\n",
1269  1);
1270  }
1271  /* These internal strings need cleaning up since
1272  the post-processing may have been interrupted
1273  at any stage */
1274  if ( (pp->xbuf_pos > 0) ||
1275  ( (pp->state != PP_Done) &&
1276  (pp->state != PP_ExpectNewLine) ) )
1277  ret = MHD_NO;
1278  else
1279  ret = MHD_YES;
1280  pp->have = NE_none;
1281  free_unmarked (pp);
1282  if (NULL != pp->nested_boundary)
1283  free (pp->nested_boundary);
1284  free (pp);
1285  return ret;
1286 }
1287 
1288 /* end of postprocessor.c */
int MHD_str_equal_caseless_n_(const char *const str1, const char *const str2, size_t maxlen)
Definition: mhd_str.c:359
Header for platform missing functions.
enum MHD_CONNECTION_STATE state
Definition: internal.h:925
void * mhd_panic_cls
Definition: panic.c:36
MHD_PanicCallback mhd_panic
Definition: panic.c:31
void * MHD_calloc_(size_t nelem, size_t elsize)
Definition: mhd_compat.c:96
#define MHD_YES
Definition: microhttpd.h:140
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:2280
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)
_MHD_EXTERN int MHD_destroy_post_processor(struct MHD_PostProcessor *pp)
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
#define NULL
Definition: reason_phrase.c:30
Header for string manipulating helpers.
_MHD_EXTERN int MHD_post_process(struct MHD_PostProcessor *pp, const char *post_data, size_t post_data_len)
#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)
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:957
NE_State
static void free_unmarked(struct MHD_PostProcessor *pp)
RN_State
Definition: postprocessor.c:68
#define MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA
Definition: microhttpd.h:958
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)
_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:957
#define MHD_HTTP_HEADER_CONTENT_TYPE
Definition: microhttpd.h:551
#define MHD_NO
Definition: microhttpd.h:145
void MHD_unescape_plus(char *arg)
Definition: internal.c:119
_MHD_EXTERN size_t MHD_http_unescape(char *val)
Definition: internal.c:138
#define XBUF_SIZE
Definition: postprocessor.c:35
static void try_get_value(const char *buf, const char *key, char **destination)