postprocessor.c

Go to the documentation of this file.
00001 /*
00002      This file is part of libmicrohttpd
00003      (C) 2007, 2009 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 
00043   /* url encoding-states */
00044   PP_ProcessValue,
00045   PP_ExpectNewLine,
00046 
00047   /* post encoding-states  */
00048   PP_ProcessEntryHeaders,
00049   PP_PerformCheckMultipart,
00050   PP_ProcessValueToBoundary,
00051   PP_PerformCleanup,
00052 
00053   /* nested post-encoding states */
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       /* Q: should this be "strcasestr"? */
00276       boundary = strstr (boundary, "boundary=");
00277       if (NULL == boundary)
00278         return NULL; /* failed to determine boundary */
00279       boundary += strlen ("boundary=");
00280       blen = strlen (boundary);
00281       if ((blen == 0) || (blen * 2 + 2 > buffer_size))
00282         return NULL;            /* (will be) out of memory or invalid boundary */
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           /* did not expect to receive more data */
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;     /* out of memory */
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;     /* no '=' yet */
00345           buf[pp->buffer_pos] = '\0';   /* 0-terminate key */
00346           pp->buffer_pos = 0;   /* reset for next key */
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           /* obtain rest of value from previous iteration */
00354           memcpy (xbuf, pp->xbuf, pp->xbuf_pos);
00355           xoff = pp->xbuf_pos;
00356           pp->xbuf_pos = 0;
00357 
00358           /* find last position in input buffer that is part of the value */
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           /* compute delta, the maximum number of bytes that we will be able to
00371              process right now (either amper-limited of xbuf-size limited) */
00372           delta = amper;
00373           if (delta > XBUF_SIZE - xoff)
00374             delta = XBUF_SIZE - xoff;
00375 
00376           /* move input into processing buffer */
00377           memcpy (&xbuf[xoff], &post_data[poff], delta);
00378           xoff += delta;
00379           poff += delta;
00380 
00381           /* find if escape sequence is at the end of the processing buffer;
00382              if so, exclude those from processing (reduce delta to point at
00383              end of processed region) */
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           /* if we have an incomplete escape sequence, save it to
00391              pp->xbuf for later */
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           /* If we have nothing to do (delta == 0) and
00400              not just because the value is empty (are
00401              waiting for more data), go for next iteration */
00402           if ((xoff == 0) && (poff == post_data_len))
00403             continue;
00404 
00405           /* unescape */
00406           xbuf[xoff] = '\0';    /* 0-terminate in preparation */
00407           xoff = MHD_http_unescape (NULL, NULL, xbuf);
00408           /* finally: call application! */
00409           if (MHD_NO == pp->ikvi (pp->cls, MHD_POSTDATA_KIND, (const char *) &pp[1],    /* key */
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           /* are we done with the value? */
00419           if (end_of_value_found)
00420             {
00421               /* we found the end of the value! */
00422               if ((post_data[poff] == '\n') || (post_data[poff] == '\r'))
00423                 {
00424                   pp->state = PP_ExpectNewLine;
00425                 }
00426               else
00427                 {
00428                   poff++;       /* skip '&' */
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               /* we are done, report error if we receive any more... */
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);          /* should never happen! */
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;   /* out of memory */
00485       return MHD_NO;            /* not enough data */
00486     }
00487   if ((0 != memcmp ("--", buf, 2)) || (0 != memcmp (&buf[2], boundary, blen)))
00488     {
00489       pp->state = PP_Error;
00490       return MHD_NO;            /* expected boundary */
00491     }
00492   /* remove boundary from buffer */
00493   (*ioffptr) += 2 + blen;
00494   /* next: start with headers */
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           /* no match */
00527           bpos = spos + 1;
00528           continue;
00529         }
00530       if (spos[klen + 1] != '"')
00531         return;                 /* not quoted */
00532       if (NULL == (endv = strstr (&spos[klen + 2], "\"")))
00533         return;                 /* no end-quote */
00534       vlen = endv - spos - klen - 1;
00535       *destination = malloc (vlen);
00536       if (NULL == *destination)
00537         return;                 /* out of memory */
00538       (*destination)[vlen - 1] = '\0';
00539       memcpy (*destination, &spos[klen + 2], vlen - 1);
00540       return;                   /* success */
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;            /* out of memory */
00571     }
00572   if (newline == pp->buffer_pos)
00573     return MHD_NO;              /* will need more data */
00574   if (newline == 0)
00575     {
00576       /* empty line - end of headers */
00577       pp->skip_rn = RN_Full;
00578       pp->state = next_state;
00579       return MHD_YES;
00580     }
00581   /* got an actual header */
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   /* all data in buf until the boundary
00629      (\r\n--+boundary) is part of the value */
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           /* can check boundary */
00639           if (0 != memcmp (&buf[newline + 4], boundary, pp->blen))
00640             {
00641               /* no boundary, "\r\n--" is part of content, skip */
00642               newline += 4;
00643               continue;
00644             }
00645           else
00646             {
00647               /* boundary found, process until newline then
00648                  skip boundary and go back to init */
00649               pp->skip_rn = RN_Dash;
00650               pp->state = next_state;
00651               pp->dash_state = next_dash_state;
00652               (*ioffptr) += pp->blen + 4;       /* skip boundary as well */
00653               break;
00654             }
00655         }
00656       else
00657         {
00658           /* cannot check for boundary, process content that
00659              we have and check again later; except, if we have
00660              no content, abort (out of memory) */
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   /* newline is either at beginning of boundary or
00670      at least at the last character that we are sure
00671      is not part of the boundary */
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       /* first, move as much input data
00737          as possible to our internal buffer */
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;        /* out of memory */
00748         }
00749       state_changed = 0;
00750 
00751       /* first state machine for '\r'-'\n' and '--' handling */
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           /* fall-through! */
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           /* fall-through! */
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;        /* no '\r\n' */
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       /* main state engine */
00810       switch (pp->state)
00811         {
00812         case PP_Error:
00813           return MHD_NO;
00814         case PP_Done:
00815           /* did not expect to receive more data */
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                   /* out of memory */
00858                   pp->state = PP_Error;
00859                   return MHD_NO;
00860                 }
00861               /* free old content type, we will need that field
00862                  for the content type of the nested elements */
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           /* clean up state of one multipart form-data element! */
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 /* or PP_Error? */ ))
00911             {
00912               if (pp->state == PP_Error)
00913                 return MHD_NO;
00914               goto END;
00915             }
00916           break;
00917         case PP_Nested_PerformMarking:
00918           /* remember what headers were given
00919              globally */
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);          /* should never happen! */
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;            /* serious error */
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   /* this should never be reached */
01019   return MHD_NO;
01020 }
01021 
01025 int
01026 MHD_destroy_post_processor (struct MHD_PostProcessor *pp)
01027 {
01028   int ret;
01029 
01030   /* These internal strings need cleaning up since
01031      the post-processing may have been interrupted
01032      at any stage */
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 /* end of postprocessor.c */

Generated on 31 Aug 2011 for GNU libmicrohttpd by  doxygen 1.6.1