diff options
Diffstat (limited to 'src/daemon/postprocessor.c')
-rw-r--r-- | src/daemon/postprocessor.c | 675 |
1 files changed, 675 insertions, 0 deletions
diff --git a/src/daemon/postprocessor.c b/src/daemon/postprocessor.c new file mode 100644 index 00000000..47d2efa6 --- /dev/null +++ b/src/daemon/postprocessor.c | |||
@@ -0,0 +1,675 @@ | |||
1 | /* | ||
2 | This file is part of libmicrohttpd | ||
3 | (C) 2007 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 | * States in the PP parser's state machine. | ||
30 | */ | ||
31 | enum PP_State | ||
32 | { | ||
33 | |||
34 | PP_Init = 0, | ||
35 | |||
36 | PP_HaveKey = 1, | ||
37 | |||
38 | PP_ExpectNewLine = 2, | ||
39 | |||
40 | PP_ExpectNewLineR = 3, | ||
41 | |||
42 | PP_ExpectNewLineN = 4, | ||
43 | |||
44 | PP_Headers = 5, | ||
45 | |||
46 | PP_SkipRNRN = 6, | ||
47 | |||
48 | PP_SkipNRN = 7, | ||
49 | |||
50 | PP_SkipRN = 8, | ||
51 | |||
52 | PP_SkipN = 9, | ||
53 | |||
54 | PP_ValueToBoundary = 10, | ||
55 | |||
56 | PP_FinalDash = 11, | ||
57 | |||
58 | PP_Error = 9999, | ||
59 | |||
60 | |||
61 | }; | ||
62 | |||
63 | /** | ||
64 | * Internal state of the post-processor. | ||
65 | */ | ||
66 | struct MHD_PostProcessor | ||
67 | { | ||
68 | |||
69 | /** | ||
70 | * The connection for which we are doing | ||
71 | * POST processing. | ||
72 | */ | ||
73 | struct MHD_Connection *connection; | ||
74 | |||
75 | /** | ||
76 | * Function to call with POST data. | ||
77 | */ | ||
78 | MHD_PostDataIterator ikvi; | ||
79 | |||
80 | /** | ||
81 | * Extra argument to ikvi. | ||
82 | */ | ||
83 | void *cls; | ||
84 | |||
85 | /** | ||
86 | * Encoding as given by the headers of the | ||
87 | * connection. | ||
88 | */ | ||
89 | const char *encoding; | ||
90 | |||
91 | /** | ||
92 | * Pointer to the name given in disposition. | ||
93 | */ | ||
94 | char *content_disposition; | ||
95 | |||
96 | /** | ||
97 | * Pointer to the (current) content type. | ||
98 | */ | ||
99 | char *content_type; | ||
100 | |||
101 | /** | ||
102 | * Pointer to the (current) filename. | ||
103 | */ | ||
104 | char *filename; | ||
105 | |||
106 | /** | ||
107 | * Pointer to the (current) encoding. | ||
108 | */ | ||
109 | char *transfer_encoding; | ||
110 | |||
111 | /** | ||
112 | * Unprocessed value bytes due to escape | ||
113 | * sequences (URL-encoding only). | ||
114 | */ | ||
115 | char xbuf[8]; | ||
116 | |||
117 | /** | ||
118 | * Size of our buffer for the key. | ||
119 | */ | ||
120 | unsigned int buffer_size; | ||
121 | |||
122 | /** | ||
123 | * Current position in the key buffer. | ||
124 | */ | ||
125 | unsigned int buffer_pos; | ||
126 | |||
127 | /** | ||
128 | * Current position in xbuf. | ||
129 | */ | ||
130 | unsigned int xbuf_pos; | ||
131 | |||
132 | /** | ||
133 | * Current offset in the value being processed. | ||
134 | */ | ||
135 | unsigned int value_offset; | ||
136 | |||
137 | /** | ||
138 | * State of the parser. | ||
139 | */ | ||
140 | enum PP_State state; | ||
141 | |||
142 | }; | ||
143 | |||
144 | |||
145 | /** | ||
146 | * Create a PostProcessor. | ||
147 | * | ||
148 | * A PostProcessor can be used to (incrementally) | ||
149 | * parse the data portion of a POST request. | ||
150 | * | ||
151 | * @param connection the connection on which the POST is | ||
152 | * happening (used to determine the POST format) | ||
153 | * @param buffer_size maximum number of bytes to use for | ||
154 | * internal buffering (used only for the parsing, | ||
155 | * specifically the parsing of the keys). A | ||
156 | * tiny value (256-1024) should be sufficient. | ||
157 | * Do NOT use 0. | ||
158 | * @param ikvi iterator to be called with the parsed data | ||
159 | * @param cls first argument to ikvi | ||
160 | * @return NULL on error (out of memory, unsupported encoding), | ||
161 | * otherwise a PP handle | ||
162 | */ | ||
163 | struct MHD_PostProcessor * | ||
164 | MHD_create_post_processor (struct MHD_Connection *connection, | ||
165 | unsigned int buffer_size, | ||
166 | MHD_PostDataIterator ikvi, void *cls) | ||
167 | { | ||
168 | struct MHD_PostProcessor *ret; | ||
169 | const char *encoding; | ||
170 | |||
171 | if ((buffer_size < 256) || (connection == NULL) || (ikvi == NULL)) | ||
172 | abort (); | ||
173 | encoding = MHD_lookup_connection_value (connection, | ||
174 | MHD_HEADER_KIND, | ||
175 | MHD_HTTP_HEADER_CONTENT_TYPE); | ||
176 | if (encoding == NULL) | ||
177 | return NULL; | ||
178 | if ((0 != strcasecmp (MHD_HTTP_POST_ENCODING_FORM_URLENCODED, | ||
179 | encoding)) && | ||
180 | (0 != strcasecmp (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, encoding))) | ||
181 | return NULL; | ||
182 | ret = malloc (sizeof (struct MHD_PostProcessor) + buffer_size + 1); | ||
183 | if (ret == NULL) | ||
184 | return NULL; | ||
185 | memset (ret, 0, sizeof (struct MHD_PostProcessor)); | ||
186 | ret->connection = connection; | ||
187 | ret->ikvi = ikvi; | ||
188 | ret->cls = cls; | ||
189 | ret->encoding = encoding; | ||
190 | ret->buffer_size = buffer_size; | ||
191 | ret->state = PP_Init; | ||
192 | return ret; | ||
193 | } | ||
194 | |||
195 | /** | ||
196 | * On-stack buffer that we use for un-escaping of the value. | ||
197 | */ | ||
198 | #define XBUF_SIZE 1024 | ||
199 | |||
200 | /** | ||
201 | * Process url-encoded POST data. | ||
202 | */ | ||
203 | static int | ||
204 | post_process_urlencoded (struct MHD_PostProcessor *pp, | ||
205 | const char *post_data, unsigned int post_data_len) | ||
206 | { | ||
207 | unsigned int equals; | ||
208 | unsigned int amper; | ||
209 | unsigned int poff; | ||
210 | unsigned int xoff; | ||
211 | unsigned int delta; | ||
212 | char *buf; | ||
213 | char xbuf[XBUF_SIZE + 1]; | ||
214 | |||
215 | buf = (char *) &pp[1]; | ||
216 | poff = 0; | ||
217 | while (poff < post_data_len) | ||
218 | { | ||
219 | switch (pp->state) | ||
220 | { | ||
221 | case PP_Init: | ||
222 | equals = 0; | ||
223 | while ((equals + poff < post_data_len) && | ||
224 | (post_data[equals + poff] != '=')) | ||
225 | equals++; | ||
226 | if (equals + pp->buffer_pos > pp->buffer_size) | ||
227 | { | ||
228 | pp->state = PP_Error; /* out of memory */ | ||
229 | return MHD_NO; | ||
230 | } | ||
231 | memcpy (&buf[pp->buffer_pos], &post_data[poff], equals); | ||
232 | pp->buffer_pos += equals; | ||
233 | if (equals + poff == post_data_len) | ||
234 | return MHD_YES; /* no '=' yet */ | ||
235 | buf[pp->buffer_pos] = '\0'; /* 0-terminate key */ | ||
236 | pp->buffer_pos = 0; /* reset for next key */ | ||
237 | MHD_http_unescape (buf); | ||
238 | poff += equals + 1; | ||
239 | pp->state = PP_HaveKey; | ||
240 | pp->value_offset = 0; | ||
241 | break; | ||
242 | case PP_HaveKey: | ||
243 | /* obtain rest of value from previous iteration */ | ||
244 | memcpy (xbuf, pp->xbuf, pp->xbuf_pos); | ||
245 | xoff = pp->xbuf_pos; | ||
246 | pp->xbuf_pos = 0; | ||
247 | |||
248 | /* find last position in input buffer that is part of the value */ | ||
249 | amper = 0; | ||
250 | while ((amper + poff < post_data_len) && | ||
251 | (post_data[amper + poff] != '&') && | ||
252 | (post_data[amper + poff] != '\n') && | ||
253 | (post_data[amper + poff] != '\r')) | ||
254 | amper++; | ||
255 | |||
256 | /* compute delta, the maximum number of bytes that we will be able to | ||
257 | process right now (either amper-limited of xbuf-size limited) */ | ||
258 | delta = amper; | ||
259 | if (delta > XBUF_SIZE - xoff) | ||
260 | delta = XBUF_SIZE - xoff; | ||
261 | |||
262 | /* move input into processing buffer */ | ||
263 | memcpy (&xbuf[xoff], &post_data[poff], delta); | ||
264 | xoff += delta; | ||
265 | poff += delta; | ||
266 | |||
267 | /* find if escape sequence is at the end of the processing buffer; | ||
268 | if so, exclude those from processing (reduce delta to point at | ||
269 | end of processed region) */ | ||
270 | delta = xoff; | ||
271 | if ((delta > 0) && (xbuf[delta - 1] == '%')) | ||
272 | delta--; | ||
273 | else if ((delta > 1) && (xbuf[delta - 2] == '%')) | ||
274 | delta -= 2; | ||
275 | |||
276 | /* if we have an incomplete escape sequence, save it to | ||
277 | pp->xbuf for later */ | ||
278 | if (delta < xoff) | ||
279 | { | ||
280 | memcpy (pp->xbuf, &xbuf[delta], xoff - delta); | ||
281 | pp->xbuf_pos = xoff - delta; | ||
282 | xoff = delta; | ||
283 | } | ||
284 | |||
285 | /* If we have nothing to do (delta == 0) and | ||
286 | not just because the value is empty (are | ||
287 | waiting for more data), go for next iteration */ | ||
288 | if ((xoff == 0) && (poff == post_data_len)) | ||
289 | continue; | ||
290 | |||
291 | /* unescape */ | ||
292 | xbuf[xoff] = '\0'; /* 0-terminate in preparation */ | ||
293 | MHD_http_unescape (xbuf); | ||
294 | |||
295 | /* finally: call application! */ | ||
296 | pp->ikvi (pp->cls, MHD_POSTDATA_KIND, (const char *) &pp[1], /* key */ | ||
297 | NULL, NULL, NULL, xbuf, pp->value_offset, xoff); | ||
298 | pp->value_offset += xoff; | ||
299 | |||
300 | /* are we done with the value? */ | ||
301 | if (poff < post_data_len) | ||
302 | { | ||
303 | /* we found the end of the value! */ | ||
304 | pp->state = PP_Init; | ||
305 | poff++; /* skip '&' or new-lines */ | ||
306 | |||
307 | if ((post_data[poff - 1] == '\n') || | ||
308 | (post_data[poff - 1] == '\r')) | ||
309 | pp->state = PP_ExpectNewLine; | ||
310 | } | ||
311 | break; | ||
312 | case PP_ExpectNewLine: | ||
313 | if ((post_data[poff] == '\n') || (post_data[poff] == '\r')) | ||
314 | { | ||
315 | poff++; | ||
316 | /* we are done, report error if we receive any more... */ | ||
317 | pp->state = PP_Error; | ||
318 | return MHD_YES; | ||
319 | } | ||
320 | return MHD_NO; | ||
321 | case PP_Error: | ||
322 | return MHD_NO; | ||
323 | default: | ||
324 | abort (); /* should never happen! */ | ||
325 | } | ||
326 | } | ||
327 | return MHD_YES; | ||
328 | } | ||
329 | |||
330 | /** | ||
331 | * If the given line matches the prefix, strdup the | ||
332 | * rest of the line into the suffix ptr. | ||
333 | * | ||
334 | * @return MHD_YES if there was a match, MHD_NO if not | ||
335 | */ | ||
336 | static int | ||
337 | try_match_header (const char *prefix, char *line, char **suffix) | ||
338 | { | ||
339 | if (0 == strncasecmp (prefix, line, strlen (prefix))) | ||
340 | { | ||
341 | *suffix = strdup (&line[strlen (prefix)]); | ||
342 | return MHD_YES; | ||
343 | } | ||
344 | return MHD_NO; | ||
345 | } | ||
346 | |||
347 | /** | ||
348 | * Decode multipart POST data. | ||
349 | * | ||
350 | * TODO: If the content-type is multipart/mixed, we do not do anything | ||
351 | * special. However, we should probably break the individual values | ||
352 | * apart and give them to the callback individually (will require some | ||
353 | * additional states & state). | ||
354 | * | ||
355 | * TODO: this code has never been tested... | ||
356 | * | ||
357 | * See http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4 | ||
358 | */ | ||
359 | static int | ||
360 | post_process_multipart (struct MHD_PostProcessor *pp, | ||
361 | const char *post_data, unsigned int post_data_len) | ||
362 | { | ||
363 | char *buf; | ||
364 | const char *boundary; | ||
365 | unsigned int max; | ||
366 | unsigned int ioff; | ||
367 | unsigned int poff; | ||
368 | unsigned int newline; | ||
369 | unsigned int endquote; | ||
370 | size_t blen; | ||
371 | |||
372 | buf = (char *) &pp[1]; | ||
373 | ioff = 0; | ||
374 | poff = 0; | ||
375 | boundary = | ||
376 | &pp->encoding[strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)]; | ||
377 | if (NULL != strstr (boundary, "boundary=")) | ||
378 | boundary = strstr (boundary, "boundary=") + strlen ("boundary="); | ||
379 | else | ||
380 | return MHD_NO; /* failed to determine boundary */ | ||
381 | blen = strlen (boundary); | ||
382 | if (blen * 2 + 2 > pp->buffer_size) | ||
383 | return MHD_NO; /* (will be) out of memory */ | ||
384 | while ((poff < post_data_len) || (pp->buffer_pos > ioff)) | ||
385 | { | ||
386 | /* first, move data to our internal buffer */ | ||
387 | max = pp->buffer_size - pp->buffer_pos; | ||
388 | if ((max < ioff) && (max < post_data_len)) | ||
389 | { | ||
390 | memmove (buf, &buf[ioff], pp->buffer_pos - ioff); | ||
391 | pp->buffer_pos -= ioff; | ||
392 | ioff = 0; | ||
393 | max = pp->buffer_size - pp->buffer_pos; | ||
394 | } | ||
395 | if (max > post_data_len) | ||
396 | max = post_data_len; | ||
397 | memcpy (&buf[pp->buffer_pos], post_data, max); | ||
398 | poff += max; | ||
399 | pp->buffer_pos += max; | ||
400 | |||
401 | switch (pp->state) | ||
402 | { | ||
403 | case PP_Init: | ||
404 | /* we're looking for the boundary */ | ||
405 | if (pp->buffer_pos < 2 + blen + ioff) | ||
406 | goto END; | ||
407 | if ((0 != memcmp ("--", &buf[ioff], 2)) || | ||
408 | (0 != memcmp (&buf[ioff + 2], boundary, blen))) | ||
409 | return MHD_NO; /* expected boundary */ | ||
410 | |||
411 | /* remove boundary from buffer */ | ||
412 | ioff += 2 + blen; | ||
413 | |||
414 | /* next: start with headers */ | ||
415 | pp->state = PP_ExpectNewLineR; | ||
416 | break; | ||
417 | case PP_ExpectNewLineR: | ||
418 | if (buf[ioff] == '-') | ||
419 | { | ||
420 | /* last boundary ends with "--" */ | ||
421 | ioff++; | ||
422 | pp->state = PP_FinalDash; | ||
423 | break; | ||
424 | } | ||
425 | if (buf[ioff] == '\r') | ||
426 | { | ||
427 | ioff++; | ||
428 | pp->state = PP_ExpectNewLineN; | ||
429 | break; | ||
430 | } | ||
431 | /* fall through! */ | ||
432 | case PP_ExpectNewLineN: | ||
433 | if (buf[ioff] == '\n') | ||
434 | { | ||
435 | ioff++; | ||
436 | pp->state = PP_Headers; | ||
437 | break; | ||
438 | } | ||
439 | return MHD_NO; | ||
440 | case PP_Headers: | ||
441 | newline = 0; | ||
442 | while ((newline + ioff < pp->buffer_pos) && | ||
443 | (buf[newline + ioff] != '\r') && | ||
444 | (buf[newline + ioff] != '\n')) | ||
445 | newline++; | ||
446 | if (newline == pp->buffer_size) | ||
447 | return MHD_NO; /* out of memory */ | ||
448 | if (newline + ioff == pp->buffer_pos) | ||
449 | { | ||
450 | /* try to make more room */ | ||
451 | memmove (buf, &buf[ioff], pp->buffer_pos - ioff); | ||
452 | pp->buffer_pos -= ioff; | ||
453 | ioff = 0; | ||
454 | break; | ||
455 | } | ||
456 | if (newline == 0) | ||
457 | { | ||
458 | pp->state = PP_SkipRNRN; | ||
459 | break; | ||
460 | } | ||
461 | buf[ioff + newline] = '\0'; | ||
462 | if ((MHD_YES | ||
463 | == try_match_header ("Content-Disposition: form-data; name=\"", | ||
464 | &buf[ioff], | ||
465 | &pp->content_disposition)) && | ||
466 | (pp->content_disposition != NULL) && | ||
467 | (0 < strlen (pp->content_disposition))) | ||
468 | { | ||
469 | /* find end-quote; then check if we also have a filename! */ | ||
470 | endquote = 0; | ||
471 | while ((pp->content_disposition[endquote] != '\"') && | ||
472 | (pp->content_disposition[endquote] != '\0')) | ||
473 | endquote++; | ||
474 | pp->content_disposition[endquote++] = '\0'; /* remove end-quote */ | ||
475 | if ((MHD_YES | ||
476 | == try_match_header (" filename=", | ||
477 | &pp->content_disposition[endquote], | ||
478 | &pp->filename)) && | ||
479 | (pp->filename != NULL) && (0 < strlen (pp->filename))) | ||
480 | pp->filename[strlen (pp->filename) - 1] = '\0'; /* remove end-quote */ | ||
481 | } | ||
482 | try_match_header ("Content-Type: ", &buf[ioff], &pp->content_type); | ||
483 | try_match_header ("Content-Transfer-Encoding: ", | ||
484 | &buf[ioff], &pp->transfer_encoding); | ||
485 | break; | ||
486 | case PP_SkipRNRN: | ||
487 | if (buf[ioff] == '\r') | ||
488 | { | ||
489 | ioff++; | ||
490 | pp->state = PP_SkipNRN; | ||
491 | break; | ||
492 | } | ||
493 | /* fall through! */ | ||
494 | case PP_SkipNRN: | ||
495 | if (buf[ioff] == '\n') | ||
496 | { | ||
497 | ioff++; | ||
498 | pp->state = PP_SkipRN; | ||
499 | break; | ||
500 | } | ||
501 | return MHD_NO; /* parse error */ | ||
502 | case PP_SkipRN: | ||
503 | if (buf[ioff] == '\r') | ||
504 | { | ||
505 | ioff++; | ||
506 | pp->state = PP_SkipN; | ||
507 | break; | ||
508 | } | ||
509 | /* fall through! */ | ||
510 | case PP_SkipN: | ||
511 | if (buf[ioff] == '\n') | ||
512 | { | ||
513 | ioff++; | ||
514 | pp->state = PP_ValueToBoundary; | ||
515 | pp->value_offset = 0; | ||
516 | break; | ||
517 | } | ||
518 | return MHD_NO; /* parse error */ | ||
519 | case PP_ValueToBoundary: | ||
520 | /* all data in buf until the boundary | ||
521 | (\r\n--+boundary) is part of the value */ | ||
522 | newline = 0; | ||
523 | while (1) | ||
524 | { | ||
525 | while ((newline + ioff + 4 < pp->buffer_pos) && | ||
526 | (0 != memcmp ("\r\n--", &buf[newline + ioff], 4))) | ||
527 | newline++; | ||
528 | if (newline + blen + 4 > pp->buffer_size) | ||
529 | { | ||
530 | /* boundary not in sight -- | ||
531 | process data, then make room for more! */ | ||
532 | if (MHD_NO == pp->ikvi (pp->cls, | ||
533 | MHD_POSTDATA_KIND, | ||
534 | pp->content_disposition, | ||
535 | pp->filename, | ||
536 | pp->content_type, | ||
537 | pp->transfer_encoding, | ||
538 | &buf[ioff], | ||
539 | pp->value_offset, newline)) | ||
540 | { | ||
541 | pp->state = PP_Error; | ||
542 | break; | ||
543 | } | ||
544 | pp->value_offset += newline; | ||
545 | ioff += newline; | ||
546 | memmove (buf, &buf[ioff], pp->buffer_pos - ioff); | ||
547 | pp->buffer_pos -= ioff; | ||
548 | break; | ||
549 | } | ||
550 | if (newline + blen + 4 < pp->buffer_pos) | ||
551 | { | ||
552 | /* can check for boundary right now! */ | ||
553 | if (0 == memcmp (&buf[newline + ioff + 4], boundary, blen)) | ||
554 | { | ||
555 | /* found: process data, then look for more */ | ||
556 | if (MHD_NO == pp->ikvi (pp->cls, | ||
557 | MHD_POSTDATA_KIND, | ||
558 | pp->content_disposition, | ||
559 | pp->filename, | ||
560 | pp->content_type, | ||
561 | pp->transfer_encoding, | ||
562 | &buf[ioff], | ||
563 | pp->value_offset, newline)) | ||
564 | { | ||
565 | pp->state = PP_Error; | ||
566 | break; | ||
567 | } | ||
568 | |||
569 | /* clean up! */ | ||
570 | if (pp->content_type != NULL) | ||
571 | { | ||
572 | free (pp->content_type); | ||
573 | pp->content_type = NULL; | ||
574 | } | ||
575 | if (pp->content_disposition != NULL) | ||
576 | { | ||
577 | free (pp->content_disposition); | ||
578 | pp->content_disposition = NULL; | ||
579 | } | ||
580 | if (pp->filename != NULL) | ||
581 | { | ||
582 | free (pp->filename); | ||
583 | pp->filename = NULL; | ||
584 | } | ||
585 | if (pp->transfer_encoding != NULL) | ||
586 | { | ||
587 | free (pp->transfer_encoding); | ||
588 | pp->transfer_encoding = NULL; | ||
589 | } | ||
590 | pp->value_offset = 0; | ||
591 | ioff += newline + 2; /* skip data + new line */ | ||
592 | pp->state = PP_Init; | ||
593 | break; | ||
594 | } | ||
595 | /* not the boundary, look further! */ | ||
596 | newline += 4; | ||
597 | continue; | ||
598 | } | ||
599 | |||
600 | |||
601 | } | ||
602 | break; | ||
603 | case PP_FinalDash: | ||
604 | if (buf[ioff] == '-') | ||
605 | { | ||
606 | /* last boundary ends with "--" */ | ||
607 | ioff++; | ||
608 | pp->state = PP_Error; | ||
609 | break; | ||
610 | } | ||
611 | return MHD_NO; /* parse error */ | ||
612 | case PP_Error: | ||
613 | return MHD_NO; | ||
614 | default: | ||
615 | abort (); /* should never happen! */ | ||
616 | |||
617 | } | ||
618 | } | ||
619 | END: | ||
620 | memmove (buf, &buf[ioff], pp->buffer_pos - ioff); | ||
621 | pp->buffer_pos -= ioff; | ||
622 | return MHD_YES; | ||
623 | } | ||
624 | |||
625 | /** | ||
626 | * Parse and process POST data. | ||
627 | * Call this function when POST data is available | ||
628 | * (usually during an MHD_AccessHandlerCallback) | ||
629 | * with the upload_data and upload_data_size. | ||
630 | * Whenever possible, this will then cause calls | ||
631 | * to the MHD_IncrementalKeyValueIterator. | ||
632 | * | ||
633 | * @param pp the post processor | ||
634 | * @param post_data post_data_len bytes of POST data | ||
635 | * @param post_data_len length of post_data | ||
636 | * @return MHD_YES on success, MHD_NO on error | ||
637 | * (out-of-memory, iterator aborted, parse error) | ||
638 | */ | ||
639 | int | ||
640 | MHD_post_process (struct MHD_PostProcessor *pp, | ||
641 | const char *post_data, unsigned int post_data_len) | ||
642 | { | ||
643 | if (post_data_len == 0) | ||
644 | return MHD_YES; | ||
645 | if (0 == strcasecmp (MHD_HTTP_POST_ENCODING_FORM_URLENCODED, pp->encoding)) | ||
646 | return post_process_urlencoded (pp, post_data, post_data_len); | ||
647 | if (0 == | ||
648 | strncasecmp (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, pp->encoding, | ||
649 | strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA))) | ||
650 | return post_process_multipart (pp, post_data, post_data_len); | ||
651 | /* this should never be reached */ | ||
652 | return MHD_NO; | ||
653 | } | ||
654 | |||
655 | /** | ||
656 | * Release PostProcessor resources. | ||
657 | */ | ||
658 | void | ||
659 | MHD_destroy_post_processor (struct MHD_PostProcessor *pp) | ||
660 | { | ||
661 | /* These internal strings need cleaning up since | ||
662 | the post-processing may have been interrupted | ||
663 | at any stage */ | ||
664 | if (pp->content_type != NULL) | ||
665 | free (pp->content_type); | ||
666 | if (pp->content_disposition != NULL) | ||
667 | free (pp->content_disposition); | ||
668 | if (pp->filename != NULL) | ||
669 | free (pp->filename); | ||
670 | if (pp->transfer_encoding != NULL) | ||
671 | free (pp->transfer_encoding); | ||
672 | free (pp); | ||
673 | } | ||
674 | |||
675 | /* end of postprocessor.c */ | ||