• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
20 /**
21  * @file postprocessor.c
22  * @brief  Methods for parsing POST data
23  * @author Christian Grothoff
24  */
25 
26 #include "internal.h"
27 
28 /**
29  * Size of on-stack buffer that we use for un-escaping of the value.
30  * We use a pretty small value to be nice to the stack on embedded
31  * systems.
32  */
33 #define XBUF_SIZE 512
34 
35 /**
36  * States in the PP parser's state machine.
37  */
38 enum PP_State
39 {
40   /* general states */
41   PP_Error,
42   PP_Done,
43   PP_Init,
44   PP_NextBoundary,
45 
46   /* url encoding-states */
47   PP_ProcessValue,
48   PP_ExpectNewLine,
49 
50   /* post encoding-states  */
51   PP_ProcessEntryHeaders,
52   PP_PerformCheckMultipart,
53   PP_ProcessValueToBoundary,
54   PP_PerformCleanup,
55 
56   /* nested post-encoding states */
57   PP_Nested_Init,
58   PP_Nested_PerformMarking,
59   PP_Nested_ProcessEntryHeaders,
60   PP_Nested_ProcessValueToBoundary,
61   PP_Nested_PerformCleanup
62 
63 };
64 
65 
66 enum RN_State
67 {
68   /**
69    * No RN-preprocessing in this state.
70    */
71   RN_Inactive = 0,
72 
73   /**
74    * If the next character is CR, skip it.  Otherwise,
75    * just go inactive.
76    */
77   RN_OptN = 1,
78 
79   /**
80    * Expect LFCR (and only LFCR).  As always, we also
81    * expect only LF or only CR.
82    */
83   RN_Full = 2,
84 
85   /**
86    * Expect either LFCR or '--'LFCR.  If '--'LFCR, transition into dash-state
87    * for the main state machine
88    */
89   RN_Dash = 3,
90 
91   /**
92    * Got a single dash, expect second dash.
93    */
94   RN_Dash2 = 4
95 };
96 
97 
98 /**
99  * Bits for the globally known fields that
100  * should not be deleted when we exit the
101  * nested state.
102  */
103 enum NE_State
104 {
105   NE_none = 0,
106   NE_content_name = 1,
107   NE_content_type = 2,
108   NE_content_filename = 4,
109   NE_content_transfer_encoding = 8
110 };
111 
112 
113 /**
114  * Internal state of the post-processor.  Note that the fields
115  * are sorted by type to enable optimal packing by the compiler.
116  */
117 struct MHD_PostProcessor
118 {
119 
120   /**
121    * The connection for which we are doing
122    * POST processing.
123    */
124   struct MHD_Connection *connection;
125 
126   /**
127    * Function to call with POST data.
128    */
129   MHD_PostDataIterator ikvi;
130 
131   /**
132    * Extra argument to ikvi.
133    */
134   void *cls;
135 
136   /**
137    * Encoding as given by the headers of the
138    * connection.
139    */
140   const char *encoding;
141 
142   /**
143    * Primary boundary (points into encoding string)
144    */
145   const char *boundary;
146 
147   /**
148    * Nested boundary (if we have multipart/mixed encoding).
149    */
150   char *nested_boundary;
151 
152   /**
153    * Pointer to the name given in disposition.
154    */
155   char *content_name;
156 
157   /**
158    * Pointer to the (current) content type.
159    */
160   char *content_type;
161 
162   /**
163    * Pointer to the (current) filename.
164    */
165   char *content_filename;
166 
167   /**
168    * Pointer to the (current) encoding.
169    */
170   char *content_transfer_encoding;
171 
172   /**
173    * Unprocessed value bytes due to escape
174    * sequences (URL-encoding only).
175    */
176   char xbuf[8];
177 
178   /**
179    * Size of our buffer for the key.
180    */
181   size_t buffer_size;
182 
183   /**
184    * Current position in the key buffer.
185    */
186   size_t buffer_pos;
187 
188   /**
189    * Current position in xbuf.
190    */
191   size_t xbuf_pos;
192 
193   /**
194    * Current offset in the value being processed.
195    */
196   uint64_t value_offset;
197 
198   /**
199    * strlen(boundary) -- if boundary != NULL.
200    */
201   size_t blen;
202 
203   /**
204    * strlen(nested_boundary) -- if nested_boundary != NULL.
205    */
206   size_t nlen;
207 
208   /**
209    * Do we have to call the 'ikvi' callback when processing the
210    * multipart post body even if the size of the payload is zero?
211    * Set to #MHD_YES whenever we parse a new multiparty entry header,
212    * and to #MHD_NO the first time we call the 'ikvi' callback.
213    * Used to ensure that we do always call 'ikvi' even if the
214    * payload is empty (but not more than once).
215    */
216   int must_ikvi;
217 
218   /**
219    * State of the parser.
220    */
221   enum PP_State state;
222 
223   /**
224    * Side-state-machine: skip LRCR (or just LF).
225    * Set to 0 if we are not in skip mode.  Set to 2
226    * if a LFCR is expected, set to 1 if a CR should
227    * be skipped if it is the next character.
228    */
229   enum RN_State skip_rn;
230 
231   /**
232    * If we are in skip_rn with "dash" mode and
233    * do find 2 dashes, what state do we go into?
234    */
235   enum PP_State dash_state;
236 
237   /**
238    * Which headers are global? (used to tell which
239    * headers were only valid for the nested multipart).
240    */
241   enum NE_State have;
242 
243 };
244 
245 
246 /**
247  * Create a `struct MHD_PostProcessor`.
248  *
249  * A `struct MHD_PostProcessor` can be used to (incrementally) parse
250  * the data portion of a POST request.  Note that some buggy browsers
251  * fail to set the encoding type.  If you want to support those, you
252  * may have to call #MHD_set_connection_value with the proper encoding
253  * type before creating a post processor (if no supported encoding
254  * type is set, this function will fail).
255  *
256  * @param connection the connection on which the POST is
257  *        happening (used to determine the POST format)
258  * @param buffer_size maximum number of bytes to use for
259  *        internal buffering (used only for the parsing,
260  *        specifically the parsing of the keys).  A
261  *        tiny value (256-1024) should be sufficient.
262  *        Do NOT use a value smaller than 256.  For good
263  *        performance, use 32 or 64k (i.e. 65536).
264  * @param iter iterator to be called with the parsed data,
265  *        Must NOT be NULL.
266  * @param iter_cls first argument to @a iter
267  * @return NULL on error (out of memory, unsupported encoding),
268  *         otherwise a PP handle
269  * @ingroup request
270  */
271 struct MHD_PostProcessor *
MHD_create_post_processor(struct MHD_Connection * connection,size_t buffer_size,MHD_PostDataIterator iter,void * iter_cls)272 MHD_create_post_processor (struct MHD_Connection *connection,
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,
284                                           MHD_HEADER_KIND,
285                                           MHD_HTTP_HEADER_CONTENT_TYPE);
286   if (encoding == NULL)
287     return NULL;
288   boundary = NULL;
289   if (!MHD_str_equal_caseless_n_ (MHD_HTTP_POST_ENCODING_FORM_URLENCODED, encoding,
290                         strlen (MHD_HTTP_POST_ENCODING_FORM_URLENCODED)))
291     {
292       if (!MHD_str_equal_caseless_n_ (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, encoding,
293                        strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)))
294         return NULL;
295       boundary =
296         &encoding[strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)];
297       /* Q: should this be "strcasestr"? */
298       boundary = strstr (boundary, "boundary=");
299       if (NULL == boundary)
300 	return NULL; /* failed to determine boundary */
301       boundary += strlen ("boundary=");
302       blen = strlen (boundary);
303       if ((blen == 0) || (blen * 2 + 2 > buffer_size))
304         return NULL;            /* (will be) out of memory or invalid boundary */
305       if ( (boundary[0] == '"') && (boundary[blen - 1] == '"') )
306 	{
307 	  /* remove enclosing quotes */
308 	  ++boundary;
309 	  blen -= 2;
310 	}
311     }
312   else
313     blen = 0;
314   buffer_size += 4; /* round up to get nice block sizes despite boundary search */
315 
316   /* add +1 to ensure we ALWAYS have a zero-termination at the end */
317   if (NULL == (ret = malloc (sizeof (struct MHD_PostProcessor) + buffer_size + 1)))
318     return NULL;
319   memset (ret, 0, sizeof (struct MHD_PostProcessor) + buffer_size + 1);
320   ret->connection = connection;
321   ret->ikvi = iter;
322   ret->cls = iter_cls;
323   ret->encoding = encoding;
324   ret->buffer_size = buffer_size;
325   ret->state = PP_Init;
326   ret->blen = blen;
327   ret->boundary = boundary;
328   ret->skip_rn = RN_Inactive;
329   return ret;
330 }
331 
332 
333 /**
334  * Process url-encoded POST data.
335  *
336  * @param pp post processor context
337  * @param post_data upload data
338  * @param post_data_len number of bytes in @a post_data
339  * @return #MHD_YES on success, #MHD_NO if there was an error processing the data
340  */
341 static int
post_process_urlencoded(struct MHD_PostProcessor * pp,const char * post_data,size_t post_data_len)342 post_process_urlencoded (struct MHD_PostProcessor *pp,
343                          const char *post_data,
344 			 size_t post_data_len)
345 {
346   size_t equals;
347   size_t amper;
348   size_t poff;
349   size_t xoff;
350   size_t delta;
351   int end_of_value_found;
352   char *buf;
353   char xbuf[XBUF_SIZE + 1];
354 
355   buf = (char *) &pp[1];
356   poff = 0;
357   while (poff < post_data_len)
358     {
359       switch (pp->state)
360         {
361         case PP_Error:
362           return MHD_NO;
363         case PP_Done:
364           /* did not expect to receive more data */
365           pp->state = PP_Error;
366           return MHD_NO;
367         case PP_Init:
368           equals = 0;
369           while ((equals + poff < post_data_len) &&
370                  (post_data[equals + poff] != '='))
371             equals++;
372           if (equals + pp->buffer_pos > pp->buffer_size)
373             {
374               pp->state = PP_Error;     /* out of memory */
375               return MHD_NO;
376             }
377           memcpy (&buf[pp->buffer_pos], &post_data[poff], equals);
378           pp->buffer_pos += equals;
379           if (equals + poff == post_data_len)
380             return MHD_YES;     /* no '=' yet */
381           buf[pp->buffer_pos] = '\0';   /* 0-terminate key */
382           pp->buffer_pos = 0;   /* reset for next key */
383 	  MHD_unescape_plus (buf);
384           MHD_http_unescape (buf);
385           poff += equals + 1;
386           pp->state = PP_ProcessValue;
387           pp->value_offset = 0;
388           break;
389         case PP_ProcessValue:
390           /* obtain rest of value from previous iteration */
391           memcpy (xbuf, pp->xbuf, pp->xbuf_pos);
392           xoff = pp->xbuf_pos;
393           pp->xbuf_pos = 0;
394 
395           /* find last position in input buffer that is part of the value */
396           amper = 0;
397           while ((amper + poff < post_data_len) &&
398                  (amper < XBUF_SIZE) &&
399                  (post_data[amper + poff] != '&') &&
400                  (post_data[amper + poff] != '\n') &&
401                  (post_data[amper + poff] != '\r'))
402             amper++;
403           end_of_value_found = ((amper + poff < post_data_len) &&
404                                 ((post_data[amper + poff] == '&') ||
405                                  (post_data[amper + poff] == '\n') ||
406                                  (post_data[amper + poff] == '\r')));
407           /* compute delta, the maximum number of bytes that we will be able to
408              process right now (either amper-limited of xbuf-size limited) */
409           delta = amper;
410           if (delta > XBUF_SIZE - xoff)
411             delta = XBUF_SIZE - xoff;
412 
413           /* move input into processing buffer */
414           memcpy (&xbuf[xoff], &post_data[poff], delta);
415           xoff += delta;
416           poff += delta;
417 
418           /* find if escape sequence is at the end of the processing buffer;
419              if so, exclude those from processing (reduce delta to point at
420              end of processed region) */
421           delta = xoff;
422           if ((delta > 0) && (xbuf[delta - 1] == '%'))
423             delta--;
424           else if ((delta > 1) && (xbuf[delta - 2] == '%'))
425             delta -= 2;
426 
427           /* if we have an incomplete escape sequence, save it to
428              pp->xbuf for later */
429           if (delta < xoff)
430             {
431               memcpy (pp->xbuf, &xbuf[delta], xoff - delta);
432               pp->xbuf_pos = xoff - delta;
433               xoff = delta;
434             }
435 
436           /* If we have nothing to do (delta == 0) and
437              not just because the value is empty (are
438              waiting for more data), go for next iteration */
439           if ((xoff == 0) && (poff == post_data_len))
440             continue;
441 
442           /* unescape */
443           xbuf[xoff] = '\0';    /* 0-terminate in preparation */
444 	  MHD_unescape_plus (xbuf);
445           xoff = MHD_http_unescape (xbuf);
446           /* finally: call application! */
447 	  pp->must_ikvi = MHD_NO;
448           if (MHD_NO == pp->ikvi (pp->cls, MHD_POSTDATA_KIND, (const char *) &pp[1],    /* key */
449                                   NULL, NULL, NULL, xbuf, pp->value_offset,
450                                   xoff))
451             {
452               pp->state = PP_Error;
453               return MHD_NO;
454             }
455           pp->value_offset += xoff;
456 
457           /* are we done with the value? */
458           if (end_of_value_found)
459             {
460               /* we found the end of the value! */
461               if ((post_data[poff] == '\n') || (post_data[poff] == '\r'))
462                 {
463                   pp->state = PP_ExpectNewLine;
464                 }
465               else if (post_data[poff] == '&')
466                 {
467                   poff++;       /* skip '&' */
468                   pp->state = PP_Init;
469                 }
470             }
471           break;
472         case PP_ExpectNewLine:
473           if ((post_data[poff] == '\n') || (post_data[poff] == '\r'))
474             {
475               poff++;
476               /* we are done, report error if we receive any more... */
477               pp->state = PP_Done;
478               return MHD_YES;
479             }
480           return MHD_NO;
481         default:
482           mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL);          /* should never happen! */
483         }
484     }
485   return MHD_YES;
486 }
487 
488 
489 /**
490  * If the given line matches the prefix, strdup the
491  * rest of the line into the suffix ptr.
492  *
493  * @param prefix prefix to match
494  * @param line line to match prefix in
495  * @param suffix set to a copy of the rest of the line, starting at the end of the match
496  * @return #MHD_YES if there was a match, #MHD_NO if not
497  */
498 static int
try_match_header(const char * prefix,char * line,char ** suffix)499 try_match_header (const char *prefix, char *line, char **suffix)
500 {
501   if (NULL != *suffix)
502     return MHD_NO;
503   while (*line != 0)
504     {
505       if (MHD_str_equal_caseless_n_ (prefix, line, strlen (prefix)))
506         {
507           *suffix = strdup (&line[strlen (prefix)]);
508           return MHD_YES;
509         }
510       ++line;
511     }
512   return MHD_NO;
513 }
514 
515 
516 /**
517  *
518  * @param pp post processor context
519  * @param boundary boundary to look for
520  * @param blen number of bytes in boundary
521  * @param ioffptr set to the end of the boundary if found,
522  *                otherwise incremented by one (FIXME: quirky API!)
523  * @param next_state state to which we should advance the post processor
524  *                   if the boundary is found
525  * @param next_dash_state dash_state to which we should advance the
526  *                   post processor if the boundary is found
527  * @return #MHD_NO if the boundary is not found, #MHD_YES if we did find it
528  */
529 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)530 find_boundary (struct MHD_PostProcessor *pp,
531                const char *boundary,
532                size_t blen,
533                size_t *ioffptr,
534                enum PP_State next_state, enum PP_State next_dash_state)
535 {
536   char *buf = (char *) &pp[1];
537   const char *dash;
538 
539   if (pp->buffer_pos < 2 + blen)
540     {
541       if (pp->buffer_pos == pp->buffer_size)
542         pp->state = PP_Error;   /* out of memory */
543       // ++(*ioffptr);
544       return MHD_NO;            /* not enough data */
545     }
546   if ((0 != memcmp ("--", buf, 2)) || (0 != memcmp (&buf[2], boundary, blen)))
547     {
548       if (pp->state != PP_Init)
549         {
550           /* garbage not allowed */
551           pp->state = PP_Error;
552         }
553       else
554         {
555           /* skip over garbage (RFC 2046, 5.1.1) */
556           dash = memchr (buf, '-', pp->buffer_pos);
557           if (NULL == dash)
558             (*ioffptr) += pp->buffer_pos; /* skip entire buffer */
559           else
560             if (dash == buf)
561               (*ioffptr)++; /* at least skip one byte */
562             else
563               (*ioffptr) += dash - buf; /* skip to first possible boundary */
564         }
565       return MHD_NO;            /* expected boundary */
566     }
567   /* remove boundary from buffer */
568   (*ioffptr) += 2 + blen;
569   /* next: start with headers */
570   pp->skip_rn = RN_Dash;
571   pp->state = next_state;
572   pp->dash_state = next_dash_state;
573   return MHD_YES;
574 }
575 
576 
577 /**
578  * In buf, there maybe an expression '$key="$value"'.  If that is the
579  * case, copy a copy of $value to destination.
580  *
581  * If destination is already non-NULL, do nothing.
582  */
583 static void
try_get_value(const char * buf,const char * key,char ** destination)584 try_get_value (const char *buf,
585 	       const char *key,
586 	       char **destination)
587 {
588   const char *spos;
589   const char *bpos;
590   const char *endv;
591   size_t klen;
592   size_t vlen;
593 
594   if (NULL != *destination)
595     return;
596   bpos = buf;
597   klen = strlen (key);
598   while (NULL != (spos = strstr (bpos, key)))
599     {
600       if ((spos[klen] != '=') || ((spos != buf) && (spos[-1] != ' ')))
601         {
602           /* no match */
603           bpos = spos + 1;
604           continue;
605         }
606       if (spos[klen + 1] != '"')
607         return;                 /* not quoted */
608       if (NULL == (endv = strchr (&spos[klen + 2], '\"')))
609         return;                 /* no end-quote */
610       vlen = endv - spos - klen - 1;
611       *destination = malloc (vlen);
612       if (NULL == *destination)
613         return;                 /* out of memory */
614       (*destination)[vlen - 1] = '\0';
615       memcpy (*destination, &spos[klen + 2], vlen - 1);
616       return;                   /* success */
617     }
618 }
619 
620 
621 /**
622  * Go over the headers of the part and update
623  * the fields in "pp" according to what we find.
624  * If we are at the end of the headers (as indicated
625  * by an empty line), transition into next_state.
626  *
627  * @param pp post processor context
628  * @param ioffptr set to how many bytes have been
629  *                processed
630  * @param next_state state to which the post processor should
631  *                be advanced if we find the end of the headers
632  * @return #MHD_YES if we can continue processing,
633  *         #MHD_NO on error or if we do not have
634  *                enough data yet
635  */
636 static int
process_multipart_headers(struct MHD_PostProcessor * pp,size_t * ioffptr,enum PP_State next_state)637 process_multipart_headers (struct MHD_PostProcessor *pp,
638                            size_t *ioffptr, enum PP_State next_state)
639 {
640   char *buf = (char *) &pp[1];
641   size_t newline;
642 
643   newline = 0;
644   while ((newline < pp->buffer_pos) &&
645          (buf[newline] != '\r') && (buf[newline] != '\n'))
646     newline++;
647   if (newline == pp->buffer_size)
648     {
649       pp->state = PP_Error;
650       return MHD_NO;            /* out of memory */
651     }
652   if (newline == pp->buffer_pos)
653     return MHD_NO;              /* will need more data */
654   if (0 == newline)
655     {
656       /* empty line - end of headers */
657       pp->skip_rn = RN_Full;
658       pp->state = next_state;
659       return MHD_YES;
660     }
661   /* got an actual header */
662   if (buf[newline] == '\r')
663     pp->skip_rn = RN_OptN;
664   buf[newline] = '\0';
665   if (MHD_str_equal_caseless_n_ ("Content-disposition: ",
666                         buf, strlen ("Content-disposition: ")))
667     {
668       try_get_value (&buf[strlen ("Content-disposition: ")],
669                      "name", &pp->content_name);
670       try_get_value (&buf[strlen ("Content-disposition: ")],
671                      "filename", &pp->content_filename);
672     }
673   else
674     {
675       try_match_header ("Content-type: ", buf, &pp->content_type);
676       try_match_header ("Content-Transfer-Encoding: ",
677                         buf, &pp->content_transfer_encoding);
678     }
679   (*ioffptr) += newline + 1;
680   return MHD_YES;
681 }
682 
683 
684 /**
685  * We have the value until we hit the given boundary;
686  * process accordingly.
687  *
688  * @param pp post processor context
689  * @param ioffptr incremented based on the number of bytes processed
690  * @param boundary the boundary to look for
691  * @param blen strlen(boundary)
692  * @param next_state what state to go into after the
693  *        boundary was found
694  * @param next_dash_state state to go into if the next
695  *        boundary ends with "--"
696  * @return #MHD_YES if we can continue processing,
697  *         #MHD_NO on error or if we do not have
698  *                enough data yet
699  */
700 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)701 process_value_to_boundary (struct MHD_PostProcessor *pp,
702                            size_t *ioffptr,
703                            const char *boundary,
704                            size_t blen,
705                            enum PP_State next_state,
706                            enum PP_State next_dash_state)
707 {
708   char *buf = (char *) &pp[1];
709   size_t newline;
710   const char *r;
711 
712   /* all data in buf until the boundary
713      (\r\n--+boundary) is part of the value */
714   newline = 0;
715   while (1)
716     {
717       while (newline + 4 < pp->buffer_pos)
718         {
719           r = memchr (&buf[newline], '\r', pp->buffer_pos - newline - 4);
720           if (NULL == r)
721           {
722             newline = pp->buffer_pos - 4;
723             break;
724           }
725           newline = r - buf;
726           if (0 == memcmp ("\r\n--", &buf[newline], 4))
727             break;
728           newline++;
729         }
730       if (newline + pp->blen + 4 <= pp->buffer_pos)
731         {
732           /* can check boundary */
733           if (0 != memcmp (&buf[newline + 4], boundary, pp->blen))
734             {
735               /* no boundary, "\r\n--" is part of content, skip */
736               newline += 4;
737               continue;
738             }
739           else
740             {
741               /* boundary found, process until newline then
742                  skip boundary and go back to init */
743               pp->skip_rn = RN_Dash;
744               pp->state = next_state;
745               pp->dash_state = next_dash_state;
746               (*ioffptr) += pp->blen + 4;       /* skip boundary as well */
747               buf[newline] = '\0';
748               break;
749             }
750         }
751       else
752         {
753           /* cannot check for boundary, process content that
754              we have and check again later; except, if we have
755              no content, abort (out of memory) */
756           if ((0 == newline) && (pp->buffer_pos == pp->buffer_size))
757             {
758               pp->state = PP_Error;
759               return MHD_NO;
760             }
761           break;
762         }
763     }
764   /* newline is either at beginning of boundary or
765      at least at the last character that we are sure
766      is not part of the boundary */
767   if ( ( (MHD_YES == pp->must_ikvi) ||
768 	 (0 != newline) ) &&
769        (MHD_NO == pp->ikvi (pp->cls,
770 			    MHD_POSTDATA_KIND,
771 			    pp->content_name,
772 			    pp->content_filename,
773 			    pp->content_type,
774 			    pp->content_transfer_encoding,
775 			    buf, pp->value_offset, newline)) )
776     {
777       pp->state = PP_Error;
778       return MHD_NO;
779     }
780   pp->must_ikvi = MHD_NO;
781   pp->value_offset += newline;
782   (*ioffptr) += newline;
783   return MHD_YES;
784 }
785 
786 
787 /**
788  *
789  * @param pp post processor context
790  */
791 static void
free_unmarked(struct MHD_PostProcessor * pp)792 free_unmarked (struct MHD_PostProcessor *pp)
793 {
794   if ((NULL != pp->content_name) && (0 == (pp->have & NE_content_name)))
795     {
796       free (pp->content_name);
797       pp->content_name = NULL;
798     }
799   if ((NULL != pp->content_type) && (0 == (pp->have & NE_content_type)))
800     {
801       free (pp->content_type);
802       pp->content_type = NULL;
803     }
804   if ((NULL != pp->content_filename) &&
805       (0 == (pp->have & NE_content_filename)))
806     {
807       free (pp->content_filename);
808       pp->content_filename = NULL;
809     }
810   if ((NULL != pp->content_transfer_encoding) &&
811       (0 == (pp->have & NE_content_transfer_encoding)))
812     {
813       free (pp->content_transfer_encoding);
814       pp->content_transfer_encoding = NULL;
815     }
816 }
817 
818 
819 /**
820  * Decode multipart POST data.
821  *
822  * @param pp post processor context
823  * @param post_data data to decode
824  * @param post_data_len number of bytes in @a post_data
825  * @return #MHD_NO on error,
826  */
827 static int
post_process_multipart(struct MHD_PostProcessor * pp,const char * post_data,size_t post_data_len)828 post_process_multipart (struct MHD_PostProcessor *pp,
829                         const char *post_data,
830 			size_t post_data_len)
831 {
832   char *buf;
833   size_t max;
834   size_t ioff;
835   size_t poff;
836   int state_changed;
837 
838   buf = (char *) &pp[1];
839   ioff = 0;
840   poff = 0;
841   state_changed = 1;
842   while ((poff < post_data_len) ||
843          ((pp->buffer_pos > 0) && (state_changed != 0)))
844     {
845       /* first, move as much input data
846          as possible to our internal buffer */
847       max = pp->buffer_size - pp->buffer_pos;
848       if (max > post_data_len - poff)
849         max = post_data_len - poff;
850       memcpy (&buf[pp->buffer_pos], &post_data[poff], max);
851       poff += max;
852       pp->buffer_pos += max;
853       if ((max == 0) && (state_changed == 0) && (poff < post_data_len))
854         {
855           pp->state = PP_Error;
856           return MHD_NO;        /* out of memory */
857         }
858       state_changed = 0;
859 
860       /* first state machine for '\r'-'\n' and '--' handling */
861       switch (pp->skip_rn)
862         {
863         case RN_Inactive:
864           break;
865         case RN_OptN:
866           if (buf[0] == '\n')
867             {
868               ioff++;
869               pp->skip_rn = RN_Inactive;
870               goto AGAIN;
871             }
872           /* fall-through! */
873         case RN_Dash:
874           if (buf[0] == '-')
875             {
876               ioff++;
877               pp->skip_rn = RN_Dash2;
878               goto AGAIN;
879             }
880           pp->skip_rn = RN_Full;
881           /* fall-through! */
882         case RN_Full:
883           if (buf[0] == '\r')
884             {
885               if ((pp->buffer_pos > 1) && (buf[1] == '\n'))
886                 {
887                   pp->skip_rn = RN_Inactive;
888                   ioff += 2;
889                 }
890               else
891                 {
892                   pp->skip_rn = RN_OptN;
893                   ioff++;
894                 }
895               goto AGAIN;
896             }
897           if (buf[0] == '\n')
898             {
899               ioff++;
900               pp->skip_rn = RN_Inactive;
901               goto AGAIN;
902             }
903           pp->skip_rn = RN_Inactive;
904           pp->state = PP_Error;
905           return MHD_NO;        /* no '\r\n' */
906         case RN_Dash2:
907           if (buf[0] == '-')
908             {
909               ioff++;
910               pp->skip_rn = RN_Full;
911               pp->state = pp->dash_state;
912               goto AGAIN;
913             }
914           pp->state = PP_Error;
915           break;
916         }
917 
918       /* main state engine */
919       switch (pp->state)
920         {
921         case PP_Error:
922           return MHD_NO;
923         case PP_Done:
924           /* did not expect to receive more data */
925           pp->state = PP_Error;
926           return MHD_NO;
927         case PP_Init:
928           /**
929            * Per RFC2046 5.1.1 NOTE TO IMPLEMENTORS, consume anything
930            * prior to the first multipart boundary:
931            *
932            * > There appears to be room for additional information prior
933            * > to the first boundary delimiter line and following the
934            * > final boundary delimiter line.  These areas should
935            * > generally be left blank, and implementations must ignore
936            * > anything that appears before the first boundary delimiter
937            * > line or after the last one.
938            */
939           (void) find_boundary (pp,
940 				pp->boundary,
941 				pp->blen,
942 				&ioff,
943 				PP_ProcessEntryHeaders, PP_Done);
944           break;
945         case PP_NextBoundary:
946           if (MHD_NO == find_boundary (pp,
947                                        pp->boundary,
948                                        pp->blen,
949                                        &ioff,
950                                        PP_ProcessEntryHeaders, PP_Done))
951             {
952               if (pp->state == PP_Error)
953                 return MHD_NO;
954               goto END;
955             }
956           break;
957         case PP_ProcessEntryHeaders:
958 	  pp->must_ikvi = MHD_YES;
959           if (MHD_NO ==
960               process_multipart_headers (pp, &ioff, PP_PerformCheckMultipart))
961             {
962               if (pp->state == PP_Error)
963                 return MHD_NO;
964               else
965                 goto END;
966             }
967           state_changed = 1;
968           break;
969         case PP_PerformCheckMultipart:
970           if ((pp->content_type != NULL) &&
971               (MHD_str_equal_caseless_n_ (pp->content_type,
972                                  "multipart/mixed",
973                                  strlen ("multipart/mixed"))))
974             {
975               pp->nested_boundary = strstr (pp->content_type, "boundary=");
976               if (pp->nested_boundary == NULL)
977                 {
978                   pp->state = PP_Error;
979                   return MHD_NO;
980                 }
981               pp->nested_boundary =
982                 strdup (&pp->nested_boundary[strlen ("boundary=")]);
983               if (pp->nested_boundary == NULL)
984                 {
985                   /* out of memory */
986                   pp->state = PP_Error;
987                   return MHD_NO;
988                 }
989               /* free old content type, we will need that field
990                  for the content type of the nested elements */
991               free (pp->content_type);
992               pp->content_type = NULL;
993               pp->nlen = strlen (pp->nested_boundary);
994               pp->state = PP_Nested_Init;
995               state_changed = 1;
996               break;
997             }
998           pp->state = PP_ProcessValueToBoundary;
999           pp->value_offset = 0;
1000           state_changed = 1;
1001           break;
1002         case PP_ProcessValueToBoundary:
1003           if (MHD_NO == process_value_to_boundary (pp,
1004                                                    &ioff,
1005                                                    pp->boundary,
1006                                                    pp->blen,
1007                                                    PP_PerformCleanup,
1008                                                    PP_Done))
1009             {
1010               if (pp->state == PP_Error)
1011                 return MHD_NO;
1012               break;
1013             }
1014           break;
1015         case PP_PerformCleanup:
1016           /* clean up state of one multipart form-data element! */
1017           pp->have = NE_none;
1018           free_unmarked (pp);
1019           if (pp->nested_boundary != NULL)
1020             {
1021               free (pp->nested_boundary);
1022               pp->nested_boundary = NULL;
1023             }
1024           pp->state = PP_ProcessEntryHeaders;
1025           state_changed = 1;
1026           break;
1027         case PP_Nested_Init:
1028           if (pp->nested_boundary == NULL)
1029             {
1030               pp->state = PP_Error;
1031               return MHD_NO;
1032             }
1033           if (MHD_NO == find_boundary (pp,
1034                                        pp->nested_boundary,
1035                                        pp->nlen,
1036                                        &ioff,
1037                                        PP_Nested_PerformMarking,
1038                                        PP_NextBoundary /* or PP_Error? */ ))
1039             {
1040               if (pp->state == PP_Error)
1041                 return MHD_NO;
1042               goto END;
1043             }
1044           break;
1045         case PP_Nested_PerformMarking:
1046           /* remember what headers were given
1047              globally */
1048           pp->have = NE_none;
1049           if (pp->content_name != NULL)
1050             pp->have |= NE_content_name;
1051           if (pp->content_type != NULL)
1052             pp->have |= NE_content_type;
1053           if (pp->content_filename != NULL)
1054             pp->have |= NE_content_filename;
1055           if (pp->content_transfer_encoding != NULL)
1056             pp->have |= NE_content_transfer_encoding;
1057           pp->state = PP_Nested_ProcessEntryHeaders;
1058           state_changed = 1;
1059           break;
1060         case PP_Nested_ProcessEntryHeaders:
1061           pp->value_offset = 0;
1062           if (MHD_NO ==
1063               process_multipart_headers (pp, &ioff,
1064                                          PP_Nested_ProcessValueToBoundary))
1065             {
1066               if (pp->state == PP_Error)
1067                 return MHD_NO;
1068               else
1069                 goto END;
1070             }
1071           state_changed = 1;
1072           break;
1073         case PP_Nested_ProcessValueToBoundary:
1074           if (MHD_NO == process_value_to_boundary (pp,
1075                                                    &ioff,
1076                                                    pp->nested_boundary,
1077                                                    pp->nlen,
1078                                                    PP_Nested_PerformCleanup,
1079                                                    PP_NextBoundary))
1080             {
1081               if (pp->state == PP_Error)
1082                 return MHD_NO;
1083               break;
1084             }
1085           break;
1086         case PP_Nested_PerformCleanup:
1087           free_unmarked (pp);
1088           pp->state = PP_Nested_ProcessEntryHeaders;
1089           state_changed = 1;
1090           break;
1091         default:
1092           mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL);          /* should never happen! */
1093         }
1094     AGAIN:
1095       if (ioff > 0)
1096         {
1097           memmove (buf, &buf[ioff], pp->buffer_pos - ioff);
1098           pp->buffer_pos -= ioff;
1099           ioff = 0;
1100           state_changed = 1;
1101         }
1102     }
1103 END:
1104   if (ioff != 0)
1105     {
1106       memmove (buf, &buf[ioff], pp->buffer_pos - ioff);
1107       pp->buffer_pos -= ioff;
1108     }
1109   if (poff < post_data_len)
1110     {
1111       pp->state = PP_Error;
1112       return MHD_NO;            /* serious error */
1113     }
1114   return MHD_YES;
1115 }
1116 
1117 
1118 /**
1119  * Parse and process POST data.  Call this function when POST data is
1120  * available (usually during an #MHD_AccessHandlerCallback) with the
1121  * "upload_data" and "upload_data_size".  Whenever possible, this will
1122  * then cause calls to the #MHD_PostDataIterator.
1123  *
1124  * @param pp the post processor
1125  * @param post_data @a post_data_len bytes of POST data
1126  * @param post_data_len length of @a post_data
1127  * @return #MHD_YES on success, #MHD_NO on error
1128  *         (out-of-memory, iterator aborted, parse error)
1129  * @ingroup request
1130  */
1131 int
MHD_post_process(struct MHD_PostProcessor * pp,const char * post_data,size_t post_data_len)1132 MHD_post_process (struct MHD_PostProcessor *pp,
1133                   const char *post_data, size_t post_data_len)
1134 {
1135   if (0 == post_data_len)
1136     return MHD_YES;
1137   if (NULL == pp)
1138     return MHD_NO;
1139   if (MHD_str_equal_caseless_n_ (MHD_HTTP_POST_ENCODING_FORM_URLENCODED, pp->encoding,
1140                          strlen(MHD_HTTP_POST_ENCODING_FORM_URLENCODED)))
1141     return post_process_urlencoded (pp, post_data, post_data_len);
1142   if (MHD_str_equal_caseless_n_ (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, pp->encoding,
1143                    strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)))
1144     return post_process_multipart (pp, post_data, post_data_len);
1145   /* this should never be reached */
1146   return MHD_NO;
1147 }
1148 
1149 
1150 /**
1151  * Release PostProcessor resources.
1152  *
1153  * @param pp post processor context to destroy
1154  * @return #MHD_YES if processing completed nicely,
1155  *         #MHD_NO if there were spurious characters / formatting
1156  *                problems; it is common to ignore the return
1157  *                value of this function
1158  * @ingroup request
1159  */
1160 int
MHD_destroy_post_processor(struct MHD_PostProcessor * pp)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 */
1192