GNU libmicrohttpd  0.9.29
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 
34 #define XBUF_SIZE 512
35 
40 {
41  /* general states */
46 
47  /* url encoding-states */
50 
51  /* post encoding-states */
56 
57  /* nested post-encoding states */
63 
64 };
65 
66 
68 {
73 
78  RN_OptN = 1,
79 
84  RN_Full = 2,
85 
90  RN_Dash = 3,
91 
96 };
97 
98 
105 {
106  NE_none = 0,
111 };
112 
113 
118 struct MHD_PostProcessor
119 {
120 
125  struct MHD_Connection *connection;
126 
131 
135  void *cls;
136 
141  const char *encoding;
142 
146  const char *boundary;
147 
151  char *nested_boundary;
152 
156  char *content_name;
157 
161  char *content_type;
162 
166  char *content_filename;
167 
171  char *content_transfer_encoding;
172 
177  char xbuf[8];
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  int must_ikvi;
218 
222  enum PP_State state;
223 
230  enum RN_State skip_rn;
231 
236  enum PP_State dash_state;
237 
242  enum NE_State have;
243 
244 };
245 
246 
272 struct MHD_PostProcessor *
274  size_t buffer_size,
276  void *iter_cls)
277 {
278  struct MHD_PostProcessor *ret;
279  const char *encoding;
280  const char *boundary;
281  size_t blen;
282 
283  if ( (buffer_size < 256) ||
284  (NULL == connection) ||
285  (NULL == iter))
287  __FILE__,
288  __LINE__,
289  NULL);
290  encoding = MHD_lookup_connection_value (connection,
293  if (NULL == encoding)
294  return NULL;
295  boundary = NULL;
297  encoding,
299  {
301  encoding,
303  return NULL;
304  boundary =
305  &encoding[strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)];
306  /* Q: should this be "strcasestr"? */
307  boundary = strstr (boundary, "boundary=");
308  if (NULL == boundary)
309  return NULL; /* failed to determine boundary */
310  boundary += strlen ("boundary=");
311  blen = strlen (boundary);
312  if ( (blen == 0) ||
313  (blen * 2 + 2 > buffer_size) )
314  return NULL; /* (will be) out of memory or invalid boundary */
315  if ( (boundary[0] == '"') &&
316  (boundary[blen - 1] == '"') )
317  {
318  /* remove enclosing quotes */
319  ++boundary;
320  blen -= 2;
321  }
322  }
323  else
324  blen = 0;
325  buffer_size += 4; /* round up to get nice block sizes despite boundary search */
326 
327  /* add +1 to ensure we ALWAYS have a zero-termination at the end */
328  if (NULL == (ret = malloc (sizeof (struct MHD_PostProcessor) + buffer_size + 1)))
329  return NULL;
330  memset (ret,
331  0,
332  sizeof (struct MHD_PostProcessor) + buffer_size + 1);
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 
527 static int
528 try_match_header (const char *prefix,
529  char *line,
530  char **suffix)
531 {
532  if (NULL != *suffix)
533  return MHD_NO;
534  while (0 != *line)
535  {
536  if (MHD_str_equal_caseless_n_ (prefix,
537  line,
538  strlen (prefix)))
539  {
540  *suffix = strdup (&line[strlen (prefix)]);
541  return MHD_YES;
542  }
543  ++line;
544  }
545  return MHD_NO;
546 }
547 
548 
562 static int
563 find_boundary (struct MHD_PostProcessor *pp,
564  const char *boundary,
565  size_t blen,
566  size_t *ioffptr,
567  enum PP_State next_state,
568  enum PP_State next_dash_state)
569 {
570  char *buf = (char *) &pp[1];
571  const char *dash;
572 
573  if (pp->buffer_pos < 2 + blen)
574  {
575  if (pp->buffer_pos == pp->buffer_size)
576  pp->state = PP_Error; /* out of memory */
577  /* ++(*ioffptr); */
578  return MHD_NO; /* not enough data */
579  }
580  if ( (0 != memcmp ("--",
581  buf,
582  2)) ||
583  (0 != memcmp (&buf[2],
584  boundary,
585  blen)))
586  {
587  if (pp->state != PP_Init)
588  {
589  /* garbage not allowed */
590  pp->state = PP_Error;
591  }
592  else
593  {
594  /* skip over garbage (RFC 2046, 5.1.1) */
595  dash = memchr (buf,
596  '-',
597  pp->buffer_pos);
598  if (NULL == dash)
599  (*ioffptr) += pp->buffer_pos; /* skip entire buffer */
600  else
601  if (dash == buf)
602  (*ioffptr)++; /* at least skip one byte */
603  else
604  (*ioffptr) += dash - buf; /* skip to first possible boundary */
605  }
606  return MHD_NO; /* expected boundary */
607  }
608  /* remove boundary from buffer */
609  (*ioffptr) += 2 + blen;
610  /* next: start with headers */
611  pp->skip_rn = RN_Dash;
612  pp->state = next_state;
613  pp->dash_state = next_dash_state;
614  return MHD_YES;
615 }
616 
617 
624 static void
625 try_get_value (const char *buf,
626  const char *key,
627  char **destination)
628 {
629  const char *spos;
630  const char *bpos;
631  const char *endv;
632  size_t klen;
633  size_t vlen;
634 
635  if (NULL != *destination)
636  return;
637  bpos = buf;
638  klen = strlen (key);
639  while (NULL != (spos = strstr (bpos, key)))
640  {
641  if ( (spos[klen] != '=') ||
642  ( (spos != buf) &&
643  (spos[-1] != ' ') ) )
644  {
645  /* no match */
646  bpos = spos + 1;
647  continue;
648  }
649  if (spos[klen + 1] != '"')
650  return; /* not quoted */
651  if (NULL == (endv = strchr (&spos[klen + 2],
652  '\"')))
653  return; /* no end-quote */
654  vlen = endv - spos - klen - 1;
655  *destination = malloc (vlen);
656  if (NULL == *destination)
657  return; /* out of memory */
658  (*destination)[vlen - 1] = '\0';
659  memcpy (*destination,
660  &spos[klen + 2],
661  vlen - 1);
662  return; /* success */
663  }
664 }
665 
666 
682 static int
683 process_multipart_headers (struct MHD_PostProcessor *pp,
684  size_t *ioffptr,
685  enum PP_State next_state)
686 {
687  char *buf = (char *) &pp[1];
688  size_t newline;
689 
690  newline = 0;
691  while ( (newline < pp->buffer_pos) &&
692  (buf[newline] != '\r') &&
693  (buf[newline] != '\n') )
694  newline++;
695  if (newline == pp->buffer_size)
696  {
697  pp->state = PP_Error;
698  return MHD_NO; /* out of memory */
699  }
700  if (newline == pp->buffer_pos)
701  return MHD_NO; /* will need more data */
702  if (0 == newline)
703  {
704  /* empty line - end of headers */
705  pp->skip_rn = RN_Full;
706  pp->state = next_state;
707  return MHD_YES;
708  }
709  /* got an actual header */
710  if (buf[newline] == '\r')
711  pp->skip_rn = RN_OptN;
712  buf[newline] = '\0';
713  if (MHD_str_equal_caseless_n_ ("Content-disposition: ",
714  buf,
715  strlen ("Content-disposition: ")))
716  {
717  try_get_value (&buf[strlen ("Content-disposition: ")],
718  "name",
719  &pp->content_name);
720  try_get_value (&buf[strlen ("Content-disposition: ")],
721  "filename",
722  &pp->content_filename);
723  }
724  else
725  {
726  try_match_header ("Content-type: ",
727  buf,
728  &pp->content_type);
729  try_match_header ("Content-Transfer-Encoding: ",
730  buf,
731  &pp->content_transfer_encoding);
732  }
733  (*ioffptr) += newline + 1;
734  return MHD_YES;
735 }
736 
737 
754 static int
755 process_value_to_boundary (struct MHD_PostProcessor *pp,
756  size_t *ioffptr,
757  const char *boundary,
758  size_t blen,
759  enum PP_State next_state,
760  enum PP_State next_dash_state)
761 {
762  char *buf = (char *) &pp[1];
763  size_t newline;
764  const char *r;
765 
766  /* all data in buf until the boundary
767  (\r\n--+boundary) is part of the value */
768  newline = 0;
769  while (1)
770  {
771  while (newline + 4 < pp->buffer_pos)
772  {
773  r = memchr (&buf[newline],
774  '\r',
775  pp->buffer_pos - newline - 4);
776  if (NULL == r)
777  {
778  newline = pp->buffer_pos - 4;
779  break;
780  }
781  newline = r - buf;
782  if (0 == memcmp ("\r\n--",
783  &buf[newline],
784  4))
785  break;
786  newline++;
787  }
788  if (newline + pp->blen + 4 <= pp->buffer_pos)
789  {
790  /* can check boundary */
791  if (0 != memcmp (&buf[newline + 4],
792  boundary,
793  pp->blen))
794  {
795  /* no boundary, "\r\n--" is part of content, skip */
796  newline += 4;
797  continue;
798  }
799  else
800  {
801  /* boundary found, process until newline then
802  skip boundary and go back to init */
803  pp->skip_rn = RN_Dash;
804  pp->state = next_state;
805  pp->dash_state = next_dash_state;
806  (*ioffptr) += pp->blen + 4; /* skip boundary as well */
807  buf[newline] = '\0';
808  break;
809  }
810  }
811  else
812  {
813  /* cannot check for boundary, process content that
814  we have and check again later; except, if we have
815  no content, abort (out of memory) */
816  if ( (0 == newline) &&
817  (pp->buffer_pos == pp->buffer_size) )
818  {
819  pp->state = PP_Error;
820  return MHD_NO;
821  }
822  break;
823  }
824  }
825  /* newline is either at beginning of boundary or
826  at least at the last character that we are sure
827  is not part of the boundary */
828  if ( ( (MHD_YES == pp->must_ikvi) ||
829  (0 != newline) ) &&
830  (MHD_NO == pp->ikvi (pp->cls,
832  pp->content_name,
833  pp->content_filename,
834  pp->content_type,
835  pp->content_transfer_encoding,
836  buf,
837  pp->value_offset,
838  newline)) )
839  {
840  pp->state = PP_Error;
841  return MHD_NO;
842  }
843  pp->must_ikvi = MHD_NO;
844  pp->value_offset += newline;
845  (*ioffptr) += newline;
846  return MHD_YES;
847 }
848 
849 
854 static void
855 free_unmarked (struct MHD_PostProcessor *pp)
856 {
857  if ( (NULL != pp->content_name) &&
858  (0 == (pp->have & NE_content_name)) )
859  {
860  free (pp->content_name);
861  pp->content_name = NULL;
862  }
863  if ( (NULL != pp->content_type) &&
864  (0 == (pp->have & NE_content_type)) )
865  {
866  free (pp->content_type);
867  pp->content_type = NULL;
868  }
869  if ( (NULL != pp->content_filename) &&
870  (0 == (pp->have & NE_content_filename)) )
871  {
872  free (pp->content_filename);
873  pp->content_filename = NULL;
874  }
875  if ( (NULL != pp->content_transfer_encoding) &&
876  (0 == (pp->have & NE_content_transfer_encoding)) )
877  {
878  free (pp->content_transfer_encoding);
879  pp->content_transfer_encoding = NULL;
880  }
881 }
882 
883 
892 static int
893 post_process_multipart (struct MHD_PostProcessor *pp,
894  const char *post_data,
895  size_t post_data_len)
896 {
897  char *buf;
898  size_t max;
899  size_t ioff;
900  size_t poff;
901  int state_changed;
902 
903  buf = (char *) &pp[1];
904  ioff = 0;
905  poff = 0;
906  state_changed = 1;
907  while ( (poff < post_data_len) ||
908  ( (pp->buffer_pos > 0) &&
909  (0 != state_changed) ) )
910  {
911  /* first, move as much input data
912  as possible to our internal buffer */
913  max = pp->buffer_size - pp->buffer_pos;
914  if (max > post_data_len - poff)
915  max = post_data_len - poff;
916  memcpy (&buf[pp->buffer_pos],
917  &post_data[poff],
918  max);
919  poff += max;
920  pp->buffer_pos += max;
921  if ( (0 == max) &&
922  (0 == state_changed) &&
923  (poff < post_data_len) )
924  {
925  pp->state = PP_Error;
926  return MHD_NO; /* out of memory */
927  }
928  state_changed = 0;
929 
930  /* first state machine for '\r'-'\n' and '--' handling */
931  switch (pp->skip_rn)
932  {
933  case RN_Inactive:
934  break;
935  case RN_OptN:
936  if (buf[0] == '\n')
937  {
938  ioff++;
939  pp->skip_rn = RN_Inactive;
940  goto AGAIN;
941  }
942  /* fall-through! */
943  case RN_Dash:
944  if (buf[0] == '-')
945  {
946  ioff++;
947  pp->skip_rn = RN_Dash2;
948  goto AGAIN;
949  }
950  pp->skip_rn = RN_Full;
951  /* fall-through! */
952  case RN_Full:
953  if (buf[0] == '\r')
954  {
955  if ( (pp->buffer_pos > 1) &&
956  ('\n' == buf[1]) )
957  {
958  pp->skip_rn = RN_Inactive;
959  ioff += 2;
960  }
961  else
962  {
963  pp->skip_rn = RN_OptN;
964  ioff++;
965  }
966  goto AGAIN;
967  }
968  if (buf[0] == '\n')
969  {
970  ioff++;
971  pp->skip_rn = RN_Inactive;
972  goto AGAIN;
973  }
974  pp->skip_rn = RN_Inactive;
975  pp->state = PP_Error;
976  return MHD_NO; /* no '\r\n' */
977  case RN_Dash2:
978  if (buf[0] == '-')
979  {
980  ioff++;
981  pp->skip_rn = RN_Full;
982  pp->state = pp->dash_state;
983  goto AGAIN;
984  }
985  pp->state = PP_Error;
986  break;
987  }
988 
989  /* main state engine */
990  switch (pp->state)
991  {
992  case PP_Error:
993  return MHD_NO;
994  case PP_Done:
995  /* did not expect to receive more data */
996  pp->state = PP_Error;
997  return MHD_NO;
998  case PP_Init:
1010  (void) find_boundary (pp,
1011  pp->boundary,
1012  pp->blen,
1013  &ioff,
1015  PP_Done);
1016  break;
1017  case PP_NextBoundary:
1018  if (MHD_NO == find_boundary (pp,
1019  pp->boundary,
1020  pp->blen,
1021  &ioff,
1023  PP_Done))
1024  {
1025  if (pp->state == PP_Error)
1026  return MHD_NO;
1027  goto END;
1028  }
1029  break;
1031  pp->must_ikvi = MHD_YES;
1032  if (MHD_NO ==
1034  &ioff,
1036  {
1037  if (pp->state == PP_Error)
1038  return MHD_NO;
1039  else
1040  goto END;
1041  }
1042  state_changed = 1;
1043  break;
1045  if ( (NULL != pp->content_type) &&
1046  (MHD_str_equal_caseless_n_ (pp->content_type,
1047  "multipart/mixed",
1048  strlen ("multipart/mixed"))))
1049  {
1050  pp->nested_boundary = strstr (pp->content_type,
1051  "boundary=");
1052  if (NULL == pp->nested_boundary)
1053  {
1054  pp->state = PP_Error;
1055  return MHD_NO;
1056  }
1057  pp->nested_boundary =
1058  strdup (&pp->nested_boundary[strlen ("boundary=")]);
1059  if (NULL == pp->nested_boundary)
1060  {
1061  /* out of memory */
1062  pp->state = PP_Error;
1063  return MHD_NO;
1064  }
1065  /* free old content type, we will need that field
1066  for the content type of the nested elements */
1067  free (pp->content_type);
1068  pp->content_type = NULL;
1069  pp->nlen = strlen (pp->nested_boundary);
1070  pp->state = PP_Nested_Init;
1071  state_changed = 1;
1072  break;
1073  }
1074  pp->state = PP_ProcessValueToBoundary;
1075  pp->value_offset = 0;
1076  state_changed = 1;
1077  break;
1079  if (MHD_NO == process_value_to_boundary (pp,
1080  &ioff,
1081  pp->boundary,
1082  pp->blen,
1084  PP_Done))
1085  {
1086  if (pp->state == PP_Error)
1087  return MHD_NO;
1088  break;
1089  }
1090  break;
1091  case PP_PerformCleanup:
1092  /* clean up state of one multipart form-data element! */
1093  pp->have = NE_none;
1094  free_unmarked (pp);
1095  if (NULL != pp->nested_boundary)
1096  {
1097  free (pp->nested_boundary);
1098  pp->nested_boundary = NULL;
1099  }
1100  pp->state = PP_ProcessEntryHeaders;
1101  state_changed = 1;
1102  break;
1103  case PP_Nested_Init:
1104  if (NULL == pp->nested_boundary)
1105  {
1106  pp->state = PP_Error;
1107  return MHD_NO;
1108  }
1109  if (MHD_NO == find_boundary (pp,
1110  pp->nested_boundary,
1111  pp->nlen,
1112  &ioff,
1114  PP_NextBoundary /* or PP_Error? */ ))
1115  {
1116  if (pp->state == PP_Error)
1117  return MHD_NO;
1118  goto END;
1119  }
1120  break;
1122  /* remember what headers were given
1123  globally */
1124  pp->have = NE_none;
1125  if (NULL != pp->content_name)
1126  pp->have |= NE_content_name;
1127  if (NULL != pp->content_type)
1128  pp->have |= NE_content_type;
1129  if (NULL != pp->content_filename)
1130  pp->have |= NE_content_filename;
1131  if (NULL != pp->content_transfer_encoding)
1132  pp->have |= NE_content_transfer_encoding;
1133  pp->state = PP_Nested_ProcessEntryHeaders;
1134  state_changed = 1;
1135  break;
1137  pp->value_offset = 0;
1138  if (MHD_NO ==
1140  &ioff,
1142  {
1143  if (pp->state == PP_Error)
1144  return MHD_NO;
1145  else
1146  goto END;
1147  }
1148  state_changed = 1;
1149  break;
1151  if (MHD_NO == process_value_to_boundary (pp,
1152  &ioff,
1153  pp->nested_boundary,
1154  pp->nlen,
1156  PP_NextBoundary))
1157  {
1158  if (pp->state == PP_Error)
1159  return MHD_NO;
1160  break;
1161  }
1162  break;
1164  free_unmarked (pp);
1165  pp->state = PP_Nested_ProcessEntryHeaders;
1166  state_changed = 1;
1167  break;
1168  default:
1170  __FILE__,
1171  __LINE__,
1172  NULL); /* should never happen! */
1173  }
1174  AGAIN:
1175  if (ioff > 0)
1176  {
1177  memmove (buf,
1178  &buf[ioff],
1179  pp->buffer_pos - ioff);
1180  pp->buffer_pos -= ioff;
1181  ioff = 0;
1182  state_changed = 1;
1183  }
1184  }
1185 END:
1186  if (0 != ioff)
1187  {
1188  memmove (buf,
1189  &buf[ioff],
1190  pp->buffer_pos - ioff);
1191  pp->buffer_pos -= ioff;
1192  }
1193  if (poff < post_data_len)
1194  {
1195  pp->state = PP_Error;
1196  return MHD_NO; /* serious error */
1197  }
1198  return MHD_YES;
1199 }
1200 
1201 
1215 int
1216 MHD_post_process (struct MHD_PostProcessor *pp,
1217  const char *post_data,
1218  size_t post_data_len)
1219 {
1220  if (0 == post_data_len)
1221  return MHD_YES;
1222  if (NULL == pp)
1223  return MHD_NO;
1225  pp->encoding,
1227  return post_process_urlencoded (pp,
1228  post_data,
1229  post_data_len);
1231  pp->encoding,
1233  return post_process_multipart (pp,
1234  post_data,
1235  post_data_len);
1236  /* this should never be reached */
1237  return MHD_NO;
1238 }
1239 
1240 
1251 int
1252 MHD_destroy_post_processor (struct MHD_PostProcessor *pp)
1253 {
1254  int ret;
1255 
1256  if (NULL == pp)
1257  return MHD_YES;
1258  if (PP_ProcessValue == pp->state)
1259  {
1260  /* key without terminated value left at the end of the
1261  buffer; fake receiving a termination character to
1262  ensure it is also processed */
1264  "\n",
1265  1);
1266  }
1267  /* These internal strings need cleaning up since
1268  the post-processing may have been interrupted
1269  at any stage */
1270  if ( (pp->xbuf_pos > 0) ||
1271  ( (pp->state != PP_Done) &&
1272  (pp->state != PP_ExpectNewLine) ) )
1273  ret = MHD_NO;
1274  else
1275  ret = MHD_YES;
1276  pp->have = NE_none;
1277  free_unmarked (pp);
1278  if (NULL != pp->nested_boundary)
1279  free (pp->nested_boundary);
1280  free (pp);
1281  return ret;
1282 }
1283 
1284 /* 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:446
void MHD_unescape_plus(char *arg)
Definition: internal.c:119
enum MHD_CONNECTION_STATE state
Definition: internal.h:813
#define NULL
Definition: reason_phrase.c:30
#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:1572
PP_State
Definition: postprocessor.c:39
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:349
_MHD_EXTERN struct MHD_PostProcessor * MHD_create_post_processor(struct MHD_Connection *connection, size_t buffer_size, MHD_PostDataIterator iter, void *iter_cls)
void * mhd_panic_cls
Definition: daemon.c:124
_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
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:481
Header for string manipulating helpers.
NE_State
static void free_unmarked(struct MHD_PostProcessor *pp)
RN_State
Definition: postprocessor.c:67
MHD_PanicCallback mhd_panic
Definition: daemon.c:119
#define MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA
Definition: microhttpd.h:482
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:408
#define MHD_NO
Definition: microhttpd.h:139
_MHD_EXTERN size_t MHD_http_unescape(char *val)
Definition: internal.c:138
#define XBUF_SIZE
Definition: postprocessor.c:34
static void try_get_value(const char *buf, const char *key, char **destination)