GNU libmicrohttpd  0.9.72
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 #include "mhd_assert.h"
30 
36 #define XBUF_SIZE 512
37 
42 {
43  /* general states */
48 
49  /* url encoding-states */
53 
54  /* post encoding-states */
59 
60  /* nested post-encoding states */
66 
67 };
68 
69 
71 {
76 
81  RN_OptN = 1,
82 
87  RN_Full = 2,
88 
93  RN_Dash = 3,
94 
98  RN_Dash2 = 4
99 };
100 
101 
108 {
109  NE_none = 0,
114 };
115 
116 
121 struct MHD_PostProcessor
122 {
123 
128  struct MHD_Connection *connection;
129 
134 
138  void *cls;
139 
143  const char *encoding;
144 
148  const char *boundary;
149 
153  char *nested_boundary;
154 
158  char *content_name;
159 
163  char *content_type;
164 
168  char *content_filename;
169 
173  char *content_transfer_encoding;
174 
178  char xbuf[2];
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  bool must_ikvi;
219 
224  bool must_unescape_key;
225 
229  enum PP_State state;
230 
237  enum RN_State skip_rn;
238 
243  enum PP_State dash_state;
244 
249  enum NE_State have;
250 
251 };
252 
253 
279 struct MHD_PostProcessor *
281  size_t buffer_size,
283  void *iter_cls)
284 {
285  struct MHD_PostProcessor *ret;
286  const char *encoding;
287  const char *boundary;
288  size_t blen;
289 
290  if ( (buffer_size < 256) ||
291  (NULL == connection) ||
292  (NULL == iter))
294  __FILE__,
295  __LINE__,
296  NULL);
297  if (MHD_NO == MHD_lookup_connection_value_n (connection,
302  &encoding,
303  NULL))
304  return NULL;
305  boundary = NULL;
307  encoding,
310  {
312  encoding,
315  return NULL;
316  boundary =
318  /* Q: should this be "strcasestr"? */
319  boundary = strstr (boundary, "boundary=");
320  if (NULL == boundary)
321  return NULL; /* failed to determine boundary */
322  boundary += MHD_STATICSTR_LEN_ ("boundary=");
323  blen = strlen (boundary);
324  if ( (blen < 2) ||
325  (blen * 2 + 2 > buffer_size) )
326  return NULL; /* (will be) out of memory or invalid boundary */
327  if ( (boundary[0] == '"') &&
328  (boundary[blen - 1] == '"') )
329  {
330  /* remove enclosing quotes */
331  ++boundary;
332  blen -= 2;
333  }
334  }
335  else
336  blen = 0;
337  buffer_size += 4; /* round up to get nice block sizes despite boundary search */
338 
339  /* add +1 to ensure we ALWAYS have a zero-termination at the end */
340  if (NULL == (ret = MHD_calloc_ (1, sizeof (struct MHD_PostProcessor)
341  + buffer_size + 1)))
342  return NULL;
343  ret->connection = connection;
344  ret->ikvi = iter;
345  ret->cls = iter_cls;
346  ret->encoding = encoding;
347  ret->buffer_size = buffer_size;
348  ret->state = PP_Init;
349  ret->blen = blen;
350  ret->boundary = boundary;
351  ret->skip_rn = RN_Inactive;
352  return ret;
353 }
354 
355 
373 static void
374 process_value (struct MHD_PostProcessor *pp,
375  const char *value_start,
376  const char *value_end,
377  const char *last_escape)
378 {
379  char xbuf[XBUF_SIZE + 1];
380  size_t xoff;
381 
382  mhd_assert (pp->xbuf_pos < sizeof (xbuf));
383  /* move remaining input from previous round into processing buffer */
384  memcpy (xbuf,
385  pp->xbuf,
386  pp->xbuf_pos);
387  xoff = pp->xbuf_pos;
388  pp->xbuf_pos = 0;
389  if (NULL != last_escape)
390  {
391  if (((size_t) (value_end - last_escape)) < sizeof (pp->xbuf))
392  {
393  pp->xbuf_pos = value_end - last_escape;
394  memcpy (pp->xbuf,
395  last_escape,
396  value_end - last_escape);
397  value_end = last_escape;
398  }
399  }
400  while ( (value_start != value_end) ||
401  (pp->must_ikvi) ||
402  (xoff > 0) )
403  {
404  size_t delta = value_end - value_start;
405  bool cut = false;
406  size_t clen = 0;
407 
408  if (delta > XBUF_SIZE - xoff)
409  delta = XBUF_SIZE - xoff;
410  /* move (additional) input into processing buffer */
411  memcpy (&xbuf[xoff],
412  value_start,
413  delta);
414  xoff += delta;
415  value_start += delta;
416  /* find if escape sequence is at the end of the processing buffer;
417  if so, exclude those from processing (reduce delta to point at
418  end of processed region) */
419  if ( (xoff > 0) &&
420  ('%' == xbuf[xoff - 1]) )
421  {
422  cut = (xoff != XBUF_SIZE);
423  xoff--;
424  if (cut)
425  {
426  /* move escape sequence into buffer for next function invocation */
427  pp->xbuf[0] = '%';
428  pp->xbuf_pos = 1;
429  }
430  else
431  {
432  /* just skip escape sequence for next loop iteration */
433  delta = xoff;
434  clen = 1;
435  }
436  }
437  else if ( (xoff > 1) &&
438  ('%' == xbuf[xoff - 2]) )
439  {
440  cut = (xoff != XBUF_SIZE);
441  xoff -= 2;
442  if (cut)
443  {
444  /* move escape sequence into buffer for next function invocation */
445  memcpy (pp->xbuf,
446  &xbuf[xoff],
447  2);
448  pp->xbuf_pos = 2;
449  }
450  else
451  {
452  /* just skip escape sequence for next loop iteration */
453  delta = xoff;
454  clen = 2;
455  }
456  }
457  mhd_assert (xoff < sizeof (xbuf));
458  /* unescape */
459  xbuf[xoff] = '\0'; /* 0-terminate in preparation */
460  MHD_unescape_plus (xbuf);
461  xoff = MHD_http_unescape (xbuf);
462  /* finally: call application! */
463  if ( (pp->must_ikvi || (0 != xoff)) )
464  {
465  pp->must_ikvi = false;
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;
478  }
479  }
480  pp->value_offset += xoff;
481  if (cut)
482  break;
483  xbuf[delta] = '%'; /* undo 0-termination */
484  memmove (xbuf,
485  &xbuf[delta],
486  clen);
487  xoff = clen;
488  }
489 }
490 
491 
500 static int
501 post_process_urlencoded (struct MHD_PostProcessor *pp,
502  const char *post_data,
503  size_t post_data_len)
504 {
505  char *kbuf = (char *) &pp[1];
506  size_t poff;
507  const char *start_key = NULL;
508  const char *end_key = NULL;
509  const char *start_value = NULL;
510  const char *end_value = NULL;
511  const char *last_escape = NULL;
512 
513  mhd_assert (PP_Callback != pp->state);
514 
515  poff = 0;
516  while ( ( (poff < post_data_len) ||
517  (pp->state == PP_Callback) ) &&
518  (pp->state != PP_Error) )
519  {
520  switch (pp->state)
521  {
522  case PP_Error:
523  /* clearly impossible as per while loop invariant */
524  abort ();
525  break;
526  case PP_Init:
527  /* key phase */
528  if (NULL == start_key)
529  start_key = &post_data[poff];
530  pp->must_ikvi = true;
531  switch (post_data[poff])
532  {
533  case '=':
534  /* Case: 'key=' */
535  end_key = &post_data[poff];
536  poff++;
537  pp->state = PP_ProcessValue;
538  break;
539  case '&':
540  /* Case: 'key&' */
541  end_key = &post_data[poff];
542  mhd_assert (NULL == start_value);
543  mhd_assert (NULL == end_value);
544  poff++;
545  pp->state = PP_Callback;
546  break;
547  case '\n':
548  case '\r':
549  /* Case: 'key\n' or 'key\r' */
550  end_key = &post_data[poff];
551  poff++;
552  pp->state = PP_Done;
553  break;
554  default:
555  /* normal character, advance! */
556  poff++;
557  continue;
558  }
559  break; /* end PP_Init */
560  case PP_ProcessValue:
561  if (NULL == start_value)
562  start_value = &post_data[poff];
563  switch (post_data[poff])
564  {
565  case '=':
566  /* case 'key==' */
567  pp->state = PP_Error;
568  continue;
569  case '&':
570  /* case 'value&' */
571  end_value = &post_data[poff];
572  poff++;
573  if (pp->must_ikvi ||
574  (start_value != end_value) )
575  {
576  pp->state = PP_Callback;
577  }
578  else
579  {
580  pp->buffer_pos = 0;
581  pp->value_offset = 0;
582  pp->state = PP_Init;
583  start_value = NULL;
584  end_value = NULL;
585  }
586  continue;
587  case '\n':
588  case '\r':
589  /* Case: 'value\n' or 'value\r' */
590  end_value = &post_data[poff];
591  poff++;
592  if (pp->must_ikvi)
593  pp->state = PP_Callback;
594  else
595  pp->state = PP_Done;
596  break;
597  case '%':
598  last_escape = &post_data[poff];
599  poff++;
600  break;
601  case '0':
602  case '1':
603  case '2':
604  case '3':
605  case '4':
606  case '5':
607  case '6':
608  case '7':
609  case '8':
610  case '9':
611  /* character, may be part of escaping */
612  poff++;
613  continue;
614  default:
615  /* normal character, no more escaping! */
616  last_escape = NULL;
617  poff++;
618  continue;
619  }
620  break; /* end PP_ProcessValue */
621  case PP_Done:
622  switch (post_data[poff])
623  {
624  case '\n':
625  case '\r':
626  poff++;
627  continue;
628  }
629  /* unexpected data at the end, fail! */
630  pp->state = PP_Error;
631  break;
632  case PP_Callback:
633  if ( (pp->buffer_pos + (end_key - start_key) >=
634  pp->buffer_size) ||
635  (pp->buffer_pos + (end_key - start_key) <
636  pp->buffer_pos) )
637  {
638  /* key too long, cannot parse! */
639  pp->state = PP_Error;
640  continue;
641  }
642  /* compute key, if we have not already */
643  if (NULL != start_key)
644  {
645  memcpy (&kbuf[pp->buffer_pos],
646  start_key,
647  end_key - start_key);
648  pp->buffer_pos += end_key - start_key;
649  start_key = NULL;
650  end_key = NULL;
651  pp->must_unescape_key = true;
652  }
653  if (pp->must_unescape_key)
654  {
655  kbuf[pp->buffer_pos] = '\0'; /* 0-terminate key */
656  MHD_unescape_plus (kbuf);
657  MHD_http_unescape (kbuf);
658  pp->must_unescape_key = false;
659  }
660  process_value (pp,
661  start_value,
662  end_value,
663  NULL);
664  pp->value_offset = 0;
665  start_value = NULL;
666  end_value = NULL;
667  pp->buffer_pos = 0;
668  pp->state = PP_Init;
669  break;
670  default:
672  __FILE__,
673  __LINE__,
674  NULL); /* should never happen! */
675  }
676  }
677 
678  /* save remaining data for next iteration */
679  if (NULL != start_key)
680  {
681  if (NULL == end_key)
682  end_key = &post_data[poff];
683  if (pp->buffer_pos + (end_key - start_key) >= pp->buffer_size)
684  {
685  pp->state = PP_Error;
686  return MHD_NO;
687  }
688  memcpy (&kbuf[pp->buffer_pos],
689  start_key,
690  end_key - start_key);
691  pp->buffer_pos += end_key - start_key;
692  pp->must_unescape_key = true;
693  start_key = NULL;
694  end_key = NULL;
695  }
696  if ( (NULL != start_value) &&
697  (PP_ProcessValue == pp->state) )
698  {
699  /* compute key, if we have not already */
700  if (pp->must_unescape_key)
701  {
702  kbuf[pp->buffer_pos] = '\0'; /* 0-terminate key */
703  MHD_unescape_plus (kbuf);
704  MHD_http_unescape (kbuf);
705  pp->must_unescape_key = false;
706  }
707  if (NULL == end_value)
708  end_value = &post_data[poff];
709  process_value (pp,
710  start_value,
711  end_value,
712  last_escape);
713  pp->must_ikvi = false;
714  }
715  if (PP_Error == pp->state)
716  {
717  /* State in error, returning failure */
718  return MHD_NO;
719  }
720  return MHD_YES;
721 }
722 
723 
734 static int
735 try_match_header (const char *prefix,
736  size_t prefix_len,
737  char *line,
738  char **suffix)
739 {
740  if (NULL != *suffix)
741  return MHD_NO;
742  while (0 != *line)
743  {
744  if (MHD_str_equal_caseless_n_ (prefix,
745  line,
746  prefix_len))
747  {
748  *suffix = strdup (&line[prefix_len]);
749  return MHD_YES;
750  }
751  ++line;
752  }
753  return MHD_NO;
754 }
755 
756 
770 static int
771 find_boundary (struct MHD_PostProcessor *pp,
772  const char *boundary,
773  size_t blen,
774  size_t *ioffptr,
775  enum PP_State next_state,
776  enum PP_State next_dash_state)
777 {
778  char *buf = (char *) &pp[1];
779  const char *dash;
780 
781  if (pp->buffer_pos < 2 + blen)
782  {
783  if (pp->buffer_pos == pp->buffer_size)
784  pp->state = PP_Error; /* out of memory */
785  /* ++(*ioffptr); */
786  return MHD_NO; /* not enough data */
787  }
788  if ( (0 != memcmp ("--",
789  buf,
790  2)) ||
791  (0 != memcmp (&buf[2],
792  boundary,
793  blen)))
794  {
795  if (pp->state != PP_Init)
796  {
797  /* garbage not allowed */
798  pp->state = PP_Error;
799  }
800  else
801  {
802  /* skip over garbage (RFC 2046, 5.1.1) */
803  dash = memchr (buf,
804  '-',
805  pp->buffer_pos);
806  if (NULL == dash)
807  (*ioffptr) += pp->buffer_pos; /* skip entire buffer */
808  else if (dash == buf)
809  (*ioffptr)++; /* at least skip one byte */
810  else
811  (*ioffptr) += dash - buf; /* skip to first possible boundary */
812  }
813  return MHD_NO; /* expected boundary */
814  }
815  /* remove boundary from buffer */
816  (*ioffptr) += 2 + blen;
817  /* next: start with headers */
818  pp->skip_rn = RN_Dash;
819  pp->state = next_state;
820  pp->dash_state = next_dash_state;
821  return MHD_YES;
822 }
823 
824 
831 static void
832 try_get_value (const char *buf,
833  const char *key,
834  char **destination)
835 {
836  const char *spos;
837  const char *bpos;
838  const char *endv;
839  size_t klen;
840  size_t vlen;
841 
842  if (NULL != *destination)
843  return;
844  bpos = buf;
845  klen = strlen (key);
846  while (NULL != (spos = strstr (bpos, key)))
847  {
848  if ( (spos[klen] != '=') ||
849  ( (spos != buf) &&
850  (spos[-1] != ' ') ) )
851  {
852  /* no match */
853  bpos = spos + 1;
854  continue;
855  }
856  if (spos[klen + 1] != '"')
857  return; /* not quoted */
858  if (NULL == (endv = strchr (&spos[klen + 2],
859  '\"')))
860  return; /* no end-quote */
861  vlen = endv - spos - klen - 1;
862  *destination = malloc (vlen);
863  if (NULL == *destination)
864  return; /* out of memory */
865  (*destination)[vlen - 1] = '\0';
866  memcpy (*destination,
867  &spos[klen + 2],
868  vlen - 1);
869  return; /* success */
870  }
871 }
872 
873 
889 static int
890 process_multipart_headers (struct MHD_PostProcessor *pp,
891  size_t *ioffptr,
892  enum PP_State next_state)
893 {
894  char *buf = (char *) &pp[1];
895  size_t newline;
896 
897  newline = 0;
898  while ( (newline < pp->buffer_pos) &&
899  (buf[newline] != '\r') &&
900  (buf[newline] != '\n') )
901  newline++;
902  if (newline == pp->buffer_size)
903  {
904  pp->state = PP_Error;
905  return MHD_NO; /* out of memory */
906  }
907  if (newline == pp->buffer_pos)
908  return MHD_NO; /* will need more data */
909  if (0 == newline)
910  {
911  /* empty line - end of headers */
912  pp->skip_rn = RN_Full;
913  pp->state = next_state;
914  return MHD_YES;
915  }
916  /* got an actual header */
917  if (buf[newline] == '\r')
918  pp->skip_rn = RN_OptN;
919  buf[newline] = '\0';
920  if (MHD_str_equal_caseless_n_ ("Content-disposition: ",
921  buf,
922  MHD_STATICSTR_LEN_ ("Content-disposition: ")))
923  {
924  try_get_value (&buf[MHD_STATICSTR_LEN_ ("Content-disposition: ")],
925  "name",
926  &pp->content_name);
927  try_get_value (&buf[MHD_STATICSTR_LEN_ ("Content-disposition: ")],
928  "filename",
929  &pp->content_filename);
930  }
931  else
932  {
933  try_match_header ("Content-type: ",
934  MHD_STATICSTR_LEN_ ("Content-type: "),
935  buf,
936  &pp->content_type);
937  try_match_header ("Content-Transfer-Encoding: ",
938  MHD_STATICSTR_LEN_ ("Content-Transfer-Encoding: "),
939  buf,
940  &pp->content_transfer_encoding);
941  }
942  (*ioffptr) += newline + 1;
943  return MHD_YES;
944 }
945 
946 
963 static int
964 process_value_to_boundary (struct MHD_PostProcessor *pp,
965  size_t *ioffptr,
966  const char *boundary,
967  size_t blen,
968  enum PP_State next_state,
969  enum PP_State next_dash_state)
970 {
971  char *buf = (char *) &pp[1];
972  size_t newline;
973  const char *r;
974 
975  /* all data in buf until the boundary
976  (\r\n--+boundary) is part of the value */
977  newline = 0;
978  while (1)
979  {
980  while (newline + 4 < pp->buffer_pos)
981  {
982  r = memchr (&buf[newline],
983  '\r',
984  pp->buffer_pos - newline - 4);
985  if (NULL == r)
986  {
987  newline = pp->buffer_pos - 4;
988  break;
989  }
990  newline = r - buf;
991  if (0 == memcmp ("\r\n--",
992  &buf[newline],
993  4))
994  break;
995  newline++;
996  }
997  if (newline + blen + 4 <= pp->buffer_pos)
998  {
999  /* can check boundary */
1000  if (0 != memcmp (&buf[newline + 4],
1001  boundary,
1002  blen))
1003  {
1004  /* no boundary, "\r\n--" is part of content, skip */
1005  newline += 4;
1006  continue;
1007  }
1008  else
1009  {
1010  /* boundary found, process until newline then
1011  skip boundary and go back to init */
1012  pp->skip_rn = RN_Dash;
1013  pp->state = next_state;
1014  pp->dash_state = next_dash_state;
1015  (*ioffptr) += blen + 4; /* skip boundary as well */
1016  buf[newline] = '\0';
1017  break;
1018  }
1019  }
1020  else
1021  {
1022  /* cannot check for boundary, process content that
1023  we have and check again later; except, if we have
1024  no content, abort (out of memory) */
1025  if ( (0 == newline) &&
1026  (pp->buffer_pos == pp->buffer_size) )
1027  {
1028  pp->state = PP_Error;
1029  return MHD_NO;
1030  }
1031  break;
1032  }
1033  }
1034  /* newline is either at beginning of boundary or
1035  at least at the last character that we are sure
1036  is not part of the boundary */
1037  if ( ( (pp->must_ikvi) ||
1038  (0 != newline) ) &&
1039  (MHD_NO == pp->ikvi (pp->cls,
1041  pp->content_name,
1042  pp->content_filename,
1043  pp->content_type,
1044  pp->content_transfer_encoding,
1045  buf,
1046  pp->value_offset,
1047  newline)) )
1048  {
1049  pp->state = PP_Error;
1050  return MHD_NO;
1051  }
1052  pp->must_ikvi = false;
1053  pp->value_offset += newline;
1054  (*ioffptr) += newline;
1055  return MHD_YES;
1056 }
1057 
1058 
1063 static void
1064 free_unmarked (struct MHD_PostProcessor *pp)
1065 {
1066  if ( (NULL != pp->content_name) &&
1067  (0 == (pp->have & NE_content_name)) )
1068  {
1069  free (pp->content_name);
1070  pp->content_name = NULL;
1071  }
1072  if ( (NULL != pp->content_type) &&
1073  (0 == (pp->have & NE_content_type)) )
1074  {
1075  free (pp->content_type);
1076  pp->content_type = NULL;
1077  }
1078  if ( (NULL != pp->content_filename) &&
1079  (0 == (pp->have & NE_content_filename)) )
1080  {
1081  free (pp->content_filename);
1082  pp->content_filename = NULL;
1083  }
1084  if ( (NULL != pp->content_transfer_encoding) &&
1085  (0 == (pp->have & NE_content_transfer_encoding)) )
1086  {
1087  free (pp->content_transfer_encoding);
1088  pp->content_transfer_encoding = NULL;
1089  }
1090 }
1091 
1092 
1101 static int
1102 post_process_multipart (struct MHD_PostProcessor *pp,
1103  const char *post_data,
1104  size_t post_data_len)
1105 {
1106  char *buf;
1107  size_t max;
1108  size_t ioff;
1109  size_t poff;
1110  int state_changed;
1111 
1112  buf = (char *) &pp[1];
1113  ioff = 0;
1114  poff = 0;
1115  state_changed = 1;
1116  while ( (poff < post_data_len) ||
1117  ( (pp->buffer_pos > 0) &&
1118  (0 != state_changed) ) )
1119  {
1120  /* first, move as much input data
1121  as possible to our internal buffer */
1122  max = pp->buffer_size - pp->buffer_pos;
1123  if (max > post_data_len - poff)
1124  max = post_data_len - poff;
1125  memcpy (&buf[pp->buffer_pos],
1126  &post_data[poff],
1127  max);
1128  poff += max;
1129  pp->buffer_pos += max;
1130  if ( (0 == max) &&
1131  (0 == state_changed) &&
1132  (poff < post_data_len) )
1133  {
1134  pp->state = PP_Error;
1135  return MHD_NO; /* out of memory */
1136  }
1137  state_changed = 0;
1138 
1139  /* first state machine for '\r'-'\n' and '--' handling */
1140  switch (pp->skip_rn)
1141  {
1142  case RN_Inactive:
1143  break;
1144  case RN_OptN:
1145  if (buf[0] == '\n')
1146  {
1147  ioff++;
1148  pp->skip_rn = RN_Inactive;
1149  goto AGAIN;
1150  }
1151  /* fall-through! */
1152  case RN_Dash:
1153  if (buf[0] == '-')
1154  {
1155  ioff++;
1156  pp->skip_rn = RN_Dash2;
1157  goto AGAIN;
1158  }
1159  pp->skip_rn = RN_Full;
1160  /* fall-through! */
1161  case RN_Full:
1162  if (buf[0] == '\r')
1163  {
1164  if ( (pp->buffer_pos > 1) &&
1165  ('\n' == buf[1]) )
1166  {
1167  pp->skip_rn = RN_Inactive;
1168  ioff += 2;
1169  }
1170  else
1171  {
1172  pp->skip_rn = RN_OptN;
1173  ioff++;
1174  }
1175  goto AGAIN;
1176  }
1177  if (buf[0] == '\n')
1178  {
1179  ioff++;
1180  pp->skip_rn = RN_Inactive;
1181  goto AGAIN;
1182  }
1183  pp->skip_rn = RN_Inactive;
1184  pp->state = PP_Error;
1185  return MHD_NO; /* no '\r\n' */
1186  case RN_Dash2:
1187  if (buf[0] == '-')
1188  {
1189  ioff++;
1190  pp->skip_rn = RN_Full;
1191  pp->state = pp->dash_state;
1192  goto AGAIN;
1193  }
1194  pp->state = PP_Error;
1195  break;
1196  }
1197 
1198  /* main state engine */
1199  switch (pp->state)
1200  {
1201  case PP_Error:
1202  return MHD_NO;
1203  case PP_Done:
1204  /* did not expect to receive more data */
1205  pp->state = PP_Error;
1206  return MHD_NO;
1207  case PP_Init:
1219  (void) find_boundary (pp,
1220  pp->boundary,
1221  pp->blen,
1222  &ioff,
1224  PP_Done);
1225  break;
1226  case PP_NextBoundary:
1227  if (MHD_NO == find_boundary (pp,
1228  pp->boundary,
1229  pp->blen,
1230  &ioff,
1232  PP_Done))
1233  {
1234  if (pp->state == PP_Error)
1235  return MHD_NO;
1236  goto END;
1237  }
1238  break;
1240  pp->must_ikvi = true;
1241  if (MHD_NO ==
1243  &ioff,
1245  {
1246  if (pp->state == PP_Error)
1247  return MHD_NO;
1248  else
1249  goto END;
1250  }
1251  state_changed = 1;
1252  break;
1254  if ( (NULL != pp->content_type) &&
1255  (MHD_str_equal_caseless_n_ (pp->content_type,
1256  "multipart/mixed",
1257  MHD_STATICSTR_LEN_ ("multipart/mixed"))))
1258  {
1259  pp->nested_boundary = strstr (pp->content_type,
1260  "boundary=");
1261  if (NULL == pp->nested_boundary)
1262  {
1263  pp->state = PP_Error;
1264  return MHD_NO;
1265  }
1266  pp->nested_boundary =
1267  strdup (&pp->nested_boundary[MHD_STATICSTR_LEN_ ("boundary=")]);
1268  if (NULL == pp->nested_boundary)
1269  {
1270  /* out of memory */
1271  pp->state = PP_Error;
1272  return MHD_NO;
1273  }
1274  /* free old content type, we will need that field
1275  for the content type of the nested elements */
1276  free (pp->content_type);
1277  pp->content_type = NULL;
1278  pp->nlen = strlen (pp->nested_boundary);
1279  pp->state = PP_Nested_Init;
1280  state_changed = 1;
1281  break;
1282  }
1283  pp->state = PP_ProcessValueToBoundary;
1284  pp->value_offset = 0;
1285  state_changed = 1;
1286  break;
1288  if (MHD_NO == process_value_to_boundary (pp,
1289  &ioff,
1290  pp->boundary,
1291  pp->blen,
1293  PP_Done))
1294  {
1295  if (pp->state == PP_Error)
1296  return MHD_NO;
1297  break;
1298  }
1299  break;
1300  case PP_PerformCleanup:
1301  /* clean up state of one multipart form-data element! */
1302  pp->have = NE_none;
1303  free_unmarked (pp);
1304  if (NULL != pp->nested_boundary)
1305  {
1306  free (pp->nested_boundary);
1307  pp->nested_boundary = NULL;
1308  }
1309  pp->state = PP_ProcessEntryHeaders;
1310  state_changed = 1;
1311  break;
1312  case PP_Nested_Init:
1313  if (NULL == pp->nested_boundary)
1314  {
1315  pp->state = PP_Error;
1316  return MHD_NO;
1317  }
1318  if (MHD_NO == find_boundary (pp,
1319  pp->nested_boundary,
1320  pp->nlen,
1321  &ioff,
1323  PP_NextBoundary /* or PP_Error? */))
1324  {
1325  if (pp->state == PP_Error)
1326  return MHD_NO;
1327  goto END;
1328  }
1329  break;
1331  /* remember what headers were given
1332  globally */
1333  pp->have = NE_none;
1334  if (NULL != pp->content_name)
1335  pp->have |= NE_content_name;
1336  if (NULL != pp->content_type)
1337  pp->have |= NE_content_type;
1338  if (NULL != pp->content_filename)
1339  pp->have |= NE_content_filename;
1340  if (NULL != pp->content_transfer_encoding)
1341  pp->have |= NE_content_transfer_encoding;
1342  pp->state = PP_Nested_ProcessEntryHeaders;
1343  state_changed = 1;
1344  break;
1346  pp->value_offset = 0;
1347  if (MHD_NO ==
1349  &ioff,
1351  {
1352  if (pp->state == PP_Error)
1353  return MHD_NO;
1354  else
1355  goto END;
1356  }
1357  state_changed = 1;
1358  break;
1360  if (MHD_NO == process_value_to_boundary (pp,
1361  &ioff,
1362  pp->nested_boundary,
1363  pp->nlen,
1365  PP_NextBoundary))
1366  {
1367  if (pp->state == PP_Error)
1368  return MHD_NO;
1369  break;
1370  }
1371  break;
1373  free_unmarked (pp);
1374  pp->state = PP_Nested_ProcessEntryHeaders;
1375  state_changed = 1;
1376  break;
1377  default:
1379  __FILE__,
1380  __LINE__,
1381  NULL); /* should never happen! */
1382  }
1383 AGAIN:
1384  if (ioff > 0)
1385  {
1386  memmove (buf,
1387  &buf[ioff],
1388  pp->buffer_pos - ioff);
1389  pp->buffer_pos -= ioff;
1390  ioff = 0;
1391  state_changed = 1;
1392  }
1393  }
1394 END:
1395  if (0 != ioff)
1396  {
1397  memmove (buf,
1398  &buf[ioff],
1399  pp->buffer_pos - ioff);
1400  pp->buffer_pos -= ioff;
1401  }
1402  if (poff < post_data_len)
1403  {
1404  pp->state = PP_Error;
1405  return MHD_NO; /* serious error */
1406  }
1407  return MHD_YES;
1408 }
1409 
1410 
1424 enum MHD_Result
1425 MHD_post_process (struct MHD_PostProcessor *pp,
1426  const char *post_data,
1427  size_t post_data_len)
1428 {
1429  if (0 == post_data_len)
1430  return MHD_YES;
1431  if (NULL == pp)
1432  return MHD_NO;
1434  pp->encoding,
1437  return post_process_urlencoded (pp,
1438  post_data,
1439  post_data_len);
1441  pp->encoding,
1444  return post_process_multipart (pp,
1445  post_data,
1446  post_data_len);
1447  /* this should never be reached */
1448  return MHD_NO;
1449 }
1450 
1451 
1462 enum MHD_Result
1463 MHD_destroy_post_processor (struct MHD_PostProcessor *pp)
1464 {
1465  enum MHD_Result ret;
1466 
1467  if (NULL == pp)
1468  return MHD_YES;
1469  if (PP_ProcessValue == pp->state)
1470  {
1471  /* key without terminated value left at the end of the
1472  buffer; fake receiving a termination character to
1473  ensure it is also processed */
1475  "\n",
1476  1);
1477  }
1478  /* These internal strings need cleaning up since
1479  the post-processing may have been interrupted
1480  at any stage */
1481  if ( (pp->xbuf_pos > 0) ||
1482  ( (pp->state != PP_Done) &&
1483  (pp->state != PP_Init) ) )
1484  ret = MHD_NO;
1485  else
1486  ret = MHD_YES;
1487  pp->have = NE_none;
1488  free_unmarked (pp);
1489  if (NULL != pp->nested_boundary)
1490  free (pp->nested_boundary);
1491  free (pp);
1492  return ret;
1493 }
1494 
1495 
1496 /* end of postprocessor.c */
#define MHD_HTTP_HEADER_CONTENT_TYPE
Definition: microhttpd.h:581
#define MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA
Definition: microhttpd.h:1006
#define MHD_HTTP_POST_ENCODING_FORM_URLENCODED
Definition: microhttpd.h:1004
_MHD_EXTERN enum MHD_Result MHD_post_process(struct MHD_PostProcessor *pp, const char *post_data, size_t post_data_len)
_MHD_EXTERN struct MHD_PostProcessor * MHD_create_post_processor(struct MHD_Connection *connection, size_t buffer_size, MHD_PostDataIterator iter, void *iter_cls)
_MHD_EXTERN enum MHD_Result MHD_destroy_post_processor(struct MHD_PostProcessor *pp)
_MHD_EXTERN enum MHD_Result 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:460
void MHD_unescape_plus(char *arg)
Definition: internal.c:123
MHD_PanicCallback mhd_panic
Definition: panic.c:31
void * mhd_panic_cls
Definition: panic.c:36
#define mhd_assert(CHK)
Definition: mhd_assert.h:39
void * MHD_calloc_(size_t nelem, size_t elsize)
Definition: mhd_compat.c:98
int MHD_str_equal_caseless_n_(const char *const str1, const char *const str2, size_t maxlen)
Definition: mhd_str.c:378
#define MHD_STATICSTR_LEN_(macro)
Definition: mhd_str.h:45
#define NULL
Definition: reason_phrase.c:30
internal shared structures
macros for mhd_assert()
Header for platform missing functions.
Header for string manipulating helpers.
MHD_Result
Definition: microhttpd.h:142
@ MHD_YES
Definition: microhttpd.h:151
@ MHD_NO
Definition: microhttpd.h:146
_MHD_EXTERN size_t MHD_http_unescape(char *val)
Definition: internal.c:142
enum MHD_Result(* 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:2378
@ MHD_POSTDATA_KIND
Definition: microhttpd.h:1812
@ MHD_HEADER_KIND
Definition: microhttpd.h:1796
static int post_process_urlencoded(struct MHD_PostProcessor *pp, const char *post_data, size_t post_data_len)
static int try_match_header(const char *prefix, size_t prefix_len, char *line, char **suffix)
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)
RN_State
Definition: postprocessor.c:71
@ RN_Dash
Definition: postprocessor.c:93
@ RN_Inactive
Definition: postprocessor.c:75
@ RN_Full
Definition: postprocessor.c:87
@ RN_OptN
Definition: postprocessor.c:81
@ RN_Dash2
Definition: postprocessor.c:98
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 XBUF_SIZE
Definition: postprocessor.c:36
NE_State
@ NE_content_name
@ NE_content_type
@ NE_content_transfer_encoding
@ NE_none
@ NE_content_filename
static int post_process_multipart(struct MHD_PostProcessor *pp, const char *post_data, size_t post_data_len)
static void process_value(struct MHD_PostProcessor *pp, const char *value_start, const char *value_end, const char *last_escape)
PP_State
Definition: postprocessor.c:42
@ PP_PerformCleanup
Definition: postprocessor.c:58
@ PP_Error
Definition: postprocessor.c:44
@ PP_Nested_PerformMarking
Definition: postprocessor.c:62
@ PP_Init
Definition: postprocessor.c:46
@ PP_PerformCheckMultipart
Definition: postprocessor.c:56
@ PP_Nested_Init
Definition: postprocessor.c:61
@ PP_ProcessValue
Definition: postprocessor.c:50
@ PP_ExpectNewLine
Definition: postprocessor.c:52
@ PP_Nested_ProcessEntryHeaders
Definition: postprocessor.c:63
@ PP_Nested_PerformCleanup
Definition: postprocessor.c:65
@ PP_NextBoundary
Definition: postprocessor.c:47
@ PP_ProcessEntryHeaders
Definition: postprocessor.c:55
@ PP_ProcessValueToBoundary
Definition: postprocessor.c:57
@ PP_Done
Definition: postprocessor.c:45
@ PP_Callback
Definition: postprocessor.c:51
@ PP_Nested_ProcessValueToBoundary
Definition: postprocessor.c:64
static void try_get_value(const char *buf, const char *key, char **destination)
static void free_unmarked(struct MHD_PostProcessor *pp)
static int process_multipart_headers(struct MHD_PostProcessor *pp, size_t *ioffptr, enum PP_State next_state)
enum MHD_CONNECTION_STATE state
Definition: internal.h:983