GNU libmicrohttpd  0.9.75
postprocessor.c
Go to the documentation of this file.
1 /*
2  This file is part of libmicrohttpd
3  Copyright (C) 2007-2021 Daniel Pittman, Christian Grothoff, and Evgeny Grin
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 
27 #include "internal.h"
28 #include "mhd_str.h"
29 #include "mhd_compat.h"
30 #include "mhd_assert.h"
31 
37 #define XBUF_SIZE 512
38 
43 {
44  /* general states */
49 
50  /* url encoding-states */
54 
55  /* post encoding-states */
60 
61  /* nested post-encoding states */
67 
68 };
69 
70 
72 {
77 
82  RN_OptN = 1,
83 
88  RN_Full = 2,
89 
94  RN_Dash = 3,
95 
99  RN_Dash2 = 4
100 };
101 
102 
109 {
110  NE_none = 0,
115 };
116 
117 
122 struct MHD_PostProcessor
123 {
124 
129  struct MHD_Connection *connection;
130 
135 
139  void *cls;
140 
144  const char *encoding;
145 
149  const char *boundary;
150 
154  char *nested_boundary;
155 
159  char *content_name;
160 
164  char *content_type;
165 
169  char *content_filename;
170 
174  char *content_transfer_encoding;
175 
179  char xbuf[2];
180 
184  size_t buffer_size;
185 
189  size_t buffer_pos;
190 
194  size_t xbuf_pos;
195 
199  uint64_t value_offset;
200 
204  size_t blen;
205 
209  size_t nlen;
210 
219  bool must_ikvi;
220 
225  bool must_unescape_key;
226 
230  enum PP_State state;
231 
238  enum RN_State skip_rn;
239 
244  enum PP_State dash_state;
245 
250  enum NE_State have;
251 
252 };
253 
254 
255 struct MHD_PostProcessor *
257  size_t buffer_size,
259  void *iter_cls)
260 {
261  struct MHD_PostProcessor *ret;
262  const char *encoding;
263  const char *boundary;
264  size_t blen;
265 
266  if ( (buffer_size < 256) ||
267  (NULL == connection) ||
268  (NULL == iter))
270  __FILE__,
271  __LINE__,
272  NULL);
273  if (MHD_NO == MHD_lookup_connection_value_n (connection,
278  &encoding,
279  NULL))
280  return NULL;
281  boundary = NULL;
283  encoding,
286  {
288  encoding,
291  return NULL;
292  boundary =
294  /* Q: should this be "strcasestr"? */
295  boundary = strstr (boundary, "boundary=");
296  if (NULL == boundary)
297  return NULL; /* failed to determine boundary */
298  boundary += MHD_STATICSTR_LEN_ ("boundary=");
299  blen = strlen (boundary);
300  if ( (blen == 0) ||
301  (blen * 2 + 2 > buffer_size) )
302  return NULL; /* (will be) out of memory or invalid boundary */
303  if ( (boundary[0] == '"') &&
304  (boundary[blen - 1] == '"') )
305  {
306  /* remove enclosing quotes */
307  ++boundary;
308  blen -= 2;
309  }
310  }
311  else
312  blen = 0;
313  buffer_size += 4; /* round up to get nice block sizes despite boundary search */
314 
315  /* add +1 to ensure we ALWAYS have a zero-termination at the end */
316  if (NULL == (ret = MHD_calloc_ (1, sizeof (struct MHD_PostProcessor)
317  + buffer_size + 1)))
318  return NULL;
319  ret->connection = connection;
320  ret->ikvi = iter;
321  ret->cls = iter_cls;
322  ret->encoding = encoding;
323  ret->buffer_size = buffer_size;
324  ret->state = PP_Init;
325  ret->blen = blen;
326  ret->boundary = boundary;
327  ret->skip_rn = RN_Inactive;
328  return ret;
329 }
330 
331 
349 static void
350 process_value (struct MHD_PostProcessor *pp,
351  const char *value_start,
352  const char *value_end,
353  const char *last_escape)
354 {
355  char xbuf[XBUF_SIZE + 1];
356  size_t xoff;
357 
358  mhd_assert (pp->xbuf_pos < sizeof (xbuf));
359  /* 'value_start' and 'value_end' must be either both non-NULL or both NULL */
360  mhd_assert ( (NULL == value_start) || (NULL != value_end) );
361  mhd_assert ( (NULL != value_start) || (NULL == value_end) );
362  mhd_assert ( (NULL == last_escape) || (NULL != value_start) );
363  /* move remaining input from previous round into processing buffer */
364  if (0 != pp->xbuf_pos)
365  memcpy (xbuf,
366  pp->xbuf,
367  pp->xbuf_pos);
368  xoff = pp->xbuf_pos;
369  pp->xbuf_pos = 0;
370  if ( (NULL != last_escape) &&
371  (((size_t) (value_end - last_escape)) < sizeof (pp->xbuf)) )
372  {
373  pp->xbuf_pos = value_end - last_escape;
374  memcpy (pp->xbuf,
375  last_escape,
376  value_end - last_escape);
377  value_end = last_escape;
378  }
379  while ( (value_start != value_end) ||
380  (pp->must_ikvi) ||
381  (xoff > 0) )
382  {
383  size_t delta = value_end - value_start;
384  bool cut = false;
385  size_t clen = 0;
386 
387  if (delta > XBUF_SIZE - xoff)
388  delta = XBUF_SIZE - xoff;
389  /* move (additional) input into processing buffer */
390  if (0 != delta)
391  {
392  memcpy (&xbuf[xoff],
393  value_start,
394  delta);
395  xoff += delta;
396  value_start += delta;
397  }
398  /* find if escape sequence is at the end of the processing buffer;
399  if so, exclude those from processing (reduce delta to point at
400  end of processed region) */
401  if ( (xoff > 0) &&
402  ('%' == xbuf[xoff - 1]) )
403  {
404  cut = (xoff != XBUF_SIZE);
405  xoff--;
406  if (cut)
407  {
408  /* move escape sequence into buffer for next function invocation */
409  pp->xbuf[0] = '%';
410  pp->xbuf_pos = 1;
411  }
412  else
413  {
414  /* just skip escape sequence for next loop iteration */
415  delta = xoff;
416  clen = 1;
417  }
418  }
419  else if ( (xoff > 1) &&
420  ('%' == xbuf[xoff - 2]) )
421  {
422  cut = (xoff != XBUF_SIZE);
423  xoff -= 2;
424  if (cut)
425  {
426  /* move escape sequence into buffer for next function invocation */
427  memcpy (pp->xbuf,
428  &xbuf[xoff],
429  2);
430  pp->xbuf_pos = 2;
431  }
432  else
433  {
434  /* just skip escape sequence for next loop iteration */
435  delta = xoff;
436  clen = 2;
437  }
438  }
439  mhd_assert (xoff < sizeof (xbuf));
440  /* unescape */
441  xbuf[xoff] = '\0'; /* 0-terminate in preparation */
442  if (0 != xoff)
443  {
444  MHD_unescape_plus (xbuf);
445  xoff = MHD_http_unescape (xbuf);
446  }
447  /* finally: call application! */
448  if (pp->must_ikvi || (0 != xoff) )
449  {
450  pp->must_ikvi = false;
451  if (MHD_NO == pp->ikvi (pp->cls,
453  (const char *) &pp[1], /* key */
454  NULL,
455  NULL,
456  NULL,
457  xbuf,
458  pp->value_offset,
459  xoff))
460  {
461  pp->state = PP_Error;
462  return;
463  }
464  }
465  pp->value_offset += xoff;
466  if (cut)
467  break;
468  if (0 != clen)
469  {
470  xbuf[delta] = '%'; /* undo 0-termination */
471  memmove (xbuf,
472  &xbuf[delta],
473  clen);
474  }
475  xoff = clen;
476  }
477 }
478 
479 
488 static int
489 post_process_urlencoded (struct MHD_PostProcessor *pp,
490  const char *post_data,
491  size_t post_data_len)
492 {
493  char *kbuf = (char *) &pp[1];
494  size_t poff;
495  const char *start_key = NULL;
496  const char *end_key = NULL;
497  const char *start_value = NULL;
498  const char *end_value = NULL;
499  const char *last_escape = NULL;
500 
501  mhd_assert (PP_Callback != pp->state);
502 
503  poff = 0;
504  while ( ( (poff < post_data_len) ||
505  (pp->state == PP_Callback) ) &&
506  (pp->state != PP_Error) )
507  {
508  switch (pp->state)
509  {
510  case PP_Error:
511  /* clearly impossible as per while loop invariant */
512  abort ();
513  break; /* Unreachable */
514  case PP_Init:
515  /* initial phase */
516  mhd_assert (NULL == start_key);
517  mhd_assert (NULL == end_key);
518  mhd_assert (NULL == start_value);
519  mhd_assert (NULL == end_value);
520  switch (post_data[poff])
521  {
522  case '=':
523  /* Case: (no key)'=' */
524  /* Empty key with value */
525  pp->state = PP_Error;
526  continue;
527  case '&':
528  /* Case: (no key)'&' */
529  /* Empty key without value */
530  poff++;
531  continue;
532  case '\n':
533  case '\r':
534  /* Case: (no key)'\n' or (no key)'\r' */
535  pp->state = PP_Done;
536  poff++;
537  break;
538  default:
539  /* normal character, key start, advance! */
540  pp->state = PP_ProcessKey;
541  start_key = &post_data[poff];
542  pp->must_ikvi = true;
543  poff++;
544  continue;
545  }
546  break; /* end PP_Init */
547  case PP_ProcessKey:
548  /* key phase */
549  mhd_assert (NULL == start_value);
550  mhd_assert (NULL == end_value);
551  mhd_assert (NULL != start_key || 0 == poff);
552  mhd_assert (0 != poff || NULL == start_key);
553  mhd_assert (NULL == end_key);
554  switch (post_data[poff])
555  {
556  case '=':
557  /* Case: 'key=' */
558  if (0 != poff)
559  end_key = &post_data[poff];
560  poff++;
561  pp->state = PP_ProcessValue;
562  break;
563  case '&':
564  /* Case: 'key&' */
565  if (0 != poff)
566  end_key = &post_data[poff];
567  poff++;
568  pp->state = PP_Callback;
569  break;
570  case '\n':
571  case '\r':
572  /* Case: 'key\n' or 'key\r' */
573  if (0 != poff)
574  end_key = &post_data[poff];
575  /* No advance here, 'PP_Done' will be selected by next 'PP_Init' phase */
576  pp->state = PP_Callback;
577  break;
578  default:
579  /* normal character, advance! */
580  if (0 == poff)
581  start_key = post_data;
582  poff++;
583  break;
584  }
585  mhd_assert (NULL == end_key || NULL != start_key);
586  break; /* end PP_ProcessKey */
587  case PP_ProcessValue:
588  if (NULL == start_value)
589  start_value = &post_data[poff];
590  switch (post_data[poff])
591  {
592  case '=':
593  /* case 'key==' */
594  pp->state = PP_Error;
595  continue;
596  case '&':
597  /* case 'value&' */
598  end_value = &post_data[poff];
599  poff++;
600  if (pp->must_ikvi ||
601  (start_value != end_value) )
602  {
603  pp->state = PP_Callback;
604  }
605  else
606  {
607  pp->buffer_pos = 0;
608  pp->value_offset = 0;
609  pp->state = PP_Init;
610  start_value = NULL;
611  end_value = NULL;
612  }
613  continue;
614  case '\n':
615  case '\r':
616  /* Case: 'value\n' or 'value\r' */
617  end_value = &post_data[poff];
618  if (pp->must_ikvi ||
619  (start_value != end_value) )
620  pp->state = PP_Callback; /* No poff advance here to set PP_Done in the next iteration */
621  else
622  {
623  poff++;
624  pp->state = PP_Done;
625  }
626  break;
627  case '%':
628  last_escape = &post_data[poff];
629  poff++;
630  break;
631  case '0':
632  case '1':
633  case '2':
634  case '3':
635  case '4':
636  case '5':
637  case '6':
638  case '7':
639  case '8':
640  case '9':
641  /* character, may be part of escaping */
642  poff++;
643  continue;
644  default:
645  /* normal character, no more escaping! */
646  last_escape = NULL;
647  poff++;
648  continue;
649  }
650  break; /* end PP_ProcessValue */
651  case PP_Done:
652  switch (post_data[poff])
653  {
654  case '\n':
655  case '\r':
656  poff++;
657  continue;
658  }
659  /* unexpected data at the end, fail! */
660  pp->state = PP_Error;
661  break;
662  case PP_Callback:
663  mhd_assert ((NULL != end_key) || (NULL == start_key));
664  if (1)
665  {
666  const size_t key_len = end_key - start_key;
667  if (0 != key_len)
668  {
669  if ( (pp->buffer_pos + key_len >= pp->buffer_size) ||
670  (pp->buffer_pos + key_len < pp->buffer_pos) )
671  {
672  /* key too long, cannot parse! */
673  pp->state = PP_Error;
674  continue;
675  }
676  /* compute key, if we have not already */
677  memcpy (&kbuf[pp->buffer_pos],
678  start_key,
679  key_len);
680  pp->buffer_pos += key_len;
681  start_key = NULL;
682  end_key = NULL;
683  pp->must_unescape_key = true;
684  }
685  }
686 #ifdef _DEBUG
687  else
688  mhd_assert (0 != pp->buffer_pos);
689 #endif /* _DEBUG */
690  if (pp->must_unescape_key)
691  {
692  kbuf[pp->buffer_pos] = '\0'; /* 0-terminate key */
693  MHD_unescape_plus (kbuf);
694  MHD_http_unescape (kbuf);
695  pp->must_unescape_key = false;
696  }
697  process_value (pp,
698  start_value,
699  end_value,
700  NULL);
701  if (PP_Error == pp->state)
702  continue;
703  pp->value_offset = 0;
704  start_value = NULL;
705  end_value = NULL;
706  pp->buffer_pos = 0;
707  pp->state = PP_Init;
708  break;
709  default:
711  __FILE__,
712  __LINE__,
713  NULL); /* should never happen! */
714  }
715  mhd_assert ((end_key == NULL) || (start_key != NULL));
716  mhd_assert ((end_value == NULL) || (start_value != NULL));
717  }
718 
719  mhd_assert (PP_Callback != pp->state);
720 
721  if (PP_Error == pp->state)
722  {
723  /* State in error, returning failure */
724  return MHD_NO;
725  }
726 
727  /* save remaining data for next iteration */
728  if (NULL != start_key)
729  {
730  size_t key_len;
731  mhd_assert ((PP_ProcessKey == pp->state) || (NULL != end_key));
732  if (NULL == end_key)
733  end_key = &post_data[poff];
734  key_len = end_key - start_key;
735  mhd_assert (0 != key_len); /* it must be always non-zero here */
736  if (pp->buffer_pos + key_len >= pp->buffer_size)
737  {
738  pp->state = PP_Error;
739  return MHD_NO;
740  }
741  memcpy (&kbuf[pp->buffer_pos],
742  start_key,
743  key_len);
744  pp->buffer_pos += key_len;
745  pp->must_unescape_key = true;
746  start_key = NULL;
747  end_key = NULL;
748  }
749  if ( (NULL != start_value) &&
750  (PP_ProcessValue == pp->state) )
751  {
752  /* compute key, if we have not already */
753  if (pp->must_unescape_key)
754  {
755  kbuf[pp->buffer_pos] = '\0'; /* 0-terminate key */
756  MHD_unescape_plus (kbuf);
757  MHD_http_unescape (kbuf);
758  pp->must_unescape_key = false;
759  }
760  if (NULL == end_value)
761  end_value = &post_data[poff];
762  if ( (NULL != last_escape) &&
763  (2 < (end_value - last_escape)) )
764  last_escape = NULL;
765  process_value (pp,
766  start_value,
767  end_value,
768  last_escape);
769  pp->must_ikvi = false;
770  }
771  if (PP_Error == pp->state)
772  {
773  /* State in error, returning failure */
774  return MHD_NO;
775  }
776  return MHD_YES;
777 }
778 
779 
790 static int
791 try_match_header (const char *prefix,
792  size_t prefix_len,
793  char *line,
794  char **suffix)
795 {
796  if (NULL != *suffix)
797  return MHD_NO;
798  while (0 != *line)
799  {
800  if (MHD_str_equal_caseless_n_ (prefix,
801  line,
802  prefix_len))
803  {
804  *suffix = strdup (&line[prefix_len]);
805  return MHD_YES;
806  }
807  ++line;
808  }
809  return MHD_NO;
810 }
811 
812 
826 static int
827 find_boundary (struct MHD_PostProcessor *pp,
828  const char *boundary,
829  size_t blen,
830  size_t *ioffptr,
831  enum PP_State next_state,
832  enum PP_State next_dash_state)
833 {
834  char *buf = (char *) &pp[1];
835  const char *dash;
836 
837  if (pp->buffer_pos < 2 + blen)
838  {
839  if (pp->buffer_pos == pp->buffer_size)
840  pp->state = PP_Error; /* out of memory */
841  /* ++(*ioffptr); */
842  return MHD_NO; /* not enough data */
843  }
844  if ( (0 != memcmp ("--",
845  buf,
846  2)) ||
847  (0 != memcmp (&buf[2],
848  boundary,
849  blen)))
850  {
851  if (pp->state != PP_Init)
852  {
853  /* garbage not allowed */
854  pp->state = PP_Error;
855  }
856  else
857  {
858  /* skip over garbage (RFC 2046, 5.1.1) */
859  dash = memchr (buf,
860  '-',
861  pp->buffer_pos);
862  if (NULL == dash)
863  (*ioffptr) += pp->buffer_pos; /* skip entire buffer */
864  else if (dash == buf)
865  (*ioffptr)++; /* at least skip one byte */
866  else
867  (*ioffptr) += dash - buf; /* skip to first possible boundary */
868  }
869  return MHD_NO; /* expected boundary */
870  }
871  /* remove boundary from buffer */
872  (*ioffptr) += 2 + blen;
873  /* next: start with headers */
874  pp->skip_rn = RN_Dash;
875  pp->state = next_state;
876  pp->dash_state = next_dash_state;
877  return MHD_YES;
878 }
879 
880 
887 static void
888 try_get_value (const char *buf,
889  const char *key,
890  char **destination)
891 {
892  const char *spos;
893  const char *bpos;
894  const char *endv;
895  size_t klen;
896  size_t vlen;
897 
898  if (NULL != *destination)
899  return;
900  bpos = buf;
901  klen = strlen (key);
902  while (NULL != (spos = strstr (bpos, key)))
903  {
904  if ( (spos[klen] != '=') ||
905  ( (spos != buf) &&
906  (spos[-1] != ' ') ) )
907  {
908  /* no match */
909  bpos = spos + 1;
910  continue;
911  }
912  if (spos[klen + 1] != '"')
913  return; /* not quoted */
914  if (NULL == (endv = strchr (&spos[klen + 2],
915  '\"')))
916  return; /* no end-quote */
917  vlen = endv - spos - klen - 1;
918  *destination = malloc (vlen);
919  if (NULL == *destination)
920  return; /* out of memory */
921  (*destination)[vlen - 1] = '\0';
922  memcpy (*destination,
923  &spos[klen + 2],
924  vlen - 1);
925  return; /* success */
926  }
927 }
928 
929 
945 static int
946 process_multipart_headers (struct MHD_PostProcessor *pp,
947  size_t *ioffptr,
948  enum PP_State next_state)
949 {
950  char *buf = (char *) &pp[1];
951  size_t newline;
952 
953  newline = 0;
954  while ( (newline < pp->buffer_pos) &&
955  (buf[newline] != '\r') &&
956  (buf[newline] != '\n') )
957  newline++;
958  if (newline == pp->buffer_size)
959  {
960  pp->state = PP_Error;
961  return MHD_NO; /* out of memory */
962  }
963  if (newline == pp->buffer_pos)
964  return MHD_NO; /* will need more data */
965  if (0 == newline)
966  {
967  /* empty line - end of headers */
968  pp->skip_rn = RN_Full;
969  pp->state = next_state;
970  return MHD_YES;
971  }
972  /* got an actual header */
973  if (buf[newline] == '\r')
974  pp->skip_rn = RN_OptN;
975  buf[newline] = '\0';
976  if (MHD_str_equal_caseless_n_ ("Content-disposition: ",
977  buf,
978  MHD_STATICSTR_LEN_ ("Content-disposition: ")))
979  {
980  try_get_value (&buf[MHD_STATICSTR_LEN_ ("Content-disposition: ")],
981  "name",
982  &pp->content_name);
983  try_get_value (&buf[MHD_STATICSTR_LEN_ ("Content-disposition: ")],
984  "filename",
985  &pp->content_filename);
986  }
987  else
988  {
989  try_match_header ("Content-type: ",
990  MHD_STATICSTR_LEN_ ("Content-type: "),
991  buf,
992  &pp->content_type);
993  try_match_header ("Content-Transfer-Encoding: ",
994  MHD_STATICSTR_LEN_ ("Content-Transfer-Encoding: "),
995  buf,
996  &pp->content_transfer_encoding);
997  }
998  (*ioffptr) += newline + 1;
999  return MHD_YES;
1000 }
1001 
1002 
1019 static int
1020 process_value_to_boundary (struct MHD_PostProcessor *pp,
1021  size_t *ioffptr,
1022  const char *boundary,
1023  size_t blen,
1024  enum PP_State next_state,
1025  enum PP_State next_dash_state)
1026 {
1027  char *buf = (char *) &pp[1];
1028  size_t newline;
1029  const char *r;
1030 
1031  /* all data in buf until the boundary
1032  (\r\n--+boundary) is part of the value */
1033  newline = 0;
1034  while (1)
1035  {
1036  while (newline + 4 < pp->buffer_pos)
1037  {
1038  r = memchr (&buf[newline],
1039  '\r',
1040  pp->buffer_pos - newline - 4);
1041  if (NULL == r)
1042  {
1043  newline = pp->buffer_pos - 4;
1044  break;
1045  }
1046  newline = r - buf;
1047  if (0 == memcmp ("\r\n--",
1048  &buf[newline],
1049  4))
1050  break;
1051  newline++;
1052  }
1053  if (newline + blen + 4 <= pp->buffer_pos)
1054  {
1055  /* can check boundary */
1056  if (0 != memcmp (&buf[newline + 4],
1057  boundary,
1058  blen))
1059  {
1060  /* no boundary, "\r\n--" is part of content, skip */
1061  newline += 4;
1062  continue;
1063  }
1064  else
1065  {
1066  /* boundary found, process until newline then
1067  skip boundary and go back to init */
1068  pp->skip_rn = RN_Dash;
1069  pp->state = next_state;
1070  pp->dash_state = next_dash_state;
1071  (*ioffptr) += blen + 4; /* skip boundary as well */
1072  buf[newline] = '\0';
1073  break;
1074  }
1075  }
1076  else
1077  {
1078  /* cannot check for boundary, process content that
1079  we have and check again later; except, if we have
1080  no content, abort (out of memory) */
1081  if ( (0 == newline) &&
1082  (pp->buffer_pos == pp->buffer_size) )
1083  {
1084  pp->state = PP_Error;
1085  return MHD_NO;
1086  }
1087  break;
1088  }
1089  }
1090  /* newline is either at beginning of boundary or
1091  at least at the last character that we are sure
1092  is not part of the boundary */
1093  if ( ( (pp->must_ikvi) ||
1094  (0 != newline) ) &&
1095  (MHD_NO == pp->ikvi (pp->cls,
1097  pp->content_name,
1098  pp->content_filename,
1099  pp->content_type,
1100  pp->content_transfer_encoding,
1101  buf,
1102  pp->value_offset,
1103  newline)) )
1104  {
1105  pp->state = PP_Error;
1106  return MHD_NO;
1107  }
1108  pp->must_ikvi = false;
1109  pp->value_offset += newline;
1110  (*ioffptr) += newline;
1111  return MHD_YES;
1112 }
1113 
1114 
1119 static void
1120 free_unmarked (struct MHD_PostProcessor *pp)
1121 {
1122  if ( (NULL != pp->content_name) &&
1123  (0 == (pp->have & NE_content_name)) )
1124  {
1125  free (pp->content_name);
1126  pp->content_name = NULL;
1127  }
1128  if ( (NULL != pp->content_type) &&
1129  (0 == (pp->have & NE_content_type)) )
1130  {
1131  free (pp->content_type);
1132  pp->content_type = NULL;
1133  }
1134  if ( (NULL != pp->content_filename) &&
1135  (0 == (pp->have & NE_content_filename)) )
1136  {
1137  free (pp->content_filename);
1138  pp->content_filename = NULL;
1139  }
1140  if ( (NULL != pp->content_transfer_encoding) &&
1141  (0 == (pp->have & NE_content_transfer_encoding)) )
1142  {
1143  free (pp->content_transfer_encoding);
1144  pp->content_transfer_encoding = NULL;
1145  }
1146 }
1147 
1148 
1157 static int
1158 post_process_multipart (struct MHD_PostProcessor *pp,
1159  const char *post_data,
1160  size_t post_data_len)
1161 {
1162  char *buf;
1163  size_t max;
1164  size_t ioff;
1165  size_t poff;
1166  int state_changed;
1167 
1168  buf = (char *) &pp[1];
1169  ioff = 0;
1170  poff = 0;
1171  state_changed = 1;
1172  while ( (poff < post_data_len) ||
1173  ( (pp->buffer_pos > 0) &&
1174  (0 != state_changed) ) )
1175  {
1176  /* first, move as much input data
1177  as possible to our internal buffer */
1178  max = pp->buffer_size - pp->buffer_pos;
1179  if (max > post_data_len - poff)
1180  max = post_data_len - poff;
1181  memcpy (&buf[pp->buffer_pos],
1182  &post_data[poff],
1183  max);
1184  poff += max;
1185  pp->buffer_pos += max;
1186  if ( (0 == max) &&
1187  (0 == state_changed) &&
1188  (poff < post_data_len) )
1189  {
1190  pp->state = PP_Error;
1191  return MHD_NO; /* out of memory */
1192  }
1193  state_changed = 0;
1194 
1195  /* first state machine for '\r'-'\n' and '--' handling */
1196  switch (pp->skip_rn)
1197  {
1198  case RN_Inactive:
1199  break;
1200  case RN_OptN:
1201  if (buf[0] == '\n')
1202  {
1203  ioff++;
1204  pp->skip_rn = RN_Inactive;
1205  goto AGAIN;
1206  }
1207  /* fall-through! */
1208  case RN_Dash:
1209  if (buf[0] == '-')
1210  {
1211  ioff++;
1212  pp->skip_rn = RN_Dash2;
1213  goto AGAIN;
1214  }
1215  pp->skip_rn = RN_Full;
1216  /* fall-through! */
1217  case RN_Full:
1218  if (buf[0] == '\r')
1219  {
1220  if ( (pp->buffer_pos > 1) &&
1221  ('\n' == buf[1]) )
1222  {
1223  pp->skip_rn = RN_Inactive;
1224  ioff += 2;
1225  }
1226  else
1227  {
1228  pp->skip_rn = RN_OptN;
1229  ioff++;
1230  }
1231  goto AGAIN;
1232  }
1233  if (buf[0] == '\n')
1234  {
1235  ioff++;
1236  pp->skip_rn = RN_Inactive;
1237  goto AGAIN;
1238  }
1239  pp->skip_rn = RN_Inactive;
1240  pp->state = PP_Error;
1241  return MHD_NO; /* no '\r\n' */
1242  case RN_Dash2:
1243  if (buf[0] == '-')
1244  {
1245  ioff++;
1246  pp->skip_rn = RN_Full;
1247  pp->state = pp->dash_state;
1248  goto AGAIN;
1249  }
1250  pp->state = PP_Error;
1251  break;
1252  }
1253 
1254  /* main state engine */
1255  switch (pp->state)
1256  {
1257  case PP_Error:
1258  return MHD_NO;
1259  case PP_Done:
1260  /* did not expect to receive more data */
1261  pp->state = PP_Error;
1262  return MHD_NO;
1263  case PP_Init:
1275  (void) find_boundary (pp,
1276  pp->boundary,
1277  pp->blen,
1278  &ioff,
1280  PP_Done);
1281  break;
1282  case PP_NextBoundary:
1283  if (MHD_NO == find_boundary (pp,
1284  pp->boundary,
1285  pp->blen,
1286  &ioff,
1288  PP_Done))
1289  {
1290  if (pp->state == PP_Error)
1291  return MHD_NO;
1292  goto END;
1293  }
1294  break;
1296  pp->must_ikvi = true;
1297  if (MHD_NO ==
1299  &ioff,
1301  {
1302  if (pp->state == PP_Error)
1303  return MHD_NO;
1304  else
1305  goto END;
1306  }
1307  state_changed = 1;
1308  break;
1310  if ( (NULL != pp->content_type) &&
1311  (MHD_str_equal_caseless_n_ (pp->content_type,
1312  "multipart/mixed",
1313  MHD_STATICSTR_LEN_ ("multipart/mixed"))))
1314  {
1315  pp->nested_boundary = strstr (pp->content_type,
1316  "boundary=");
1317  if (NULL == pp->nested_boundary)
1318  {
1319  pp->state = PP_Error;
1320  return MHD_NO;
1321  }
1322  pp->nested_boundary =
1323  strdup (&pp->nested_boundary[MHD_STATICSTR_LEN_ ("boundary=")]);
1324  if (NULL == pp->nested_boundary)
1325  {
1326  /* out of memory */
1327  pp->state = PP_Error;
1328  return MHD_NO;
1329  }
1330  /* free old content type, we will need that field
1331  for the content type of the nested elements */
1332  free (pp->content_type);
1333  pp->content_type = NULL;
1334  pp->nlen = strlen (pp->nested_boundary);
1335  pp->state = PP_Nested_Init;
1336  state_changed = 1;
1337  break;
1338  }
1339  pp->state = PP_ProcessValueToBoundary;
1340  pp->value_offset = 0;
1341  state_changed = 1;
1342  break;
1344  if (MHD_NO == process_value_to_boundary (pp,
1345  &ioff,
1346  pp->boundary,
1347  pp->blen,
1349  PP_Done))
1350  {
1351  if (pp->state == PP_Error)
1352  return MHD_NO;
1353  break;
1354  }
1355  break;
1356  case PP_PerformCleanup:
1357  /* clean up state of one multipart form-data element! */
1358  pp->have = NE_none;
1359  free_unmarked (pp);
1360  if (NULL != pp->nested_boundary)
1361  {
1362  free (pp->nested_boundary);
1363  pp->nested_boundary = NULL;
1364  }
1365  pp->state = PP_ProcessEntryHeaders;
1366  state_changed = 1;
1367  break;
1368  case PP_Nested_Init:
1369  if (NULL == pp->nested_boundary)
1370  {
1371  pp->state = PP_Error;
1372  return MHD_NO;
1373  }
1374  if (MHD_NO == find_boundary (pp,
1375  pp->nested_boundary,
1376  pp->nlen,
1377  &ioff,
1379  PP_NextBoundary /* or PP_Error? */))
1380  {
1381  if (pp->state == PP_Error)
1382  return MHD_NO;
1383  goto END;
1384  }
1385  break;
1387  /* remember what headers were given
1388  globally */
1389  pp->have = NE_none;
1390  if (NULL != pp->content_name)
1391  pp->have |= NE_content_name;
1392  if (NULL != pp->content_type)
1393  pp->have |= NE_content_type;
1394  if (NULL != pp->content_filename)
1395  pp->have |= NE_content_filename;
1396  if (NULL != pp->content_transfer_encoding)
1397  pp->have |= NE_content_transfer_encoding;
1398  pp->state = PP_Nested_ProcessEntryHeaders;
1399  state_changed = 1;
1400  break;
1402  pp->value_offset = 0;
1403  if (MHD_NO ==
1405  &ioff,
1407  {
1408  if (pp->state == PP_Error)
1409  return MHD_NO;
1410  else
1411  goto END;
1412  }
1413  state_changed = 1;
1414  break;
1416  if (MHD_NO == process_value_to_boundary (pp,
1417  &ioff,
1418  pp->nested_boundary,
1419  pp->nlen,
1421  PP_NextBoundary))
1422  {
1423  if (pp->state == PP_Error)
1424  return MHD_NO;
1425  break;
1426  }
1427  break;
1429  free_unmarked (pp);
1430  pp->state = PP_Nested_ProcessEntryHeaders;
1431  state_changed = 1;
1432  break;
1433  default:
1435  __FILE__,
1436  __LINE__,
1437  NULL); /* should never happen! */
1438  }
1439 AGAIN:
1440  if (ioff > 0)
1441  {
1442  memmove (buf,
1443  &buf[ioff],
1444  pp->buffer_pos - ioff);
1445  pp->buffer_pos -= ioff;
1446  ioff = 0;
1447  state_changed = 1;
1448  }
1449  }
1450 END:
1451  if (0 != ioff)
1452  {
1453  memmove (buf,
1454  &buf[ioff],
1455  pp->buffer_pos - ioff);
1456  pp->buffer_pos -= ioff;
1457  }
1458  if (poff < post_data_len)
1459  {
1460  pp->state = PP_Error;
1461  return MHD_NO; /* serious error */
1462  }
1463  return MHD_YES;
1464 }
1465 
1466 
1467 enum MHD_Result
1468 MHD_post_process (struct MHD_PostProcessor *pp,
1469  const char *post_data,
1470  size_t post_data_len)
1471 {
1472  if (0 == post_data_len)
1473  return MHD_YES;
1474  if (NULL == pp)
1475  return MHD_NO;
1477  pp->encoding,
1480  return post_process_urlencoded (pp,
1481  post_data,
1482  post_data_len);
1484  pp->encoding,
1487  return post_process_multipart (pp,
1488  post_data,
1489  post_data_len);
1490  /* this should never be reached */
1491  return MHD_NO;
1492 }
1493 
1494 
1495 enum MHD_Result
1496 MHD_destroy_post_processor (struct MHD_PostProcessor *pp)
1497 {
1498  enum MHD_Result ret;
1499 
1500  if (NULL == pp)
1501  return MHD_YES;
1502  if (PP_ProcessValue == pp->state)
1503  {
1504  /* key without terminated value left at the end of the
1505  buffer; fake receiving a termination character to
1506  ensure it is also processed */
1508  "\n",
1509  1);
1510  }
1511  /* These internal strings need cleaning up since
1512  the post-processing may have been interrupted
1513  at any stage */
1514  if ( (pp->xbuf_pos > 0) ||
1515  ( (pp->state != PP_Done) &&
1516  (pp->state != PP_Init) ) )
1517  ret = MHD_NO;
1518  else
1519  ret = MHD_YES;
1520  pp->have = NE_none;
1521  free_unmarked (pp);
1522  if (NULL != pp->nested_boundary)
1523  free (pp->nested_boundary);
1524  free (pp);
1525  return ret;
1526 }
1527 
1528 
1529 /* end of postprocessor.c */
#define MHD_HTTP_HEADER_CONTENT_TYPE
Definition: microhttpd.h:618
#define MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA
Definition: microhttpd.h:1177
#define MHD_HTTP_POST_ENCODING_FORM_URLENCODED
Definition: microhttpd.h:1175
enum MHD_Result MHD_destroy_post_processor(struct MHD_PostProcessor *pp)
enum MHD_Result MHD_post_process(struct MHD_PostProcessor *pp, const char *post_data, size_t post_data_len)
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_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:649
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
MHD internal shared structures.
macros for mhd_assert()
Header for platform missing functions.
Header for string manipulating helpers.
MHD_Result
Definition: microhttpd.h:158
@ MHD_YES
Definition: microhttpd.h:167
@ MHD_NO
Definition: microhttpd.h:162
_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:2636
@ MHD_POSTDATA_KIND
Definition: microhttpd.h:2009
@ MHD_HEADER_KIND
Definition: microhttpd.h:1993
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:72
@ RN_Dash
Definition: postprocessor.c:94
@ RN_Inactive
Definition: postprocessor.c:76
@ RN_Full
Definition: postprocessor.c:88
@ RN_OptN
Definition: postprocessor.c:82
@ RN_Dash2
Definition: postprocessor.c:99
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:37
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:43
@ PP_PerformCleanup
Definition: postprocessor.c:59
@ PP_Error
Definition: postprocessor.c:45
@ PP_Nested_PerformMarking
Definition: postprocessor.c:63
@ PP_ProcessKey
Definition: postprocessor.c:51
@ PP_Init
Definition: postprocessor.c:47
@ PP_PerformCheckMultipart
Definition: postprocessor.c:57
@ PP_Nested_Init
Definition: postprocessor.c:62
@ PP_ProcessValue
Definition: postprocessor.c:52
@ PP_Nested_ProcessEntryHeaders
Definition: postprocessor.c:64
@ PP_Nested_PerformCleanup
Definition: postprocessor.c:66
@ PP_NextBoundary
Definition: postprocessor.c:48
@ PP_ProcessEntryHeaders
Definition: postprocessor.c:56
@ PP_ProcessValueToBoundary
Definition: postprocessor.c:58
@ PP_Done
Definition: postprocessor.c:46
@ PP_Callback
Definition: postprocessor.c:53
@ PP_Nested_ProcessValueToBoundary
Definition: postprocessor.c:65
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:1263