GNU libmicrohttpd  0.9.69
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:(void) find_boundary (pp,
1017  pp->boundary,
1018  pp->blen,
1019  &ioff,
1021  PP_Done);
1022  break;
1023  case PP_NextBoundary:
1024  if (MHD_NO == find_boundary (pp,
1025  pp->boundary,
1026  pp->blen,
1027  &ioff,
1029  PP_Done))
1030  {
1031  if (pp->state == PP_Error)
1032  return MHD_NO;
1033  goto END;
1034  }
1035  break;
1037  pp->must_ikvi = MHD_YES;
1038  if (MHD_NO ==
1040  &ioff,
1042  {
1043  if (pp->state == PP_Error)
1044  return MHD_NO;
1045  else
1046  goto END;
1047  }
1048  state_changed = 1;
1049  break;
1051  if ( (NULL != pp->content_type) &&
1052  (MHD_str_equal_caseless_n_ (pp->content_type,
1053  "multipart/mixed",
1054  MHD_STATICSTR_LEN_ ("multipart/mixed"))))
1055  {
1056  pp->nested_boundary = strstr (pp->content_type,
1057  "boundary=");
1058  if (NULL == pp->nested_boundary)
1059  {
1060  pp->state = PP_Error;
1061  return MHD_NO;
1062  }
1063  pp->nested_boundary =
1064  strdup (&pp->nested_boundary[MHD_STATICSTR_LEN_ ("boundary=")]);
1065  if (NULL == pp->nested_boundary)
1066  {
1067  /* out of memory */
1068  pp->state = PP_Error;
1069  return MHD_NO;
1070  }
1071  /* free old content type, we will need that field
1072  for the content type of the nested elements */
1073  free (pp->content_type);
1074  pp->content_type = NULL;
1075  pp->nlen = strlen (pp->nested_boundary);
1076  pp->state = PP_Nested_Init;
1077  state_changed = 1;
1078  break;
1079  }
1080  pp->state = PP_ProcessValueToBoundary;
1081  pp->value_offset = 0;
1082  state_changed = 1;
1083  break;
1085  if (MHD_NO == process_value_to_boundary (pp,
1086  &ioff,
1087  pp->boundary,
1088  pp->blen,
1090  PP_Done))
1091  {
1092  if (pp->state == PP_Error)
1093  return MHD_NO;
1094  break;
1095  }
1096  break;
1097  case PP_PerformCleanup:
1098  /* clean up state of one multipart form-data element! */
1099  pp->have = NE_none;
1100  free_unmarked (pp);
1101  if (NULL != pp->nested_boundary)
1102  {
1103  free (pp->nested_boundary);
1104  pp->nested_boundary = NULL;
1105  }
1106  pp->state = PP_ProcessEntryHeaders;
1107  state_changed = 1;
1108  break;
1109  case PP_Nested_Init:
1110  if (NULL == pp->nested_boundary)
1111  {
1112  pp->state = PP_Error;
1113  return MHD_NO;
1114  }
1115  if (MHD_NO == find_boundary (pp,
1116  pp->nested_boundary,
1117  pp->nlen,
1118  &ioff,
1120  PP_NextBoundary /* or PP_Error? */))
1121  {
1122  if (pp->state == PP_Error)
1123  return MHD_NO;
1124  goto END;
1125  }
1126  break;
1128  /* remember what headers were given
1129  globally */
1130  pp->have = NE_none;
1131  if (NULL != pp->content_name)
1132  pp->have |= NE_content_name;
1133  if (NULL != pp->content_type)
1134  pp->have |= NE_content_type;
1135  if (NULL != pp->content_filename)
1136  pp->have |= NE_content_filename;
1137  if (NULL != pp->content_transfer_encoding)
1138  pp->have |= NE_content_transfer_encoding;
1139  pp->state = PP_Nested_ProcessEntryHeaders;
1140  state_changed = 1;
1141  break;
1143  pp->value_offset = 0;
1144  if (MHD_NO ==
1146  &ioff,
1148  {
1149  if (pp->state == PP_Error)
1150  return MHD_NO;
1151  else
1152  goto END;
1153  }
1154  state_changed = 1;
1155  break;
1157  if (MHD_NO == process_value_to_boundary (pp,
1158  &ioff,
1159  pp->nested_boundary,
1160  pp->nlen,
1162  PP_NextBoundary))
1163  {
1164  if (pp->state == PP_Error)
1165  return MHD_NO;
1166  break;
1167  }
1168  break;
1170  free_unmarked (pp);
1171  pp->state = PP_Nested_ProcessEntryHeaders;
1172  state_changed = 1;
1173  break;
1174  default:
1176  __FILE__,
1177  __LINE__,
1178  NULL); /* should never happen! */
1179  }
1180 AGAIN:
1181  if (ioff > 0)
1182  {
1183  memmove (buf,
1184  &buf[ioff],
1185  pp->buffer_pos - ioff);
1186  pp->buffer_pos -= ioff;
1187  ioff = 0;
1188  state_changed = 1;
1189  }
1190  }
1191 END:
1192  if (0 != ioff)
1193  {
1194  memmove (buf,
1195  &buf[ioff],
1196  pp->buffer_pos - ioff);
1197  pp->buffer_pos -= ioff;
1198  }
1199  if (poff < post_data_len)
1200  {
1201  pp->state = PP_Error;
1202  return MHD_NO; /* serious error */
1203  }
1204  return MHD_YES;
1205 }
1206 
1207 
1221 int
1222 MHD_post_process (struct MHD_PostProcessor *pp,
1223  const char *post_data,
1224  size_t post_data_len)
1225 {
1226  if (0 == post_data_len)
1227  return MHD_YES;
1228  if (NULL == pp)
1229  return MHD_NO;
1231  pp->encoding,
1234  return post_process_urlencoded (pp,
1235  post_data,
1236  post_data_len);
1238  pp->encoding,
1241  return post_process_multipart (pp,
1242  post_data,
1243  post_data_len);
1244  /* this should never be reached */
1245  return MHD_NO;
1246 }
1247 
1248 
1259 int
1260 MHD_destroy_post_processor (struct MHD_PostProcessor *pp)
1261 {
1262  int ret;
1263 
1264  if (NULL == pp)
1265  return MHD_YES;
1266  if (PP_ProcessValue == pp->state)
1267  {
1268  /* key without terminated value left at the end of the
1269  buffer; fake receiving a termination character to
1270  ensure it is also processed */
1272  "\n",
1273  1);
1274  }
1275  /* These internal strings need cleaning up since
1276  the post-processing may have been interrupted
1277  at any stage */
1278  if ( (pp->xbuf_pos > 0) ||
1279  ( (pp->state != PP_Done) &&
1280  (pp->state != PP_ExpectNewLine) ) )
1281  ret = MHD_NO;
1282  else
1283  ret = MHD_YES;
1284  pp->have = NE_none;
1285  free_unmarked (pp);
1286  if (NULL != pp->nested_boundary)
1287  free (pp->nested_boundary);
1288  free (pp);
1289  return ret;
1290 }
1291 
1292 
1293 /* end of postprocessor.c */
RN_Full
Definition: postprocessor.c:85
mhd_compat.h
Header for platform missing functions.
NE_State
NE_State
Definition: postprocessor.c:105
PP_Nested_ProcessValueToBoundary
Definition: postprocessor.c:62
process_multipart_headers
static int process_multipart_headers(struct MHD_PostProcessor *pp, size_t *ioffptr, enum PP_State next_state)
Definition: postprocessor.c:688
MHD_YES
#define MHD_YES
Definition: microhttpd.h:140
MHD_unescape_plus
void MHD_unescape_plus(char *arg)
Definition: internal.c:123
mhd_panic_cls
void * mhd_panic_cls
Definition: panic.c:36
MHD_post_process
_MHD_EXTERN int MHD_post_process(struct MHD_PostProcessor *pp, const char *post_data, size_t post_data_len)
Definition: postprocessor.c:1222
PP_Nested_ProcessEntryHeaders
Definition: postprocessor.c:61
MHD_HTTP_POST_ENCODING_FORM_URLENCODED
#define MHD_HTTP_POST_ENCODING_FORM_URLENCODED
Definition: microhttpd.h:981
MHD_PostDataIterator
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
NE_content_transfer_encoding
Definition: postprocessor.c:111
MHD_calloc_
void * MHD_calloc_(size_t nelem, size_t elsize)
Definition: mhd_compat.c:98
PP_Init
Definition: postprocessor.c:45
PP_ExpectNewLine
Definition: postprocessor.c:50
RN_OptN
Definition: postprocessor.c:79
NE_content_type
Definition: postprocessor.c:109
PP_Nested_PerformMarking
Definition: postprocessor.c:60
internal.h
internal shared structures
MHD_lookup_connection_value_n
_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:567
RN_Inactive
Definition: postprocessor.c:73
NULL
#define NULL
Definition: reason_phrase.c:30
PP_PerformCheckMultipart
Definition: postprocessor.c:54
MHD_HTTP_HEADER_CONTENT_TYPE
#define MHD_HTTP_HEADER_CONTENT_TYPE
Definition: microhttpd.h:572
free_unmarked
static void free_unmarked(struct MHD_PostProcessor *pp)
Definition: postprocessor.c:862
PP_PerformCleanup
Definition: postprocessor.c:56
find_boundary
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)
Definition: postprocessor.c:569
MHD_Connection::state
enum MHD_CONNECTION_STATE state
Definition: internal.h:924
NE_content_name
Definition: postprocessor.c:108
NE_none
Definition: postprocessor.c:107
try_match_header
static int try_match_header(const char *prefix, size_t prefix_len, char *line, char **suffix)
Definition: postprocessor.c:533
PP_Nested_PerformCleanup
Definition: postprocessor.c:63
MHD_POSTDATA_KIND
Definition: microhttpd.h:1789
MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA
#define MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA
Definition: microhttpd.h:983
MHD_http_unescape
_MHD_EXTERN size_t MHD_http_unescape(char *val)
Definition: internal.c:142
RN_State
RN_State
Definition: postprocessor.c:68
PP_ProcessEntryHeaders
Definition: postprocessor.c:53
try_get_value
static void try_get_value(const char *buf, const char *key, char **destination)
Definition: postprocessor.c:630
MHD_STATICSTR_LEN_
#define MHD_STATICSTR_LEN_(macro)
Definition: mhd_str.h:45
mhd_str.h
Header for string manipulating helpers.
MHD_create_post_processor
_MHD_EXTERN struct MHD_PostProcessor * MHD_create_post_processor(struct MHD_Connection *connection, size_t buffer_size, MHD_PostDataIterator iter, void *iter_cls)
Definition: postprocessor.c:274
MHD_destroy_post_processor
_MHD_EXTERN int MHD_destroy_post_processor(struct MHD_PostProcessor *pp)
Definition: postprocessor.c:1260
PP_NextBoundary
Definition: postprocessor.c:46
MHD_HEADER_KIND
Definition: microhttpd.h:1773
XBUF_SIZE
#define XBUF_SIZE
Definition: postprocessor.c:35
PP_Error
Definition: postprocessor.c:43
post_process_multipart
static int post_process_multipart(struct MHD_PostProcessor *pp, const char *post_data, size_t post_data_len)
Definition: postprocessor.c:900
PP_Nested_Init
Definition: postprocessor.c:59
MHD_Connection
Definition: internal.h:633
PP_ProcessValue
Definition: postprocessor.c:49
post_process_urlencoded
static int post_process_urlencoded(struct MHD_PostProcessor *pp, const char *post_data, size_t post_data_len)
Definition: postprocessor.c:359
RN_Dash
Definition: postprocessor.c:91
PP_State
PP_State
Definition: postprocessor.c:40
MHD_NO
#define MHD_NO
Definition: microhttpd.h:145
PP_ProcessValueToBoundary
Definition: postprocessor.c:55
RN_Dash2
Definition: postprocessor.c:96
NE_content_filename
Definition: postprocessor.c:110
mhd_panic
MHD_PanicCallback mhd_panic
Definition: panic.c:31
MHD_str_equal_caseless_n_
int MHD_str_equal_caseless_n_(const char *const str1, const char *const str2, size_t maxlen)
Definition: mhd_str.c:378
PP_Done
Definition: postprocessor.c:44
process_value_to_boundary
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)
Definition: postprocessor.c:762