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