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

Generated on Tue May 19 23:21:08 2009 for GNU libmicrohttpd by  doxygen 1.5.8