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 if (NULL != strstr (boundary, "boundary="))
00277 boundary = strstr (boundary, "boundary=") + strlen ("boundary=");
00278 else
00279 return NULL;
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 (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 (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 case RN_Dash:
00764 if (buf[0] == '-')
00765 {
00766 ioff++;
00767 pp->skip_rn = RN_Dash2;
00768 goto AGAIN;
00769 }
00770 pp->skip_rn = RN_Full;
00771
00772 case RN_Full:
00773 if (buf[0] == '\r')
00774 {
00775 if ((pp->buffer_pos > 1) && (buf[1] == '\n'))
00776 {
00777 pp->skip_rn = RN_Inactive;
00778 ioff += 2;
00779 }
00780 else
00781 {
00782 pp->skip_rn = RN_OptN;
00783 ioff++;
00784 }
00785 goto AGAIN;
00786 }
00787 if (buf[0] == '\n')
00788 {
00789 ioff++;
00790 pp->skip_rn = RN_Inactive;
00791 goto AGAIN;
00792 }
00793 pp->skip_rn = RN_Inactive;
00794 pp->state = PP_Error;
00795 return MHD_NO;
00796 case RN_Dash2:
00797 if (buf[0] == '-')
00798 {
00799 ioff++;
00800 pp->skip_rn = RN_Full;
00801 pp->state = pp->dash_state;
00802 goto AGAIN;
00803 }
00804 pp->state = PP_Error;
00805 break;
00806 }
00807
00808
00809 switch (pp->state)
00810 {
00811 case PP_Error:
00812 return MHD_NO;
00813 case PP_Done:
00814
00815 pp->state = PP_Error;
00816 return MHD_NO;
00817 case PP_Init:
00818 if (MHD_NO == find_boundary (pp,
00819 pp->boundary,
00820 pp->blen,
00821 &ioff,
00822 PP_ProcessEntryHeaders, PP_Done))
00823 {
00824 if (pp->state == PP_Error)
00825 return MHD_NO;
00826 goto END;
00827 }
00828 break;
00829 case PP_ProcessEntryHeaders:
00830 if (MHD_NO ==
00831 process_multipart_headers (pp, &ioff, PP_PerformCheckMultipart))
00832 {
00833 if (pp->state == PP_Error)
00834 return MHD_NO;
00835 else
00836 goto END;
00837 }
00838 state_changed = 1;
00839 break;
00840 case PP_PerformCheckMultipart:
00841 if ((pp->content_type != NULL) &&
00842 (0 == strncasecmp (pp->content_type,
00843 "multipart/mixed",
00844 strlen ("multipart/mixed"))))
00845 {
00846 pp->nested_boundary = strstr (pp->content_type, "boundary=");
00847 if (pp->nested_boundary == NULL)
00848 {
00849 pp->state = PP_Error;
00850 return MHD_NO;
00851 }
00852 pp->nested_boundary =
00853 strdup (&pp->nested_boundary[strlen ("boundary=")]);
00854 if (pp->nested_boundary == NULL)
00855 {
00856
00857 pp->state = PP_Error;
00858 return MHD_NO;
00859 }
00860
00861
00862 free (pp->content_type);
00863 pp->content_type = NULL;
00864 pp->nlen = strlen (pp->nested_boundary);
00865 pp->state = PP_Nested_Init;
00866 state_changed = 1;
00867 break;
00868 }
00869 pp->state = PP_ProcessValueToBoundary;
00870 pp->value_offset = 0;
00871 state_changed = 1;
00872 break;
00873 case PP_ProcessValueToBoundary:
00874 if (MHD_NO == process_value_to_boundary (pp,
00875 &ioff,
00876 pp->boundary,
00877 pp->blen,
00878 PP_PerformCleanup,
00879 PP_Done))
00880 {
00881 if (pp->state == PP_Error)
00882 return MHD_NO;
00883 break;
00884 }
00885 break;
00886 case PP_PerformCleanup:
00887
00888 pp->have = NE_none;
00889 free_unmarked (pp);
00890 if (pp->nested_boundary != NULL)
00891 {
00892 free (pp->nested_boundary);
00893 pp->nested_boundary = NULL;
00894 }
00895 pp->state = PP_ProcessEntryHeaders;
00896 state_changed = 1;
00897 break;
00898 case PP_Nested_Init:
00899 if (pp->nested_boundary == NULL)
00900 {
00901 pp->state = PP_Error;
00902 return MHD_NO;
00903 }
00904 if (MHD_NO == find_boundary (pp,
00905 pp->nested_boundary,
00906 pp->nlen,
00907 &ioff,
00908 PP_Nested_PerformMarking,
00909 PP_Init ))
00910 {
00911 if (pp->state == PP_Error)
00912 return MHD_NO;
00913 goto END;
00914 }
00915 break;
00916 case PP_Nested_PerformMarking:
00917
00918
00919 pp->have = NE_none;
00920 if (pp->content_name != NULL)
00921 pp->have |= NE_content_name;
00922 if (pp->content_type != NULL)
00923 pp->have |= NE_content_type;
00924 if (pp->content_filename != NULL)
00925 pp->have |= NE_content_filename;
00926 if (pp->content_transfer_encoding != NULL)
00927 pp->have |= NE_content_transfer_encoding;
00928 pp->state = PP_Nested_ProcessEntryHeaders;
00929 state_changed = 1;
00930 break;
00931 case PP_Nested_ProcessEntryHeaders:
00932 pp->value_offset = 0;
00933 if (MHD_NO ==
00934 process_multipart_headers (pp, &ioff,
00935 PP_Nested_ProcessValueToBoundary))
00936 {
00937 if (pp->state == PP_Error)
00938 return MHD_NO;
00939 else
00940 goto END;
00941 }
00942 state_changed = 1;
00943 break;
00944 case PP_Nested_ProcessValueToBoundary:
00945 if (MHD_NO == process_value_to_boundary (pp,
00946 &ioff,
00947 pp->nested_boundary,
00948 pp->nlen,
00949 PP_Nested_PerformCleanup,
00950 PP_Init))
00951 {
00952 if (pp->state == PP_Error)
00953 return MHD_NO;
00954 break;
00955 }
00956 break;
00957 case PP_Nested_PerformCleanup:
00958 free_unmarked (pp);
00959 pp->state = PP_Nested_ProcessEntryHeaders;
00960 state_changed = 1;
00961 break;
00962 default:
00963 mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL);
00964 }
00965 AGAIN:
00966 if (ioff > 0)
00967 {
00968 memmove (buf, &buf[ioff], pp->buffer_pos - ioff);
00969 pp->buffer_pos -= ioff;
00970 ioff = 0;
00971 state_changed = 1;
00972 }
00973 }
00974 END:
00975 if (ioff != 0)
00976 {
00977 memmove (buf, &buf[ioff], pp->buffer_pos - ioff);
00978 pp->buffer_pos -= ioff;
00979 }
00980 if (poff < post_data_len)
00981 {
00982 pp->state = PP_Error;
00983 return MHD_NO;
00984 }
00985 return MHD_YES;
00986 }
00987
01002 int
01003 MHD_post_process (struct MHD_PostProcessor *pp,
01004 const char *post_data, size_t post_data_len)
01005 {
01006 if (post_data_len == 0)
01007 return MHD_YES;
01008 if (pp == NULL)
01009 return MHD_NO;
01010 if (0 == strncasecmp (MHD_HTTP_POST_ENCODING_FORM_URLENCODED, pp->encoding,
01011 strlen(MHD_HTTP_POST_ENCODING_FORM_URLENCODED)))
01012 return post_process_urlencoded (pp, post_data, post_data_len);
01013 if (0 ==
01014 strncasecmp (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, pp->encoding,
01015 strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)))
01016 return post_process_multipart (pp, post_data, post_data_len);
01017
01018 return MHD_NO;
01019 }
01020
01024 int
01025 MHD_destroy_post_processor (struct MHD_PostProcessor *pp)
01026 {
01027 int ret;
01028
01029
01030
01031
01032 if ((pp->xbuf_pos > 0) || (pp->state != PP_Done))
01033 ret = MHD_NO;
01034 else
01035 ret = MHD_YES;
01036 pp->have = NE_none;
01037 free_unmarked (pp);
01038 if (pp->nested_boundary != NULL)
01039 free (pp->nested_boundary);
01040 free (pp);
01041 return ret;
01042 }
01043
01044