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