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 
33 #define XBUF_SIZE 512
34 
39 {
40  /* general states */
45 
46  /* url encoding-states */
49 
50  /* post encoding-states */
55 
56  /* nested post-encoding states */
62 
63 };
64 
65 
67 {
72 
77  RN_OptN = 1,
78 
83  RN_Full = 2,
84 
89  RN_Dash = 3,
90 
95 };
96 
97 
104 {
105  NE_none = 0,
110 };
111 
112 
117 struct MHD_PostProcessor
118 {
119 
124  struct MHD_Connection *connection;
125 
130 
134  void *cls;
135 
140  const char *encoding;
141 
145  const char *boundary;
146 
150  char *nested_boundary;
151 
155  char *content_name;
156 
160  char *content_type;
161 
165  char *content_filename;
166 
170  char *content_transfer_encoding;
171 
176  char xbuf[8];
177 
181  size_t buffer_size;
182 
186  size_t buffer_pos;
187 
191  size_t xbuf_pos;
192 
196  uint64_t value_offset;
197 
201  size_t blen;
202 
206  size_t nlen;
207 
216  int must_ikvi;
217 
221  enum PP_State state;
222 
229  enum RN_State skip_rn;
230 
235  enum PP_State dash_state;
236 
241  enum NE_State have;
242 
243 };
244 
245 
271 struct MHD_PostProcessor *
273  size_t buffer_size,
274  MHD_PostDataIterator iter, void *iter_cls)
275 {
276  struct MHD_PostProcessor *ret;
277  const char *encoding;
278  const char *boundary;
279  size_t blen;
280 
281  if ((buffer_size < 256) || (connection == NULL) || (iter == NULL))
282  mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL);
283  encoding = MHD_lookup_connection_value (connection,
286  if (encoding == NULL)
287  return NULL;
288  boundary = NULL;
291  {
294  return NULL;
295  boundary =
296  &encoding[strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)];
297  /* Q: should this be "strcasestr"? */
298  boundary = strstr (boundary, "boundary=");
299  if (NULL == boundary)
300  return NULL; /* failed to determine boundary */
301  boundary += strlen ("boundary=");
302  blen = strlen (boundary);
303  if ((blen == 0) || (blen * 2 + 2 > buffer_size))
304  return NULL; /* (will be) out of memory or invalid boundary */
305  if ( (boundary[0] == '"') && (boundary[blen - 1] == '"') )
306  {
307  /* remove enclosing quotes */
308  ++boundary;
309  blen -= 2;
310  }
311  }
312  else
313  blen = 0;
314  buffer_size += 4; /* round up to get nice block sizes despite boundary search */
315 
316  /* add +1 to ensure we ALWAYS have a zero-termination at the end */
317  if (NULL == (ret = malloc (sizeof (struct MHD_PostProcessor) + buffer_size + 1)))
318  return NULL;
319  memset (ret, 0, sizeof (struct MHD_PostProcessor) + buffer_size + 1);
320  ret->connection = connection;
321  ret->ikvi = iter;
322  ret->cls = iter_cls;
323  ret->encoding = encoding;
324  ret->buffer_size = buffer_size;
325  ret->state = PP_Init;
326  ret->blen = blen;
327  ret->boundary = boundary;
328  ret->skip_rn = RN_Inactive;
329  return ret;
330 }
331 
332 
341 static int
342 post_process_urlencoded (struct MHD_PostProcessor *pp,
343  const char *post_data,
344  size_t post_data_len)
345 {
346  size_t equals;
347  size_t amper;
348  size_t poff;
349  size_t xoff;
350  size_t delta;
351  int end_of_value_found;
352  char *buf;
353  char xbuf[XBUF_SIZE + 1];
354 
355  buf = (char *) &pp[1];
356  poff = 0;
357  while (poff < post_data_len)
358  {
359  switch (pp->state)
360  {
361  case PP_Error:
362  return MHD_NO;
363  case PP_Done:
364  /* did not expect to receive more data */
365  pp->state = PP_Error;
366  return MHD_NO;
367  case PP_Init:
368  equals = 0;
369  while ((equals + poff < post_data_len) &&
370  (post_data[equals + poff] != '='))
371  equals++;
372  if (equals + pp->buffer_pos > pp->buffer_size)
373  {
374  pp->state = PP_Error; /* out of memory */
375  return MHD_NO;
376  }
377  memcpy (&buf[pp->buffer_pos], &post_data[poff], equals);
378  pp->buffer_pos += equals;
379  if (equals + poff == post_data_len)
380  return MHD_YES; /* no '=' yet */
381  buf[pp->buffer_pos] = '\0'; /* 0-terminate key */
382  pp->buffer_pos = 0; /* reset for next key */
383  MHD_unescape_plus (buf);
384  MHD_http_unescape (buf);
385  poff += equals + 1;
386  pp->state = PP_ProcessValue;
387  pp->value_offset = 0;
388  break;
389  case PP_ProcessValue:
390  /* obtain rest of value from previous iteration */
391  memcpy (xbuf, pp->xbuf, pp->xbuf_pos);
392  xoff = pp->xbuf_pos;
393  pp->xbuf_pos = 0;
394 
395  /* find last position in input buffer that is part of the value */
396  amper = 0;
397  while ((amper + poff < post_data_len) &&
398  (amper < XBUF_SIZE) &&
399  (post_data[amper + poff] != '&') &&
400  (post_data[amper + poff] != '\n') &&
401  (post_data[amper + poff] != '\r'))
402  amper++;
403  end_of_value_found = ((amper + poff < post_data_len) &&
404  ((post_data[amper + poff] == '&') ||
405  (post_data[amper + poff] == '\n') ||
406  (post_data[amper + poff] == '\r')));
407  /* compute delta, the maximum number of bytes that we will be able to
408  process right now (either amper-limited of xbuf-size limited) */
409  delta = amper;
410  if (delta > XBUF_SIZE - xoff)
411  delta = XBUF_SIZE - xoff;
412 
413  /* move input into processing buffer */
414  memcpy (&xbuf[xoff], &post_data[poff], delta);
415  xoff += delta;
416  poff += delta;
417 
418  /* find if escape sequence is at the end of the processing buffer;
419  if so, exclude those from processing (reduce delta to point at
420  end of processed region) */
421  delta = xoff;
422  if ((delta > 0) && (xbuf[delta - 1] == '%'))
423  delta--;
424  else if ((delta > 1) && (xbuf[delta - 2] == '%'))
425  delta -= 2;
426 
427  /* if we have an incomplete escape sequence, save it to
428  pp->xbuf for later */
429  if (delta < xoff)
430  {
431  memcpy (pp->xbuf, &xbuf[delta], xoff - delta);
432  pp->xbuf_pos = xoff - delta;
433  xoff = delta;
434  }
435 
436  /* If we have nothing to do (delta == 0) and
437  not just because the value is empty (are
438  waiting for more data), go for next iteration */
439  if ((xoff == 0) && (poff == post_data_len))
440  continue;
441 
442  /* unescape */
443  xbuf[xoff] = '\0'; /* 0-terminate in preparation */
444  MHD_unescape_plus (xbuf);
445  xoff = MHD_http_unescape (xbuf);
446  /* finally: call application! */
447  pp->must_ikvi = MHD_NO;
448  if (MHD_NO == pp->ikvi (pp->cls, MHD_POSTDATA_KIND, (const char *) &pp[1], /* key */
449  NULL, NULL, NULL, xbuf, pp->value_offset,
450  xoff))
451  {
452  pp->state = PP_Error;
453  return MHD_NO;
454  }
455  pp->value_offset += xoff;
456 
457  /* are we done with the value? */
458  if (end_of_value_found)
459  {
460  /* we found the end of the value! */
461  if ((post_data[poff] == '\n') || (post_data[poff] == '\r'))
462  {
463  pp->state = PP_ExpectNewLine;
464  }
465  else if (post_data[poff] == '&')
466  {
467  poff++; /* skip '&' */
468  pp->state = PP_Init;
469  }
470  }
471  break;
472  case PP_ExpectNewLine:
473  if ((post_data[poff] == '\n') || (post_data[poff] == '\r'))
474  {
475  poff++;
476  /* we are done, report error if we receive any more... */
477  pp->state = PP_Done;
478  return MHD_YES;
479  }
480  return MHD_NO;
481  default:
482  mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL); /* should never happen! */
483  }
484  }
485  return MHD_YES;
486 }
487 
488 
498 static int
499 try_match_header (const char *prefix, char *line, char **suffix)
500 {
501  if (NULL != *suffix)
502  return MHD_NO;
503  while (*line != 0)
504  {
505  if (MHD_str_equal_caseless_n_ (prefix, line, strlen (prefix)))
506  {
507  *suffix = strdup (&line[strlen (prefix)]);
508  return MHD_YES;
509  }
510  ++line;
511  }
512  return MHD_NO;
513 }
514 
515 
529 static int
530 find_boundary (struct MHD_PostProcessor *pp,
531  const char *boundary,
532  size_t blen,
533  size_t *ioffptr,
534  enum PP_State next_state, enum PP_State next_dash_state)
535 {
536  char *buf = (char *) &pp[1];
537  const char *dash;
538 
539  if (pp->buffer_pos < 2 + blen)
540  {
541  if (pp->buffer_pos == pp->buffer_size)
542  pp->state = PP_Error; /* out of memory */
543  /* ++(*ioffptr); */
544  return MHD_NO; /* not enough data */
545  }
546  if ((0 != memcmp ("--", buf, 2)) || (0 != memcmp (&buf[2], boundary, blen)))
547  {
548  if (pp->state != PP_Init)
549  {
550  /* garbage not allowed */
551  pp->state = PP_Error;
552  }
553  else
554  {
555  /* skip over garbage (RFC 2046, 5.1.1) */
556  dash = memchr (buf, '-', pp->buffer_pos);
557  if (NULL == dash)
558  (*ioffptr) += pp->buffer_pos; /* skip entire buffer */
559  else
560  if (dash == buf)
561  (*ioffptr)++; /* at least skip one byte */
562  else
563  (*ioffptr) += dash - buf; /* skip to first possible boundary */
564  }
565  return MHD_NO; /* expected boundary */
566  }
567  /* remove boundary from buffer */
568  (*ioffptr) += 2 + blen;
569  /* next: start with headers */
570  pp->skip_rn = RN_Dash;
571  pp->state = next_state;
572  pp->dash_state = next_dash_state;
573  return MHD_YES;
574 }
575 
576 
583 static void
584 try_get_value (const char *buf,
585  const char *key,
586  char **destination)
587 {
588  const char *spos;
589  const char *bpos;
590  const char *endv;
591  size_t klen;
592  size_t vlen;
593 
594  if (NULL != *destination)
595  return;
596  bpos = buf;
597  klen = strlen (key);
598  while (NULL != (spos = strstr (bpos, key)))
599  {
600  if ((spos[klen] != '=') || ((spos != buf) && (spos[-1] != ' ')))
601  {
602  /* no match */
603  bpos = spos + 1;
604  continue;
605  }
606  if (spos[klen + 1] != '"')
607  return; /* not quoted */
608  if (NULL == (endv = strchr (&spos[klen + 2], '\"')))
609  return; /* no end-quote */
610  vlen = endv - spos - klen - 1;
611  *destination = malloc (vlen);
612  if (NULL == *destination)
613  return; /* out of memory */
614  (*destination)[vlen - 1] = '\0';
615  memcpy (*destination, &spos[klen + 2], vlen - 1);
616  return; /* success */
617  }
618 }
619 
620 
636 static int
637 process_multipart_headers (struct MHD_PostProcessor *pp,
638  size_t *ioffptr, enum PP_State next_state)
639 {
640  char *buf = (char *) &pp[1];
641  size_t newline;
642 
643  newline = 0;
644  while ((newline < pp->buffer_pos) &&
645  (buf[newline] != '\r') && (buf[newline] != '\n'))
646  newline++;
647  if (newline == pp->buffer_size)
648  {
649  pp->state = PP_Error;
650  return MHD_NO; /* out of memory */
651  }
652  if (newline == pp->buffer_pos)
653  return MHD_NO; /* will need more data */
654  if (0 == newline)
655  {
656  /* empty line - end of headers */
657  pp->skip_rn = RN_Full;
658  pp->state = next_state;
659  return MHD_YES;
660  }
661  /* got an actual header */
662  if (buf[newline] == '\r')
663  pp->skip_rn = RN_OptN;
664  buf[newline] = '\0';
665  if (MHD_str_equal_caseless_n_ ("Content-disposition: ",
666  buf, strlen ("Content-disposition: ")))
667  {
668  try_get_value (&buf[strlen ("Content-disposition: ")],
669  "name", &pp->content_name);
670  try_get_value (&buf[strlen ("Content-disposition: ")],
671  "filename", &pp->content_filename);
672  }
673  else
674  {
675  try_match_header ("Content-type: ", buf, &pp->content_type);
676  try_match_header ("Content-Transfer-Encoding: ",
677  buf, &pp->content_transfer_encoding);
678  }
679  (*ioffptr) += newline + 1;
680  return MHD_YES;
681 }
682 
683 
700 static int
701 process_value_to_boundary (struct MHD_PostProcessor *pp,
702  size_t *ioffptr,
703  const char *boundary,
704  size_t blen,
705  enum PP_State next_state,
706  enum PP_State next_dash_state)
707 {
708  char *buf = (char *) &pp[1];
709  size_t newline;
710  const char *r;
711 
712  /* all data in buf until the boundary
713  (\r\n--+boundary) is part of the value */
714  newline = 0;
715  while (1)
716  {
717  while (newline + 4 < pp->buffer_pos)
718  {
719  r = memchr (&buf[newline], '\r', pp->buffer_pos - newline - 4);
720  if (NULL == r)
721  {
722  newline = pp->buffer_pos - 4;
723  break;
724  }
725  newline = r - buf;
726  if (0 == memcmp ("\r\n--", &buf[newline], 4))
727  break;
728  newline++;
729  }
730  if (newline + pp->blen + 4 <= pp->buffer_pos)
731  {
732  /* can check boundary */
733  if (0 != memcmp (&buf[newline + 4], boundary, pp->blen))
734  {
735  /* no boundary, "\r\n--" is part of content, skip */
736  newline += 4;
737  continue;
738  }
739  else
740  {
741  /* boundary found, process until newline then
742  skip boundary and go back to init */
743  pp->skip_rn = RN_Dash;
744  pp->state = next_state;
745  pp->dash_state = next_dash_state;
746  (*ioffptr) += pp->blen + 4; /* skip boundary as well */
747  buf[newline] = '\0';
748  break;
749  }
750  }
751  else
752  {
753  /* cannot check for boundary, process content that
754  we have and check again later; except, if we have
755  no content, abort (out of memory) */
756  if ((0 == newline) && (pp->buffer_pos == pp->buffer_size))
757  {
758  pp->state = PP_Error;
759  return MHD_NO;
760  }
761  break;
762  }
763  }
764  /* newline is either at beginning of boundary or
765  at least at the last character that we are sure
766  is not part of the boundary */
767  if ( ( (MHD_YES == pp->must_ikvi) ||
768  (0 != newline) ) &&
769  (MHD_NO == pp->ikvi (pp->cls,
771  pp->content_name,
772  pp->content_filename,
773  pp->content_type,
774  pp->content_transfer_encoding,
775  buf, pp->value_offset, newline)) )
776  {
777  pp->state = PP_Error;
778  return MHD_NO;
779  }
780  pp->must_ikvi = MHD_NO;
781  pp->value_offset += newline;
782  (*ioffptr) += newline;
783  return MHD_YES;
784 }
785 
786 
791 static void
792 free_unmarked (struct MHD_PostProcessor *pp)
793 {
794  if ((NULL != pp->content_name) && (0 == (pp->have & NE_content_name)))
795  {
796  free (pp->content_name);
797  pp->content_name = NULL;
798  }
799  if ((NULL != pp->content_type) && (0 == (pp->have & NE_content_type)))
800  {
801  free (pp->content_type);
802  pp->content_type = NULL;
803  }
804  if ((NULL != pp->content_filename) &&
805  (0 == (pp->have & NE_content_filename)))
806  {
807  free (pp->content_filename);
808  pp->content_filename = NULL;
809  }
810  if ((NULL != pp->content_transfer_encoding) &&
811  (0 == (pp->have & NE_content_transfer_encoding)))
812  {
813  free (pp->content_transfer_encoding);
814  pp->content_transfer_encoding = NULL;
815  }
816 }
817 
818 
827 static int
828 post_process_multipart (struct MHD_PostProcessor *pp,
829  const char *post_data,
830  size_t post_data_len)
831 {
832  char *buf;
833  size_t max;
834  size_t ioff;
835  size_t poff;
836  int state_changed;
837 
838  buf = (char *) &pp[1];
839  ioff = 0;
840  poff = 0;
841  state_changed = 1;
842  while ((poff < post_data_len) ||
843  ((pp->buffer_pos > 0) && (state_changed != 0)))
844  {
845  /* first, move as much input data
846  as possible to our internal buffer */
847  max = pp->buffer_size - pp->buffer_pos;
848  if (max > post_data_len - poff)
849  max = post_data_len - poff;
850  memcpy (&buf[pp->buffer_pos], &post_data[poff], max);
851  poff += max;
852  pp->buffer_pos += max;
853  if ((max == 0) && (state_changed == 0) && (poff < post_data_len))
854  {
855  pp->state = PP_Error;
856  return MHD_NO; /* out of memory */
857  }
858  state_changed = 0;
859 
860  /* first state machine for '\r'-'\n' and '--' handling */
861  switch (pp->skip_rn)
862  {
863  case RN_Inactive:
864  break;
865  case RN_OptN:
866  if (buf[0] == '\n')
867  {
868  ioff++;
869  pp->skip_rn = RN_Inactive;
870  goto AGAIN;
871  }
872  /* fall-through! */
873  case RN_Dash:
874  if (buf[0] == '-')
875  {
876  ioff++;
877  pp->skip_rn = RN_Dash2;
878  goto AGAIN;
879  }
880  pp->skip_rn = RN_Full;
881  /* fall-through! */
882  case RN_Full:
883  if (buf[0] == '\r')
884  {
885  if ((pp->buffer_pos > 1) && (buf[1] == '\n'))
886  {
887  pp->skip_rn = RN_Inactive;
888  ioff += 2;
889  }
890  else
891  {
892  pp->skip_rn = RN_OptN;
893  ioff++;
894  }
895  goto AGAIN;
896  }
897  if (buf[0] == '\n')
898  {
899  ioff++;
900  pp->skip_rn = RN_Inactive;
901  goto AGAIN;
902  }
903  pp->skip_rn = RN_Inactive;
904  pp->state = PP_Error;
905  return MHD_NO; /* no '\r\n' */
906  case RN_Dash2:
907  if (buf[0] == '-')
908  {
909  ioff++;
910  pp->skip_rn = RN_Full;
911  pp->state = pp->dash_state;
912  goto AGAIN;
913  }
914  pp->state = PP_Error;
915  break;
916  }
917 
918  /* main state engine */
919  switch (pp->state)
920  {
921  case PP_Error:
922  return MHD_NO;
923  case PP_Done:
924  /* did not expect to receive more data */
925  pp->state = PP_Error;
926  return MHD_NO;
927  case PP_Init:
939  (void) find_boundary (pp,
940  pp->boundary,
941  pp->blen,
942  &ioff,
944  break;
945  case PP_NextBoundary:
946  if (MHD_NO == find_boundary (pp,
947  pp->boundary,
948  pp->blen,
949  &ioff,
951  {
952  if (pp->state == PP_Error)
953  return MHD_NO;
954  goto END;
955  }
956  break;
958  pp->must_ikvi = MHD_YES;
959  if (MHD_NO ==
961  {
962  if (pp->state == PP_Error)
963  return MHD_NO;
964  else
965  goto END;
966  }
967  state_changed = 1;
968  break;
970  if ((pp->content_type != NULL) &&
971  (MHD_str_equal_caseless_n_ (pp->content_type,
972  "multipart/mixed",
973  strlen ("multipart/mixed"))))
974  {
975  pp->nested_boundary = strstr (pp->content_type, "boundary=");
976  if (pp->nested_boundary == NULL)
977  {
978  pp->state = PP_Error;
979  return MHD_NO;
980  }
981  pp->nested_boundary =
982  strdup (&pp->nested_boundary[strlen ("boundary=")]);
983  if (pp->nested_boundary == NULL)
984  {
985  /* out of memory */
986  pp->state = PP_Error;
987  return MHD_NO;
988  }
989  /* free old content type, we will need that field
990  for the content type of the nested elements */
991  free (pp->content_type);
992  pp->content_type = NULL;
993  pp->nlen = strlen (pp->nested_boundary);
994  pp->state = PP_Nested_Init;
995  state_changed = 1;
996  break;
997  }
998  pp->state = PP_ProcessValueToBoundary;
999  pp->value_offset = 0;
1000  state_changed = 1;
1001  break;
1003  if (MHD_NO == process_value_to_boundary (pp,
1004  &ioff,
1005  pp->boundary,
1006  pp->blen,
1008  PP_Done))
1009  {
1010  if (pp->state == PP_Error)
1011  return MHD_NO;
1012  break;
1013  }
1014  break;
1015  case PP_PerformCleanup:
1016  /* clean up state of one multipart form-data element! */
1017  pp->have = NE_none;
1018  free_unmarked (pp);
1019  if (pp->nested_boundary != NULL)
1020  {
1021  free (pp->nested_boundary);
1022  pp->nested_boundary = NULL;
1023  }
1024  pp->state = PP_ProcessEntryHeaders;
1025  state_changed = 1;
1026  break;
1027  case PP_Nested_Init:
1028  if (pp->nested_boundary == NULL)
1029  {
1030  pp->state = PP_Error;
1031  return MHD_NO;
1032  }
1033  if (MHD_NO == find_boundary (pp,
1034  pp->nested_boundary,
1035  pp->nlen,
1036  &ioff,
1038  PP_NextBoundary /* or PP_Error? */ ))
1039  {
1040  if (pp->state == PP_Error)
1041  return MHD_NO;
1042  goto END;
1043  }
1044  break;
1046  /* remember what headers were given
1047  globally */
1048  pp->have = NE_none;
1049  if (pp->content_name != NULL)
1050  pp->have |= NE_content_name;
1051  if (pp->content_type != NULL)
1052  pp->have |= NE_content_type;
1053  if (pp->content_filename != NULL)
1054  pp->have |= NE_content_filename;
1055  if (pp->content_transfer_encoding != NULL)
1056  pp->have |= NE_content_transfer_encoding;
1057  pp->state = PP_Nested_ProcessEntryHeaders;
1058  state_changed = 1;
1059  break;
1061  pp->value_offset = 0;
1062  if (MHD_NO ==
1063  process_multipart_headers (pp, &ioff,
1065  {
1066  if (pp->state == PP_Error)
1067  return MHD_NO;
1068  else
1069  goto END;
1070  }
1071  state_changed = 1;
1072  break;
1074  if (MHD_NO == process_value_to_boundary (pp,
1075  &ioff,
1076  pp->nested_boundary,
1077  pp->nlen,
1079  PP_NextBoundary))
1080  {
1081  if (pp->state == PP_Error)
1082  return MHD_NO;
1083  break;
1084  }
1085  break;
1087  free_unmarked (pp);
1088  pp->state = PP_Nested_ProcessEntryHeaders;
1089  state_changed = 1;
1090  break;
1091  default:
1092  mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL); /* should never happen! */
1093  }
1094  AGAIN:
1095  if (ioff > 0)
1096  {
1097  memmove (buf, &buf[ioff], pp->buffer_pos - ioff);
1098  pp->buffer_pos -= ioff;
1099  ioff = 0;
1100  state_changed = 1;
1101  }
1102  }
1103 END:
1104  if (ioff != 0)
1105  {
1106  memmove (buf, &buf[ioff], pp->buffer_pos - ioff);
1107  pp->buffer_pos -= ioff;
1108  }
1109  if (poff < post_data_len)
1110  {
1111  pp->state = PP_Error;
1112  return MHD_NO; /* serious error */
1113  }
1114  return MHD_YES;
1115 }
1116 
1117 
1131 int
1132 MHD_post_process (struct MHD_PostProcessor *pp,
1133  const char *post_data, size_t post_data_len)
1134 {
1135  if (0 == post_data_len)
1136  return MHD_YES;
1137  if (NULL == pp)
1138  return MHD_NO;
1141  return post_process_urlencoded (pp, post_data, post_data_len);
1144  return post_process_multipart (pp, post_data, post_data_len);
1145  /* this should never be reached */
1146  return MHD_NO;
1147 }
1148 
1149 
1160 int
1161 MHD_destroy_post_processor (struct MHD_PostProcessor *pp)
1162 {
1163  int ret;
1164 
1165  if (NULL == pp)
1166  return MHD_YES;
1167  if (PP_ProcessValue == pp->state)
1168  {
1169  /* key without terminated value left at the end of the
1170  buffer; fake receiving a termination character to
1171  ensure it is also processed */
1172  post_process_urlencoded (pp, "\n", 1);
1173  }
1174  /* These internal strings need cleaning up since
1175  the post-processing may have been interrupted
1176  at any stage */
1177  if ((pp->xbuf_pos > 0) ||
1178  ( (pp->state != PP_Done) &&
1179  (pp->state != PP_ExpectNewLine)))
1180  ret = MHD_NO;
1181  else
1182  ret = MHD_YES;
1183  pp->have = NE_none;
1184  free_unmarked (pp);
1185  if (pp->nested_boundary != NULL)
1186  free (pp->nested_boundary);
1187  free (pp);
1188  return ret;
1189 }
1190 
1191 /* end of postprocessor.c */
void MHD_unescape_plus(char *arg)
Definition: internal.c:113
void * mhd_panic_cls
Definition: daemon.c:154
_MHD_EXTERN const char * MHD_lookup_connection_value(struct MHD_Connection *connection, enum MHD_ValueKind kind, const char *key)
Definition: connection.c:219
enum MHD_CONNECTION_STATE state
Definition: internal.h:774
#define NULL
Definition: reason_phrase.c:30
#define MHD_YES
Definition: microhttpd.h:138
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:1505
PP_State
Definition: postprocessor.c:38
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)
internal shared structures
_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)
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:467
NE_State
static void free_unmarked(struct MHD_PostProcessor *pp)
RN_State
Definition: postprocessor.c:66
#define MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA
Definition: microhttpd.h:468
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_PanicCallback mhd_panic
Definition: daemon.c:149
#define MHD_HTTP_HEADER_CONTENT_TYPE
Definition: microhttpd.h:394
#define MHD_str_equal_caseless_n_(a, b, n)
#define MHD_NO
Definition: microhttpd.h:143
_MHD_EXTERN size_t MHD_http_unescape(char *val)
Definition: internal.c:132
#define XBUF_SIZE
Definition: postprocessor.c:33
static void try_get_value(const char *buf, const char *key, char **destination)