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

Generated on 12 Sep 2013 for GNU libmicrohttpd by  doxygen 1.6.1