00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00026 #include "internal.h"
00027
00031 #define XBUF_SIZE 1024
00032
00036 enum PP_State
00037 {
00038
00039 PP_Error,
00040 PP_Done,
00041 PP_Init,
00042
00043
00044 PP_ProcessValue,
00045 PP_ExpectNewLine,
00046
00047
00048 PP_ProcessEntryHeaders,
00049 PP_PerformCheckMultipart,
00050 PP_ProcessValueToBoundary,
00051 PP_PerformCleanup,
00052
00053
00054 PP_Nested_Init,
00055 PP_Nested_PerformMarking,
00056 PP_Nested_ProcessEntryHeaders,
00057 PP_Nested_ProcessValueToBoundary,
00058 PP_Nested_PerformCleanup,
00059
00060 };
00061
00062 enum RN_State
00063 {
00067 RN_Inactive = 0,
00068
00073 RN_OptN = 1,
00074
00079 RN_Full = 2,
00080
00085 RN_Dash = 3,
00086
00090 RN_Dash2 = 4,
00091 };
00092
00098 enum NE_State
00099 {
00100 NE_none = 0,
00101 NE_content_name = 1,
00102 NE_content_type = 2,
00103 NE_content_filename = 4,
00104 NE_content_transfer_encoding = 8,
00105 };
00106
00111 struct MHD_PostProcessor
00112 {
00113
00118 struct MHD_Connection *connection;
00119
00123 MHD_PostDataIterator ikvi;
00124
00128 void *cls;
00129
00134 const char *encoding;
00135
00139 const char *boundary;
00140
00144 char *nested_boundary;
00145
00149 char *content_name;
00150
00154 char *content_type;
00155
00159 char *content_filename;
00160
00164 char *content_transfer_encoding;
00165
00170 char xbuf[8];
00171
00175 size_t buffer_size;
00176
00180 size_t buffer_pos;
00181
00185 size_t xbuf_pos;
00186
00190 uint64_t value_offset;
00191
00195 size_t blen;
00196
00200 size_t nlen;
00201
00205 enum PP_State state;
00206
00213 enum RN_State skip_rn;
00214
00219 enum PP_State dash_state;
00220
00225 enum NE_State have;
00226
00227 };
00228
00229
00248 struct MHD_PostProcessor *
00249 MHD_create_post_processor (struct MHD_Connection *connection,
00250 size_t buffer_size,
00251 MHD_PostDataIterator ikvi, void *cls)
00252 {
00253 struct MHD_PostProcessor *ret;
00254 const char *encoding;
00255 const char *boundary;
00256 size_t blen;
00257
00258 if ((buffer_size < 256) || (connection == NULL) || (ikvi == NULL))
00259 mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL);
00260 encoding = MHD_lookup_connection_value (connection,
00261 MHD_HEADER_KIND,
00262 MHD_HTTP_HEADER_CONTENT_TYPE);
00263 if (encoding == NULL)
00264 return NULL;
00265 boundary = NULL;
00266 if (0 != strncasecmp (MHD_HTTP_POST_ENCODING_FORM_URLENCODED, encoding,
00267 strlen (MHD_HTTP_POST_ENCODING_FORM_URLENCODED)))
00268 {
00269 if (0 !=
00270 strncasecmp (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, encoding,
00271 strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)))
00272 return NULL;
00273 boundary =
00274 &encoding[strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)];
00275
00276 boundary = strstr (boundary, "boundary=");
00277 if (NULL == boundary)
00278 return NULL;
00279 boundary += strlen ("boundary=");
00280 blen = strlen (boundary);
00281 if ((blen == 0) || (blen * 2 + 2 > buffer_size))
00282 return NULL;
00283 }
00284 else
00285 blen = 0;
00286 ret = malloc (sizeof (struct MHD_PostProcessor) + buffer_size + 1);
00287 if (ret == NULL)
00288 return NULL;
00289 memset (ret, 0, sizeof (struct MHD_PostProcessor) + buffer_size + 1);
00290 ret->connection = connection;
00291 ret->ikvi = ikvi;
00292 ret->cls = cls;
00293 ret->encoding = encoding;
00294 ret->buffer_size = buffer_size;
00295 ret->state = PP_Init;
00296 ret->blen = blen;
00297 ret->boundary = boundary;
00298 ret->skip_rn = RN_Inactive;
00299 return ret;
00300 }
00301
00305 static int
00306 post_process_urlencoded (struct MHD_PostProcessor *pp,
00307 const char *post_data,
00308 size_t post_data_len)
00309 {
00310 size_t equals;
00311 size_t amper;
00312 size_t poff;
00313 size_t xoff;
00314 size_t delta;
00315 int end_of_value_found;
00316 char *buf;
00317 char xbuf[XBUF_SIZE + 1];
00318
00319 buf = (char *) &pp[1];
00320 poff = 0;
00321 while (poff < post_data_len)
00322 {
00323 switch (pp->state)
00324 {
00325 case PP_Error:
00326 return MHD_NO;
00327 case PP_Done:
00328
00329 pp->state = PP_Error;
00330 return MHD_NO;
00331 case PP_Init:
00332 equals = 0;
00333 while ((equals + poff < post_data_len) &&
00334 (post_data[equals + poff] != '='))
00335 equals++;
00336 if (equals + pp->buffer_pos > pp->buffer_size)
00337 {
00338 pp->state = PP_Error;
00339 return MHD_NO;
00340 }
00341 memcpy (&buf[pp->buffer_pos], &post_data[poff], equals);
00342 pp->buffer_pos += equals;
00343 if (equals + poff == post_data_len)
00344 return MHD_YES;
00345 buf[pp->buffer_pos] = '\0';
00346 pp->buffer_pos = 0;
00347 MHD_http_unescape (NULL, NULL, buf);
00348 poff += equals + 1;
00349 pp->state = PP_ProcessValue;
00350 pp->value_offset = 0;
00351 break;
00352 case PP_ProcessValue:
00353
00354 memcpy (xbuf, pp->xbuf, pp->xbuf_pos);
00355 xoff = pp->xbuf_pos;
00356 pp->xbuf_pos = 0;
00357
00358
00359 amper = 0;
00360 while ((amper + poff < post_data_len) &&
00361 (amper < XBUF_SIZE) &&
00362 (post_data[amper + poff] != '&') &&
00363 (post_data[amper + poff] != '\n') &&
00364 (post_data[amper + poff] != '\r'))
00365 amper++;
00366 end_of_value_found = ((amper + poff < post_data_len) &&
00367 ((post_data[amper + poff] == '&') ||
00368 (post_data[amper + poff] == '\n') ||
00369 (post_data[amper + poff] == '\r')));
00370
00371
00372 delta = amper;
00373 if (delta > XBUF_SIZE - xoff)
00374 delta = XBUF_SIZE - xoff;
00375
00376
00377 memcpy (&xbuf[xoff], &post_data[poff], delta);
00378 xoff += delta;
00379 poff += delta;
00380
00381
00382
00383
00384 delta = xoff;
00385 if ((delta > 0) && (xbuf[delta - 1] == '%'))
00386 delta--;
00387 else if ((delta > 1) && (xbuf[delta - 2] == '%'))
00388 delta -= 2;
00389
00390
00391
00392 if (delta < xoff)
00393 {
00394 memcpy (pp->xbuf, &xbuf[delta], xoff - delta);
00395 pp->xbuf_pos = xoff - delta;
00396 xoff = delta;
00397 }
00398
00399
00400
00401
00402 if ((xoff == 0) && (poff == post_data_len))
00403 continue;
00404
00405
00406 xbuf[xoff] = '\0';
00407 xoff = MHD_http_unescape (NULL, NULL, xbuf);
00408
00409 if (MHD_NO == pp->ikvi (pp->cls, MHD_POSTDATA_KIND, (const char *) &pp[1],
00410 NULL, NULL, NULL, xbuf, pp->value_offset,
00411 xoff))
00412 {
00413 pp->state = PP_Error;
00414 return MHD_NO;
00415 }
00416 pp->value_offset += xoff;
00417
00418
00419 if (end_of_value_found)
00420 {
00421
00422 if ((post_data[poff] == '\n') || (post_data[poff] == '\r'))
00423 {
00424 pp->state = PP_ExpectNewLine;
00425 }
00426 else
00427 {
00428 poff++;
00429 pp->state = PP_Init;
00430 }
00431 }
00432 break;
00433 case PP_ExpectNewLine:
00434 if ((post_data[poff] == '\n') || (post_data[poff] == '\r'))
00435 {
00436 poff++;
00437
00438 pp->state = PP_Done;
00439 return MHD_YES;
00440 }
00441 return MHD_NO;
00442 default:
00443 mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL);
00444 }
00445 }
00446 return MHD_YES;
00447 }
00448
00455 static int
00456 try_match_header (const char *prefix, char *line, char **suffix)
00457 {
00458 if (NULL != *suffix)
00459 return MHD_NO;
00460 while (*line != 0)
00461 {
00462 if (0 == strncasecmp (prefix, line, strlen (prefix)))
00463 {
00464 *suffix = strdup (&line[strlen (prefix)]);
00465 return MHD_YES;
00466 }
00467 ++line;
00468 }
00469 return MHD_NO;
00470 }
00471
00472 static int
00473 find_boundary (struct MHD_PostProcessor *pp,
00474 const char *boundary,
00475 size_t blen,
00476 size_t *ioffptr,
00477 enum PP_State next_state, enum PP_State next_dash_state)
00478 {
00479 char *buf = (char *) &pp[1];
00480
00481 if (pp->buffer_pos < 2 + blen)
00482 {
00483 if (pp->buffer_pos == pp->buffer_size)
00484 pp->state = PP_Error;
00485 return MHD_NO;
00486 }
00487 if ((0 != memcmp ("--", buf, 2)) || (0 != memcmp (&buf[2], boundary, blen)))
00488 {
00489 pp->state = PP_Error;
00490 return MHD_NO;
00491 }
00492
00493 (*ioffptr) += 2 + blen;
00494
00495 pp->skip_rn = RN_Dash;
00496 pp->state = next_state;
00497 pp->dash_state = next_dash_state;
00498 return MHD_YES;
00499 }
00500
00509 static void
00510 try_get_value (const char *buf, const char *key, char **destination)
00511 {
00512 const char *spos;
00513 const char *bpos;
00514 const char *endv;
00515 size_t klen;
00516 size_t vlen;
00517
00518 if (NULL != *destination)
00519 return;
00520 bpos = buf;
00521 klen = strlen (key);
00522 while (NULL != (spos = strstr (bpos, key)))
00523 {
00524 if ((spos[klen] != '=') || ((spos != buf) && (spos[-1] != ' ')))
00525 {
00526
00527 bpos = spos + 1;
00528 continue;
00529 }
00530 if (spos[klen + 1] != '"')
00531 return;
00532 if (NULL == (endv = strstr (&spos[klen + 2], "\"")))
00533 return;
00534 vlen = endv - spos - klen - 1;
00535 *destination = malloc (vlen);
00536 if (NULL == *destination)
00537 return;
00538 (*destination)[vlen - 1] = '\0';
00539 memcpy (*destination, &spos[klen + 2], vlen - 1);
00540 return;
00541 }
00542 }
00543
00556 static int
00557 process_multipart_headers (struct MHD_PostProcessor *pp,
00558 size_t *ioffptr, enum PP_State next_state)
00559 {
00560 char *buf = (char *) &pp[1];
00561 size_t newline;
00562
00563 newline = 0;
00564 while ((newline < pp->buffer_pos) &&
00565 (buf[newline] != '\r') && (buf[newline] != '\n'))
00566 newline++;
00567 if (newline == pp->buffer_size)
00568 {
00569 pp->state = PP_Error;
00570 return MHD_NO;
00571 }
00572 if (newline == pp->buffer_pos)
00573 return MHD_NO;
00574 if (newline == 0)
00575 {
00576
00577 pp->skip_rn = RN_Full;
00578 pp->state = next_state;
00579 return MHD_YES;
00580 }
00581
00582 if (buf[newline] == '\r')
00583 pp->skip_rn = RN_OptN;
00584 buf[newline] = '\0';
00585 if (0 == strncasecmp ("Content-disposition: ",
00586 buf, strlen ("Content-disposition: ")))
00587 {
00588 try_get_value (&buf[strlen ("Content-disposition: ")],
00589 "name", &pp->content_name);
00590 try_get_value (&buf[strlen ("Content-disposition: ")],
00591 "filename", &pp->content_filename);
00592 }
00593 else
00594 {
00595 try_match_header ("Content-type: ", buf, &pp->content_type);
00596 try_match_header ("Content-Transfer-Encoding: ",
00597 buf, &pp->content_transfer_encoding);
00598 }
00599 (*ioffptr) += newline + 1;
00600 return MHD_YES;
00601 }
00602
00617 static int
00618 process_value_to_boundary (struct MHD_PostProcessor *pp,
00619 size_t *ioffptr,
00620 const char *boundary,
00621 size_t blen,
00622 enum PP_State next_state,
00623 enum PP_State next_dash_state)
00624 {
00625 char *buf = (char *) &pp[1];
00626 size_t newline;
00627
00628
00629
00630 newline = 0;
00631 while (1)
00632 {
00633 while ((newline + 4 < pp->buffer_pos) &&
00634 (0 != memcmp ("\r\n--", &buf[newline], 4)))
00635 newline++;
00636 if (newline + pp->blen + 4 <= pp->buffer_pos)
00637 {
00638
00639 if (0 != memcmp (&buf[newline + 4], boundary, pp->blen))
00640 {
00641
00642 newline += 4;
00643 continue;
00644 }
00645 else
00646 {
00647
00648
00649 pp->skip_rn = RN_Dash;
00650 pp->state = next_state;
00651 pp->dash_state = next_dash_state;
00652 (*ioffptr) += pp->blen + 4;
00653 break;
00654 }
00655 }
00656 else
00657 {
00658
00659
00660
00661 if ((newline == 0) && (pp->buffer_pos == pp->buffer_size))
00662 {
00663 pp->state = PP_Error;
00664 return MHD_NO;
00665 }
00666 break;
00667 }
00668 }
00669
00670
00671
00672 if (MHD_NO == pp->ikvi (pp->cls,
00673 MHD_POSTDATA_KIND,
00674 pp->content_name,
00675 pp->content_filename,
00676 pp->content_type,
00677 pp->content_transfer_encoding,
00678 buf, pp->value_offset, newline))
00679 {
00680 pp->state = PP_Error;
00681 return MHD_NO;
00682 }
00683 pp->value_offset += newline;
00684 (*ioffptr) += newline;
00685 return MHD_YES;
00686 }
00687
00688 static void
00689 free_unmarked (struct MHD_PostProcessor *pp)
00690 {
00691 if ((pp->content_name != NULL) && (0 == (pp->have & NE_content_name)))
00692 {
00693 free (pp->content_name);
00694 pp->content_name = NULL;
00695 }
00696 if ((pp->content_type != NULL) && (0 == (pp->have & NE_content_type)))
00697 {
00698 free (pp->content_type);
00699 pp->content_type = NULL;
00700 }
00701 if ((pp->content_filename != NULL) &&
00702 (0 == (pp->have & NE_content_filename)))
00703 {
00704 free (pp->content_filename);
00705 pp->content_filename = NULL;
00706 }
00707 if ((pp->content_transfer_encoding != NULL) &&
00708 (0 == (pp->have & NE_content_transfer_encoding)))
00709 {
00710 free (pp->content_transfer_encoding);
00711 pp->content_transfer_encoding = NULL;
00712 }
00713 }
00714
00718 static int
00719 post_process_multipart (struct MHD_PostProcessor *pp,
00720 const char *post_data,
00721 size_t post_data_len)
00722 {
00723 char *buf;
00724 size_t max;
00725 size_t ioff;
00726 size_t poff;
00727 int state_changed;
00728
00729 buf = (char *) &pp[1];
00730 ioff = 0;
00731 poff = 0;
00732 state_changed = 1;
00733 while ((poff < post_data_len) ||
00734 ((pp->buffer_pos > 0) && (state_changed != 0)))
00735 {
00736
00737
00738 max = pp->buffer_size - pp->buffer_pos;
00739 if (max > post_data_len - poff)
00740 max = post_data_len - poff;
00741 memcpy (&buf[pp->buffer_pos], &post_data[poff], max);
00742 poff += max;
00743 pp->buffer_pos += max;
00744 if ((max == 0) && (state_changed == 0) && (poff < post_data_len))
00745 {
00746 pp->state = PP_Error;
00747 return MHD_NO;
00748 }
00749 state_changed = 0;
00750
00751
00752 switch (pp->skip_rn)
00753 {
00754 case RN_Inactive:
00755 break;
00756 case RN_OptN:
00757 if (buf[0] == '\n')
00758 {
00759 ioff++;
00760 pp->skip_rn = RN_Inactive;
00761 goto AGAIN;
00762 }
00763
00764 case RN_Dash:
00765 if (buf[0] == '-')
00766 {
00767 ioff++;
00768 pp->skip_rn = RN_Dash2;
00769 goto AGAIN;
00770 }
00771 pp->skip_rn = RN_Full;
00772
00773 case RN_Full:
00774 if (buf[0] == '\r')
00775 {
00776 if ((pp->buffer_pos > 1) && (buf[1] == '\n'))
00777 {
00778 pp->skip_rn = RN_Inactive;
00779 ioff += 2;
00780 }
00781 else
00782 {
00783 pp->skip_rn = RN_OptN;
00784 ioff++;
00785 }
00786 goto AGAIN;
00787 }
00788 if (buf[0] == '\n')
00789 {
00790 ioff++;
00791 pp->skip_rn = RN_Inactive;
00792 goto AGAIN;
00793 }
00794 pp->skip_rn = RN_Inactive;
00795 pp->state = PP_Error;
00796 return MHD_NO;
00797 case RN_Dash2:
00798 if (buf[0] == '-')
00799 {
00800 ioff++;
00801 pp->skip_rn = RN_Full;
00802 pp->state = pp->dash_state;
00803 goto AGAIN;
00804 }
00805 pp->state = PP_Error;
00806 break;
00807 }
00808
00809
00810 switch (pp->state)
00811 {
00812 case PP_Error:
00813 return MHD_NO;
00814 case PP_Done:
00815
00816 pp->state = PP_Error;
00817 return MHD_NO;
00818 case PP_Init:
00819 if (MHD_NO == find_boundary (pp,
00820 pp->boundary,
00821 pp->blen,
00822 &ioff,
00823 PP_ProcessEntryHeaders, PP_Done))
00824 {
00825 if (pp->state == PP_Error)
00826 return MHD_NO;
00827 goto END;
00828 }
00829 break;
00830 case PP_ProcessEntryHeaders:
00831 if (MHD_NO ==
00832 process_multipart_headers (pp, &ioff, PP_PerformCheckMultipart))
00833 {
00834 if (pp->state == PP_Error)
00835 return MHD_NO;
00836 else
00837 goto END;
00838 }
00839 state_changed = 1;
00840 break;
00841 case PP_PerformCheckMultipart:
00842 if ((pp->content_type != NULL) &&
00843 (0 == strncasecmp (pp->content_type,
00844 "multipart/mixed",
00845 strlen ("multipart/mixed"))))
00846 {
00847 pp->nested_boundary = strstr (pp->content_type, "boundary=");
00848 if (pp->nested_boundary == NULL)
00849 {
00850 pp->state = PP_Error;
00851 return MHD_NO;
00852 }
00853 pp->nested_boundary =
00854 strdup (&pp->nested_boundary[strlen ("boundary=")]);
00855 if (pp->nested_boundary == NULL)
00856 {
00857
00858 pp->state = PP_Error;
00859 return MHD_NO;
00860 }
00861
00862
00863 free (pp->content_type);
00864 pp->content_type = NULL;
00865 pp->nlen = strlen (pp->nested_boundary);
00866 pp->state = PP_Nested_Init;
00867 state_changed = 1;
00868 break;
00869 }
00870 pp->state = PP_ProcessValueToBoundary;
00871 pp->value_offset = 0;
00872 state_changed = 1;
00873 break;
00874 case PP_ProcessValueToBoundary:
00875 if (MHD_NO == process_value_to_boundary (pp,
00876 &ioff,
00877 pp->boundary,
00878 pp->blen,
00879 PP_PerformCleanup,
00880 PP_Done))
00881 {
00882 if (pp->state == PP_Error)
00883 return MHD_NO;
00884 break;
00885 }
00886 break;
00887 case PP_PerformCleanup:
00888
00889 pp->have = NE_none;
00890 free_unmarked (pp);
00891 if (pp->nested_boundary != NULL)
00892 {
00893 free (pp->nested_boundary);
00894 pp->nested_boundary = NULL;
00895 }
00896 pp->state = PP_ProcessEntryHeaders;
00897 state_changed = 1;
00898 break;
00899 case PP_Nested_Init:
00900 if (pp->nested_boundary == NULL)
00901 {
00902 pp->state = PP_Error;
00903 return MHD_NO;
00904 }
00905 if (MHD_NO == find_boundary (pp,
00906 pp->nested_boundary,
00907 pp->nlen,
00908 &ioff,
00909 PP_Nested_PerformMarking,
00910 PP_Init ))
00911 {
00912 if (pp->state == PP_Error)
00913 return MHD_NO;
00914 goto END;
00915 }
00916 break;
00917 case PP_Nested_PerformMarking:
00918
00919
00920 pp->have = NE_none;
00921 if (pp->content_name != NULL)
00922 pp->have |= NE_content_name;
00923 if (pp->content_type != NULL)
00924 pp->have |= NE_content_type;
00925 if (pp->content_filename != NULL)
00926 pp->have |= NE_content_filename;
00927 if (pp->content_transfer_encoding != NULL)
00928 pp->have |= NE_content_transfer_encoding;
00929 pp->state = PP_Nested_ProcessEntryHeaders;
00930 state_changed = 1;
00931 break;
00932 case PP_Nested_ProcessEntryHeaders:
00933 pp->value_offset = 0;
00934 if (MHD_NO ==
00935 process_multipart_headers (pp, &ioff,
00936 PP_Nested_ProcessValueToBoundary))
00937 {
00938 if (pp->state == PP_Error)
00939 return MHD_NO;
00940 else
00941 goto END;
00942 }
00943 state_changed = 1;
00944 break;
00945 case PP_Nested_ProcessValueToBoundary:
00946 if (MHD_NO == process_value_to_boundary (pp,
00947 &ioff,
00948 pp->nested_boundary,
00949 pp->nlen,
00950 PP_Nested_PerformCleanup,
00951 PP_Init))
00952 {
00953 if (pp->state == PP_Error)
00954 return MHD_NO;
00955 break;
00956 }
00957 break;
00958 case PP_Nested_PerformCleanup:
00959 free_unmarked (pp);
00960 pp->state = PP_Nested_ProcessEntryHeaders;
00961 state_changed = 1;
00962 break;
00963 default:
00964 mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL);
00965 }
00966 AGAIN:
00967 if (ioff > 0)
00968 {
00969 memmove (buf, &buf[ioff], pp->buffer_pos - ioff);
00970 pp->buffer_pos -= ioff;
00971 ioff = 0;
00972 state_changed = 1;
00973 }
00974 }
00975 END:
00976 if (ioff != 0)
00977 {
00978 memmove (buf, &buf[ioff], pp->buffer_pos - ioff);
00979 pp->buffer_pos -= ioff;
00980 }
00981 if (poff < post_data_len)
00982 {
00983 pp->state = PP_Error;
00984 return MHD_NO;
00985 }
00986 return MHD_YES;
00987 }
00988
01003 int
01004 MHD_post_process (struct MHD_PostProcessor *pp,
01005 const char *post_data, size_t post_data_len)
01006 {
01007 if (post_data_len == 0)
01008 return MHD_YES;
01009 if (pp == NULL)
01010 return MHD_NO;
01011 if (0 == strncasecmp (MHD_HTTP_POST_ENCODING_FORM_URLENCODED, pp->encoding,
01012 strlen(MHD_HTTP_POST_ENCODING_FORM_URLENCODED)))
01013 return post_process_urlencoded (pp, post_data, post_data_len);
01014 if (0 ==
01015 strncasecmp (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, pp->encoding,
01016 strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)))
01017 return post_process_multipart (pp, post_data, post_data_len);
01018
01019 return MHD_NO;
01020 }
01021
01025 int
01026 MHD_destroy_post_processor (struct MHD_PostProcessor *pp)
01027 {
01028 int ret;
01029
01030
01031
01032
01033 if ((pp->xbuf_pos > 0) || (pp->state != PP_Done))
01034 ret = MHD_NO;
01035 else
01036 ret = MHD_YES;
01037 pp->have = NE_none;
01038 free_unmarked (pp);
01039 if (pp->nested_boundary != NULL)
01040 free (pp->nested_boundary);
01041 free (pp);
01042 return ret;
01043 }
01044
01045