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