postprocessor.c

Go to the documentation of this file.
00001 /*
00002      This file is part of libmicrohttpd
00003      (C) 2007, 2009, 2010, 2011, 2012 Daniel Pittman and Christian Grothoff
00004 
00005      This library is free software; you can redistribute it and/or
00006      modify it under the terms of the GNU Lesser General Public
00007      License as published by the Free Software Foundation; either
00008      version 2.1 of the License, or (at your option) any later version.
00009 
00010      This library is distributed in the hope that it will be useful,
00011      but WITHOUT ANY WARRANTY; without even the implied warranty of
00012      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013      Lesser General Public License for more details.
00014 
00015      You should have received a copy of the GNU Lesser General Public
00016      License along with this library; if not, write to the Free Software
00017      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00018 */
00019 
00026 #include "internal.h"
00027 
00033 #define XBUF_SIZE 512
00034 
00038 enum PP_State
00039 {
00040   /* general states */
00041   PP_Error,
00042   PP_Done,
00043   PP_Init,
00044   PP_NextBoundary,
00045 
00046   /* url encoding-states */
00047   PP_ProcessValue,
00048   PP_ExpectNewLine,
00049 
00050   /* post encoding-states  */
00051   PP_ProcessEntryHeaders,
00052   PP_PerformCheckMultipart,
00053   PP_ProcessValueToBoundary,
00054   PP_PerformCleanup,
00055 
00056   /* nested post-encoding states */
00057   PP_Nested_Init,
00058   PP_Nested_PerformMarking,
00059   PP_Nested_ProcessEntryHeaders,
00060   PP_Nested_ProcessValueToBoundary,
00061   PP_Nested_PerformCleanup,
00062 
00063 };
00064 
00065 enum RN_State
00066 {
00070   RN_Inactive = 0,
00071 
00076   RN_OptN = 1,
00077 
00082   RN_Full = 2,
00083 
00088   RN_Dash = 3,
00089 
00093   RN_Dash2 = 4,
00094 };
00095 
00101 enum NE_State
00102 {
00103   NE_none = 0,
00104   NE_content_name = 1,
00105   NE_content_type = 2,
00106   NE_content_filename = 4,
00107   NE_content_transfer_encoding = 8,
00108 };
00109 
00114 struct MHD_PostProcessor
00115 {
00116 
00121   struct MHD_Connection *connection;
00122 
00126   MHD_PostDataIterator ikvi;
00127 
00131   void *cls;
00132 
00137   const char *encoding;
00138 
00142   const char *boundary;
00143 
00147   char *nested_boundary;
00148 
00152   char *content_name;
00153 
00157   char *content_type;
00158 
00162   char *content_filename;
00163 
00167   char *content_transfer_encoding;
00168 
00173   char xbuf[8];
00174 
00178   size_t buffer_size;
00179 
00183   size_t buffer_pos;
00184 
00188   size_t xbuf_pos;
00189 
00193   uint64_t value_offset;
00194 
00198   size_t blen;
00199 
00203   size_t nlen;
00204 
00208   enum PP_State state;
00209 
00216   enum RN_State skip_rn;
00217 
00222   enum PP_State dash_state;
00223 
00228   enum NE_State have;
00229 
00230 };
00231 
00232 
00251 struct MHD_PostProcessor *
00252 MHD_create_post_processor (struct MHD_Connection *connection,
00253                            size_t buffer_size,
00254                            MHD_PostDataIterator ikvi, void *cls)
00255 {
00256   struct MHD_PostProcessor *ret;
00257   const char *encoding;
00258   const char *boundary;
00259   size_t blen;
00260 
00261   if ((buffer_size < 256) || (connection == NULL) || (ikvi == NULL))
00262     mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL);
00263   encoding = MHD_lookup_connection_value (connection,
00264                                           MHD_HEADER_KIND,
00265                                           MHD_HTTP_HEADER_CONTENT_TYPE);
00266   if (encoding == NULL)
00267     return NULL;
00268   boundary = NULL;
00269   if (0 != strncasecmp (MHD_HTTP_POST_ENCODING_FORM_URLENCODED, encoding,
00270                         strlen (MHD_HTTP_POST_ENCODING_FORM_URLENCODED)))
00271     {
00272       if (0 !=
00273           strncasecmp (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, encoding,
00274                        strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)))
00275         return NULL;
00276       boundary =
00277         &encoding[strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)];
00278       /* Q: should this be "strcasestr"? */
00279       boundary = strstr (boundary, "boundary=");
00280       if (NULL == boundary)
00281         return NULL; /* failed to determine boundary */
00282       boundary += strlen ("boundary=");
00283       blen = strlen (boundary);
00284       if ((blen == 0) || (blen * 2 + 2 > buffer_size))
00285         return NULL;            /* (will be) out of memory or invalid boundary */
00286       if ( (boundary[0] == '"') && (boundary[blen - 1] == '"') )
00287         {
00288           /* remove enclosing quotes */
00289           ++boundary;
00290           blen -= 2;
00291         } 
00292     }
00293   else
00294     blen = 0;
00295   ret = malloc (sizeof (struct MHD_PostProcessor) + buffer_size + 1);
00296   if (ret == NULL)
00297     return NULL;
00298   memset (ret, 0, sizeof (struct MHD_PostProcessor) + buffer_size + 1);
00299   ret->connection = connection;
00300   ret->ikvi = ikvi;
00301   ret->cls = cls;
00302   ret->encoding = encoding;
00303   ret->buffer_size = buffer_size;
00304   ret->state = PP_Init;
00305   ret->blen = blen;
00306   ret->boundary = boundary;
00307   ret->skip_rn = RN_Inactive;
00308   return ret;
00309 }
00310 
00314 static int
00315 post_process_urlencoded (struct MHD_PostProcessor *pp,
00316                          const char *post_data,
00317                          size_t post_data_len)
00318 {
00319   size_t equals;
00320   size_t amper;
00321   size_t poff;
00322   size_t xoff;
00323   size_t delta;
00324   int end_of_value_found;
00325   char *buf;
00326   char xbuf[XBUF_SIZE + 1];
00327 
00328   buf = (char *) &pp[1];
00329   poff = 0;
00330   while (poff < post_data_len)
00331     {
00332       switch (pp->state)
00333         {
00334         case PP_Error:
00335           return MHD_NO;
00336         case PP_Done:
00337           /* did not expect to receive more data */
00338           pp->state = PP_Error;
00339           return MHD_NO;
00340         case PP_Init:
00341           equals = 0;
00342           while ((equals + poff < post_data_len) &&
00343                  (post_data[equals + poff] != '='))
00344             equals++;
00345           if (equals + pp->buffer_pos > pp->buffer_size)
00346             {
00347               pp->state = PP_Error;     /* out of memory */
00348               return MHD_NO;
00349             }
00350           memcpy (&buf[pp->buffer_pos], &post_data[poff], equals);
00351           pp->buffer_pos += equals;
00352           if (equals + poff == post_data_len)
00353             return MHD_YES;     /* no '=' yet */
00354           buf[pp->buffer_pos] = '\0';   /* 0-terminate key */
00355           pp->buffer_pos = 0;   /* reset for next key */
00356           MHD_http_unescape (NULL, NULL, buf);
00357           poff += equals + 1;
00358           pp->state = PP_ProcessValue;
00359           pp->value_offset = 0;
00360           break;
00361         case PP_ProcessValue:
00362           /* obtain rest of value from previous iteration */
00363           memcpy (xbuf, pp->xbuf, pp->xbuf_pos);
00364           xoff = pp->xbuf_pos;
00365           pp->xbuf_pos = 0;
00366 
00367           /* find last position in input buffer that is part of the value */
00368           amper = 0;
00369           while ((amper + poff < post_data_len) &&
00370                  (amper < XBUF_SIZE) &&
00371                  (post_data[amper + poff] != '&') &&
00372                  (post_data[amper + poff] != '\n') &&
00373                  (post_data[amper + poff] != '\r'))
00374             amper++;
00375           end_of_value_found = ((amper + poff < post_data_len) &&
00376                                 ((post_data[amper + poff] == '&') ||
00377                                  (post_data[amper + poff] == '\n') ||
00378                                  (post_data[amper + poff] == '\r')));
00379           /* compute delta, the maximum number of bytes that we will be able to
00380              process right now (either amper-limited of xbuf-size limited) */
00381           delta = amper;
00382           if (delta > XBUF_SIZE - xoff)
00383             delta = XBUF_SIZE - xoff;
00384 
00385           /* move input into processing buffer */
00386           memcpy (&xbuf[xoff], &post_data[poff], delta);
00387           xoff += delta;
00388           poff += delta;
00389 
00390           /* find if escape sequence is at the end of the processing buffer;
00391              if so, exclude those from processing (reduce delta to point at
00392              end of processed region) */
00393           delta = xoff;
00394           if ((delta > 0) && (xbuf[delta - 1] == '%'))
00395             delta--;
00396           else if ((delta > 1) && (xbuf[delta - 2] == '%'))
00397             delta -= 2;
00398 
00399           /* if we have an incomplete escape sequence, save it to
00400              pp->xbuf for later */
00401           if (delta < xoff)
00402             {
00403               memcpy (pp->xbuf, &xbuf[delta], xoff - delta);
00404               pp->xbuf_pos = xoff - delta;
00405               xoff = delta;
00406             }
00407 
00408           /* If we have nothing to do (delta == 0) and
00409              not just because the value is empty (are
00410              waiting for more data), go for next iteration */
00411           if ((xoff == 0) && (poff == post_data_len))
00412             continue;
00413 
00414           /* unescape */
00415           xbuf[xoff] = '\0';    /* 0-terminate in preparation */
00416           xoff = MHD_http_unescape (NULL, NULL, xbuf);
00417           /* finally: call application! */
00418           if (MHD_NO == pp->ikvi (pp->cls, MHD_POSTDATA_KIND, (const char *) &pp[1],    /* key */
00419                                   NULL, NULL, NULL, xbuf, pp->value_offset,
00420                                   xoff))
00421             {
00422               pp->state = PP_Error;
00423               return MHD_NO;
00424             }
00425           pp->value_offset += xoff;
00426 
00427           /* are we done with the value? */
00428           if (end_of_value_found)
00429             {
00430               /* we found the end of the value! */
00431               if ((post_data[poff] == '\n') || (post_data[poff] == '\r'))
00432                 {
00433                   pp->state = PP_ExpectNewLine;
00434                 }
00435               else
00436                 {
00437                   poff++;       /* skip '&' */
00438                   pp->state = PP_Init;
00439                 }
00440             }
00441           break;
00442         case PP_ExpectNewLine:
00443           if ((post_data[poff] == '\n') || (post_data[poff] == '\r'))
00444             {
00445               poff++;
00446               /* we are done, report error if we receive any more... */
00447               pp->state = PP_Done;
00448               return MHD_YES;
00449             }
00450           return MHD_NO;
00451         default:
00452           mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL);          /* should never happen! */
00453         }
00454     }
00455   return MHD_YES;
00456 }
00457 
00464 static int
00465 try_match_header (const char *prefix, char *line, char **suffix)
00466 {
00467   if (NULL != *suffix)
00468     return MHD_NO;
00469   while (*line != 0)
00470     {
00471       if (0 == strncasecmp (prefix, line, strlen (prefix)))
00472         {
00473           *suffix = strdup (&line[strlen (prefix)]);
00474           return MHD_YES;
00475         }
00476       ++line;
00477     }
00478   return MHD_NO;
00479 }
00480 
00481 static int
00482 find_boundary (struct MHD_PostProcessor *pp,
00483                const char *boundary,
00484                size_t blen,
00485                size_t *ioffptr,
00486                enum PP_State next_state, enum PP_State next_dash_state)
00487 {
00488   char *buf = (char *) &pp[1];
00489 
00490   if (pp->buffer_pos < 2 + blen)
00491     {
00492       if (pp->buffer_pos == pp->buffer_size)
00493         pp->state = PP_Error;   /* out of memory */
00494       return MHD_NO;            /* not enough data */
00495     }
00496   if ((0 != memcmp ("--", buf, 2)) || (0 != memcmp (&buf[2], boundary, blen)))
00497     {
00498       if (pp->state != PP_Init)
00499         pp->state = PP_Error;
00500       return MHD_NO;            /* expected boundary */
00501     }
00502   /* remove boundary from buffer */
00503   (*ioffptr) += 2 + blen;
00504   /* next: start with headers */
00505   pp->skip_rn = RN_Dash;
00506   pp->state = next_state;
00507   pp->dash_state = next_dash_state;
00508   return MHD_YES;
00509 }
00510 
00519 static void
00520 try_get_value (const char *buf, const char *key, char **destination)
00521 {
00522   const char *spos;
00523   const char *bpos;
00524   const char *endv;
00525   size_t klen;
00526   size_t vlen;
00527 
00528   if (NULL != *destination)
00529     return;
00530   bpos = buf;
00531   klen = strlen (key);
00532   while (NULL != (spos = strstr (bpos, key)))
00533     {
00534       if ((spos[klen] != '=') || ((spos != buf) && (spos[-1] != ' ')))
00535         {
00536           /* no match */
00537           bpos = spos + 1;
00538           continue;
00539         }
00540       if (spos[klen + 1] != '"')
00541         return;                 /* not quoted */
00542       if (NULL == (endv = strchr (&spos[klen + 2], '\"')))
00543         return;                 /* no end-quote */
00544       vlen = endv - spos - klen - 1;
00545       *destination = malloc (vlen);
00546       if (NULL == *destination)
00547         return;                 /* out of memory */
00548       (*destination)[vlen - 1] = '\0';
00549       memcpy (*destination, &spos[klen + 2], vlen - 1);
00550       return;                   /* success */
00551     }
00552 }
00553 
00566 static int
00567 process_multipart_headers (struct MHD_PostProcessor *pp,
00568                            size_t *ioffptr, enum PP_State next_state)
00569 {
00570   char *buf = (char *) &pp[1];
00571   size_t newline;
00572 
00573   newline = 0;
00574   while ((newline < pp->buffer_pos) &&
00575          (buf[newline] != '\r') && (buf[newline] != '\n'))
00576     newline++;
00577   if (newline == pp->buffer_size)
00578     {
00579       pp->state = PP_Error;
00580       return MHD_NO;            /* out of memory */
00581     }
00582   if (newline == pp->buffer_pos)
00583     return MHD_NO;              /* will need more data */
00584   if (newline == 0)
00585     {
00586       /* empty line - end of headers */
00587       pp->skip_rn = RN_Full;
00588       pp->state = next_state;
00589       return MHD_YES;
00590     }
00591   /* got an actual header */
00592   if (buf[newline] == '\r')
00593     pp->skip_rn = RN_OptN;
00594   buf[newline] = '\0';
00595   if (0 == strncasecmp ("Content-disposition: ",
00596                         buf, strlen ("Content-disposition: ")))
00597     {
00598       try_get_value (&buf[strlen ("Content-disposition: ")],
00599                      "name", &pp->content_name);
00600       try_get_value (&buf[strlen ("Content-disposition: ")],
00601                      "filename", &pp->content_filename);
00602     }
00603   else
00604     {
00605       try_match_header ("Content-type: ", buf, &pp->content_type);
00606       try_match_header ("Content-Transfer-Encoding: ",
00607                         buf, &pp->content_transfer_encoding);
00608     }
00609   (*ioffptr) += newline + 1;
00610   return MHD_YES;
00611 }
00612 
00627 static int
00628 process_value_to_boundary (struct MHD_PostProcessor *pp,
00629                            size_t *ioffptr,
00630                            const char *boundary,
00631                            size_t blen,
00632                            enum PP_State next_state,
00633                            enum PP_State next_dash_state)
00634 {
00635   char *buf = (char *) &pp[1];
00636   size_t newline;
00637 
00638   /* all data in buf until the boundary
00639      (\r\n--+boundary) is part of the value */
00640   newline = 0;
00641   while (1)
00642     {
00643       while ((newline + 4 < pp->buffer_pos) &&
00644              (0 != memcmp ("\r\n--", &buf[newline], 4)))
00645         newline++;
00646       if (newline + pp->blen + 4 <= pp->buffer_pos)
00647         {
00648           /* can check boundary */
00649           if (0 != memcmp (&buf[newline + 4], boundary, pp->blen))
00650             {
00651               /* no boundary, "\r\n--" is part of content, skip */
00652               newline += 4;
00653               continue;
00654             }
00655           else
00656             {
00657               /* boundary found, process until newline then
00658                  skip boundary and go back to init */
00659               pp->skip_rn = RN_Dash;
00660               pp->state = next_state;
00661               pp->dash_state = next_dash_state;
00662               (*ioffptr) += pp->blen + 4;       /* skip boundary as well */
00663               buf[newline] = '\0';
00664               break;
00665             }
00666         }
00667       else
00668         {
00669           /* cannot check for boundary, process content that
00670              we have and check again later; except, if we have
00671              no content, abort (out of memory) */
00672           if ((newline == 0) && (pp->buffer_pos == pp->buffer_size))
00673             {
00674               pp->state = PP_Error;
00675               return MHD_NO;
00676             }
00677           break;
00678         }
00679     }
00680   /* newline is either at beginning of boundary or
00681      at least at the last character that we are sure
00682      is not part of the boundary */
00683   if (MHD_NO == pp->ikvi (pp->cls,
00684                           MHD_POSTDATA_KIND,
00685                           pp->content_name,
00686                           pp->content_filename,
00687                           pp->content_type,
00688                           pp->content_transfer_encoding,
00689                           buf, pp->value_offset, newline))
00690     {
00691       pp->state = PP_Error;
00692       return MHD_NO;
00693     }
00694   pp->value_offset += newline;
00695   (*ioffptr) += newline;
00696   return MHD_YES;
00697 }
00698 
00699 static void
00700 free_unmarked (struct MHD_PostProcessor *pp)
00701 {
00702   if ((pp->content_name != NULL) && (0 == (pp->have & NE_content_name)))
00703     {
00704       free (pp->content_name);
00705       pp->content_name = NULL;
00706     }
00707   if ((pp->content_type != NULL) && (0 == (pp->have & NE_content_type)))
00708     {
00709       free (pp->content_type);
00710       pp->content_type = NULL;
00711     }
00712   if ((pp->content_filename != NULL) &&
00713       (0 == (pp->have & NE_content_filename)))
00714     {
00715       free (pp->content_filename);
00716       pp->content_filename = NULL;
00717     }
00718   if ((pp->content_transfer_encoding != NULL) &&
00719       (0 == (pp->have & NE_content_transfer_encoding)))
00720     {
00721       free (pp->content_transfer_encoding);
00722       pp->content_transfer_encoding = NULL;
00723     }
00724 }
00725 
00729 static int
00730 post_process_multipart (struct MHD_PostProcessor *pp,
00731                         const char *post_data,
00732                         size_t post_data_len)
00733 {
00734   char *buf;
00735   size_t max;
00736   size_t ioff;
00737   size_t poff;
00738   int state_changed;
00739 
00740   buf = (char *) &pp[1];
00741   ioff = 0;
00742   poff = 0;
00743   state_changed = 1;
00744   while ((poff < post_data_len) ||
00745          ((pp->buffer_pos > 0) && (state_changed != 0)))
00746     {
00747       /* first, move as much input data
00748          as possible to our internal buffer */
00749       max = pp->buffer_size - pp->buffer_pos;
00750       if (max > post_data_len - poff)
00751         max = post_data_len - poff;
00752       memcpy (&buf[pp->buffer_pos], &post_data[poff], max);
00753       poff += max;
00754       pp->buffer_pos += max;
00755       if ((max == 0) && (state_changed == 0) && (poff < post_data_len))
00756         {
00757           pp->state = PP_Error;
00758           return MHD_NO;        /* out of memory */
00759         }
00760       state_changed = 0;
00761 
00762       /* first state machine for '\r'-'\n' and '--' handling */
00763       switch (pp->skip_rn)
00764         {
00765         case RN_Inactive:
00766           break;
00767         case RN_OptN:
00768           if (buf[0] == '\n')
00769             {
00770               ioff++;
00771               pp->skip_rn = RN_Inactive;
00772               goto AGAIN;
00773             }
00774           /* fall-through! */
00775         case RN_Dash:
00776           if (buf[0] == '-')
00777             {
00778               ioff++;
00779               pp->skip_rn = RN_Dash2;
00780               goto AGAIN;
00781             }
00782           pp->skip_rn = RN_Full;
00783           /* fall-through! */
00784         case RN_Full:
00785           if (buf[0] == '\r')
00786             {
00787               if ((pp->buffer_pos > 1) && (buf[1] == '\n'))
00788                 {
00789                   pp->skip_rn = RN_Inactive;
00790                   ioff += 2;
00791                 }
00792               else
00793                 {
00794                   pp->skip_rn = RN_OptN;
00795                   ioff++;
00796                 }
00797               goto AGAIN;
00798             }
00799           if (buf[0] == '\n')
00800             {
00801               ioff++;
00802               pp->skip_rn = RN_Inactive;
00803               goto AGAIN;
00804             }
00805           pp->skip_rn = RN_Inactive;
00806           pp->state = PP_Error;
00807           return MHD_NO;        /* no '\r\n' */
00808         case RN_Dash2:
00809           if (buf[0] == '-')
00810             {
00811               ioff++;
00812               pp->skip_rn = RN_Full;
00813               pp->state = pp->dash_state;
00814               goto AGAIN;
00815             }
00816           pp->state = PP_Error;
00817           break;
00818         }
00819 
00820       /* main state engine */
00821       switch (pp->state)
00822         {
00823         case PP_Error:
00824           return MHD_NO;
00825         case PP_Done:
00826           /* did not expect to receive more data */
00827           pp->state = PP_Error;
00828           return MHD_NO;
00829         case PP_Init:
00841           if (MHD_NO == find_boundary (pp,
00842                                        pp->boundary,
00843                                        pp->blen,
00844                                        &ioff,
00845                                        PP_ProcessEntryHeaders, PP_Done))
00846             ++ioff;
00847           break;
00848         case PP_NextBoundary:
00849           if (MHD_NO == find_boundary (pp,
00850                                        pp->boundary,
00851                                        pp->blen,
00852                                        &ioff,
00853                                        PP_ProcessEntryHeaders, PP_Done))
00854             {
00855               if (pp->state == PP_Error)
00856                 return MHD_NO;
00857               goto END;
00858             }
00859           break;
00860         case PP_ProcessEntryHeaders:
00861           if (MHD_NO ==
00862               process_multipart_headers (pp, &ioff, PP_PerformCheckMultipart))
00863             {
00864               if (pp->state == PP_Error)
00865                 return MHD_NO;
00866               else
00867                 goto END;
00868             }
00869           state_changed = 1;
00870           break;
00871         case PP_PerformCheckMultipart:
00872           if ((pp->content_type != NULL) &&
00873               (0 == strncasecmp (pp->content_type,
00874                                  "multipart/mixed",
00875                                  strlen ("multipart/mixed"))))
00876             {
00877               pp->nested_boundary = strstr (pp->content_type, "boundary=");
00878               if (pp->nested_boundary == NULL)
00879                 {
00880                   pp->state = PP_Error;
00881                   return MHD_NO;
00882                 }
00883               pp->nested_boundary =
00884                 strdup (&pp->nested_boundary[strlen ("boundary=")]);
00885               if (pp->nested_boundary == NULL)
00886                 {
00887                   /* out of memory */
00888                   pp->state = PP_Error;
00889                   return MHD_NO;
00890                 }
00891               /* free old content type, we will need that field
00892                  for the content type of the nested elements */
00893               free (pp->content_type);
00894               pp->content_type = NULL;
00895               pp->nlen = strlen (pp->nested_boundary);
00896               pp->state = PP_Nested_Init;
00897               state_changed = 1;
00898               break;
00899             }
00900           pp->state = PP_ProcessValueToBoundary;
00901           pp->value_offset = 0;
00902           state_changed = 1;
00903           break;
00904         case PP_ProcessValueToBoundary:
00905           if (MHD_NO == process_value_to_boundary (pp,
00906                                                    &ioff,
00907                                                    pp->boundary,
00908                                                    pp->blen,
00909                                                    PP_PerformCleanup,
00910                                                    PP_Done))
00911             {
00912               if (pp->state == PP_Error)
00913                 return MHD_NO;
00914               break;
00915             }
00916           break;
00917         case PP_PerformCleanup:
00918           /* clean up state of one multipart form-data element! */
00919           pp->have = NE_none;
00920           free_unmarked (pp);
00921           if (pp->nested_boundary != NULL)
00922             {
00923               free (pp->nested_boundary);
00924               pp->nested_boundary = NULL;
00925             }
00926           pp->state = PP_ProcessEntryHeaders;
00927           state_changed = 1;
00928           break;
00929         case PP_Nested_Init:
00930           if (pp->nested_boundary == NULL)
00931             {
00932               pp->state = PP_Error;
00933               return MHD_NO;
00934             }
00935           if (MHD_NO == find_boundary (pp,
00936                                        pp->nested_boundary,
00937                                        pp->nlen,
00938                                        &ioff,
00939                                        PP_Nested_PerformMarking,
00940                                        PP_NextBoundary /* or PP_Error? */ ))
00941             {
00942               if (pp->state == PP_Error)
00943                 return MHD_NO;
00944               goto END;
00945             }
00946           break;
00947         case PP_Nested_PerformMarking:
00948           /* remember what headers were given
00949              globally */
00950           pp->have = NE_none;
00951           if (pp->content_name != NULL)
00952             pp->have |= NE_content_name;
00953           if (pp->content_type != NULL)
00954             pp->have |= NE_content_type;
00955           if (pp->content_filename != NULL)
00956             pp->have |= NE_content_filename;
00957           if (pp->content_transfer_encoding != NULL)
00958             pp->have |= NE_content_transfer_encoding;
00959           pp->state = PP_Nested_ProcessEntryHeaders;
00960           state_changed = 1;
00961           break;
00962         case PP_Nested_ProcessEntryHeaders:
00963           pp->value_offset = 0;
00964           if (MHD_NO ==
00965               process_multipart_headers (pp, &ioff,
00966                                          PP_Nested_ProcessValueToBoundary))
00967             {
00968               if (pp->state == PP_Error)
00969                 return MHD_NO;
00970               else
00971                 goto END;
00972             }
00973           state_changed = 1;
00974           break;
00975         case PP_Nested_ProcessValueToBoundary:
00976           if (MHD_NO == process_value_to_boundary (pp,
00977                                                    &ioff,
00978                                                    pp->nested_boundary,
00979                                                    pp->nlen,
00980                                                    PP_Nested_PerformCleanup,
00981                                                    PP_NextBoundary))
00982             {
00983               if (pp->state == PP_Error)
00984                 return MHD_NO;
00985               break;
00986             }
00987           break;
00988         case PP_Nested_PerformCleanup:
00989           free_unmarked (pp);
00990           pp->state = PP_Nested_ProcessEntryHeaders;
00991           state_changed = 1;
00992           break;
00993         default:
00994           mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL);          /* should never happen! */
00995         }
00996     AGAIN:
00997       if (ioff > 0)
00998         {
00999           memmove (buf, &buf[ioff], pp->buffer_pos - ioff);
01000           pp->buffer_pos -= ioff;
01001           ioff = 0;
01002           state_changed = 1;
01003         }
01004     }
01005 END:
01006   if (ioff != 0)
01007     {
01008       memmove (buf, &buf[ioff], pp->buffer_pos - ioff);
01009       pp->buffer_pos -= ioff;
01010     }
01011   if (poff < post_data_len)
01012     {
01013       pp->state = PP_Error;
01014       return MHD_NO;            /* serious error */
01015     }
01016   return MHD_YES;
01017 }
01018 
01033 int
01034 MHD_post_process (struct MHD_PostProcessor *pp,
01035                   const char *post_data, size_t post_data_len)
01036 {
01037   if (post_data_len == 0)
01038     return MHD_YES;
01039   if (pp == NULL)
01040     return MHD_NO;
01041   if (0 == strncasecmp (MHD_HTTP_POST_ENCODING_FORM_URLENCODED, pp->encoding,
01042                          strlen(MHD_HTTP_POST_ENCODING_FORM_URLENCODED)))
01043     return post_process_urlencoded (pp, post_data, post_data_len);
01044   if (0 ==
01045       strncasecmp (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, pp->encoding,
01046                    strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)))
01047     return post_process_multipart (pp, post_data, post_data_len);
01048   /* this should never be reached */
01049   return MHD_NO;
01050 }
01051 
01055 int
01056 MHD_destroy_post_processor (struct MHD_PostProcessor *pp)
01057 {
01058   int ret;
01059 
01060   if (NULL == pp)
01061     return MHD_YES;
01062   /* These internal strings need cleaning up since
01063      the post-processing may have been interrupted
01064      at any stage */
01065   if ((pp->xbuf_pos > 0) || (pp->state != PP_Done))
01066     ret = MHD_NO;
01067   else
01068     ret = MHD_YES;
01069   pp->have = NE_none;
01070   free_unmarked (pp);
01071   if (pp->nested_boundary != NULL)
01072     free (pp->nested_boundary);
01073   free (pp);
01074   return ret;
01075 }
01076 
01077 /* end of postprocessor.c */

Generated on 27 Sep 2012 for GNU libmicrohttpd by  doxygen 1.6.1