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