postprocessor.c

Go to the documentation of this file.
00001 /*
00002      This file is part of libmicrohttpd
00003      (C) 2007 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   unsigned int buffer_size;
00176 
00180   unsigned int buffer_pos;
00181 
00185   unsigned int xbuf_pos;
00186 
00190   unsigned int 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                            unsigned int 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 != strcasecmp (MHD_HTTP_POST_ENCODING_FORM_URLENCODED, encoding))
00267     {
00268       if (0 !=
00269           strncasecmp (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, encoding,
00270                        strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)))
00271         return NULL;
00272       boundary =
00273         &encoding[strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)];
00274       /* Q: should this be "strcasestr"? */
00275       if (NULL != strstr (boundary, "boundary="))
00276         boundary = strstr (boundary, "boundary=") + strlen ("boundary=");
00277       else
00278         return NULL;            /* failed to determine boundary */
00279       blen = strlen (boundary);
00280       if ((blen == 0) || (blen * 2 + 2 > buffer_size))
00281         return NULL;            /* (will be) out of memory or invalid boundary */
00282     }
00283   else
00284     blen = 0;
00285   ret = malloc (sizeof (struct MHD_PostProcessor) + buffer_size + 1);
00286   if (ret == NULL)
00287     return NULL;
00288   memset (ret, 0, sizeof (struct MHD_PostProcessor) + buffer_size + 1);
00289   ret->connection = connection;
00290   ret->ikvi = ikvi;
00291   ret->cls = cls;
00292   ret->encoding = encoding;
00293   ret->buffer_size = buffer_size;
00294   ret->state = PP_Init;
00295   ret->blen = blen;
00296   ret->boundary = boundary;
00297   ret->skip_rn = RN_Inactive;
00298   return ret;
00299 }
00300 
00304 static int
00305 post_process_urlencoded (struct MHD_PostProcessor *pp,
00306                          const char *post_data, unsigned int post_data_len)
00307 {
00308   unsigned int equals;
00309   unsigned int amper;
00310   unsigned int poff;
00311   unsigned int xoff;
00312   unsigned int delta;
00313   int end_of_value_found;
00314   char *buf;
00315   char xbuf[XBUF_SIZE + 1];
00316 
00317   buf = (char *) &pp[1];
00318   poff = 0;
00319   while (poff < post_data_len)
00320     {
00321       switch (pp->state)
00322         {
00323         case PP_Error:
00324           return MHD_NO;
00325         case PP_Done:
00326           /* did not expect to receive more data */
00327           pp->state = PP_Error;
00328           return MHD_NO;
00329         case PP_Init:
00330           equals = 0;
00331           while ((equals + poff < post_data_len) &&
00332                  (post_data[equals + poff] != '='))
00333             equals++;
00334           if (equals + pp->buffer_pos > pp->buffer_size)
00335             {
00336               pp->state = PP_Error;     /* out of memory */
00337               return MHD_NO;
00338             }
00339           memcpy (&buf[pp->buffer_pos], &post_data[poff], equals);
00340           pp->buffer_pos += equals;
00341           if (equals + poff == post_data_len)
00342             return MHD_YES;     /* no '=' yet */
00343           buf[pp->buffer_pos] = '\0';   /* 0-terminate key */
00344           pp->buffer_pos = 0;   /* reset for next key */
00345           MHD_http_unescape (buf);
00346           poff += equals + 1;
00347           pp->state = PP_ProcessValue;
00348           pp->value_offset = 0;
00349           break;
00350         case PP_ProcessValue:
00351           /* obtain rest of value from previous iteration */
00352           memcpy (xbuf, pp->xbuf, pp->xbuf_pos);
00353           xoff = pp->xbuf_pos;
00354           pp->xbuf_pos = 0;
00355 
00356           /* find last position in input buffer that is part of the value */
00357           amper = 0;
00358           while ((amper + poff < post_data_len) &&
00359                  (amper < XBUF_SIZE) && 
00360                  (post_data[amper + poff] != '&') &&
00361                  (post_data[amper + poff] != '\n') &&
00362                  (post_data[amper + poff] != '\r'))
00363             amper++;
00364           end_of_value_found = ( (amper + poff < post_data_len) &&
00365                                  ( (post_data[amper + poff] == '&') ||
00366                                    (post_data[amper + poff] == '\n') ||
00367                                    (post_data[amper + poff] == '\r') ) );
00368           /* compute delta, the maximum number of bytes that we will be able to
00369              process right now (either amper-limited of xbuf-size limited) */
00370           delta = amper;
00371           if (delta > XBUF_SIZE - xoff)
00372             delta = XBUF_SIZE - xoff;
00373 
00374           /* move input into processing buffer */
00375           memcpy (&xbuf[xoff], &post_data[poff], delta);
00376           xoff += delta;
00377           poff += delta;
00378 
00379           /* find if escape sequence is at the end of the processing buffer;
00380              if so, exclude those from processing (reduce delta to point at
00381              end of processed region) */
00382           delta = xoff;
00383           if ((delta > 0) && (xbuf[delta - 1] == '%'))
00384             delta--;
00385           else if ((delta > 1) && (xbuf[delta - 2] == '%'))
00386             delta -= 2;
00387 
00388           /* if we have an incomplete escape sequence, save it to
00389              pp->xbuf for later */
00390           if (delta < xoff)
00391             {
00392               memcpy (pp->xbuf, &xbuf[delta], xoff - delta);
00393               pp->xbuf_pos = xoff - delta;
00394               xoff = delta;
00395             }
00396 
00397           /* If we have nothing to do (delta == 0) and
00398              not just because the value is empty (are
00399              waiting for more data), go for next iteration */
00400           if ((xoff == 0) && (poff == post_data_len))
00401             continue;
00402 
00403           /* unescape */
00404           xbuf[xoff] = '\0';    /* 0-terminate in preparation */
00405           MHD_http_unescape (xbuf);
00406 
00407           /* finally: call application! */
00408           if (MHD_NO ==
00409               pp->ikvi (pp->cls, MHD_POSTDATA_KIND, (const char *) &pp[1],  /* key */
00410                         NULL, NULL, NULL, xbuf, pp->value_offset, xoff))
00411             {
00412               pp->state = PP_Error;
00413               return MHD_NO;
00414             }
00415           pp->value_offset += xoff;
00416 
00417           /* are we done with the value? */
00418           if (end_of_value_found)
00419             {
00420               /* we found the end of the value! */
00421               if ((post_data[poff] == '\n') ||
00422                   (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                unsigned int *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                            unsigned int *ioffptr, enum PP_State next_state)
00559 {
00560   char *buf = (char *) &pp[1];
00561   unsigned int 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                            unsigned int *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   unsigned int 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, unsigned int post_data_len)
00721 {
00722   char *buf;
00723   unsigned int max;
00724   unsigned int ioff;
00725   unsigned int poff;
00726   int state_changed;
00727 
00728   buf = (char *) &pp[1];
00729   ioff = 0;
00730   poff = 0;
00731   state_changed = 1;
00732   while ((poff < post_data_len) ||
00733          ((pp->buffer_pos > 0) && (state_changed != 0)))
00734     {
00735       /* first, move as much input data
00736          as possible to our internal buffer */
00737       max = pp->buffer_size - pp->buffer_pos;
00738       if (max > post_data_len - poff)
00739         max = post_data_len - poff;
00740       memcpy (&buf[pp->buffer_pos], &post_data[poff], max);
00741       poff += max;
00742       pp->buffer_pos += max;
00743       if ((max == 0) && (state_changed == 0) && (poff < post_data_len))
00744         {
00745           pp->state = PP_Error;
00746           return MHD_NO;        /* out of memory */
00747         }
00748       state_changed = 0;
00749 
00750       /* first state machine for '\r'-'\n' and '--' handling */
00751       switch (pp->skip_rn)
00752         {
00753         case RN_Inactive:
00754           break;
00755         case RN_OptN:
00756           if (buf[0] == '\n')
00757             {
00758               ioff++;
00759               pp->skip_rn = RN_Inactive;
00760               goto AGAIN;
00761             }
00762         case RN_Dash:
00763           if (buf[0] == '-')
00764             {
00765               ioff++;
00766               pp->skip_rn = RN_Dash2;
00767               goto AGAIN;
00768             }
00769           pp->skip_rn = RN_Full;
00770           /* fall-through! */
00771         case RN_Full:
00772           if (buf[0] == '\r')
00773             {
00774               if ((pp->buffer_pos > 1) && (buf[1] == '\n'))
00775                 {
00776                   pp->skip_rn = RN_Inactive;
00777                   ioff += 2;
00778                 }
00779               else
00780                 {
00781                   pp->skip_rn = RN_OptN;
00782                   ioff++;
00783                 }
00784               goto AGAIN;
00785             }
00786           if (buf[0] == '\n')
00787             {
00788               ioff++;
00789               pp->skip_rn = RN_Inactive;
00790               goto AGAIN;
00791             }
00792           pp->skip_rn = RN_Inactive;
00793           pp->state = PP_Error;
00794           return MHD_NO;        /* no '\r\n' */
00795         case RN_Dash2:
00796           if (buf[0] == '-')
00797             {
00798               ioff++;
00799               pp->skip_rn = RN_Full;
00800               pp->state = pp->dash_state;
00801               goto AGAIN;
00802             }
00803           pp->state = PP_Error;
00804           break;
00805         }
00806 
00807       /* main state engine */
00808       switch (pp->state)
00809         {
00810         case PP_Error:
00811           return MHD_NO;
00812         case PP_Done:
00813           /* did not expect to receive more data */
00814           pp->state = PP_Error;
00815           return MHD_NO;
00816         case PP_Init:
00817           if (MHD_NO == find_boundary (pp,
00818                                        pp->boundary,
00819                                        pp->blen,
00820                                        &ioff,
00821                                        PP_ProcessEntryHeaders, PP_Done))
00822             {
00823               if (pp->state == PP_Error)
00824                 return MHD_NO;
00825               goto END;
00826             }
00827           break;
00828         case PP_ProcessEntryHeaders:
00829           if (MHD_NO ==
00830               process_multipart_headers (pp, &ioff, PP_PerformCheckMultipart))
00831             {
00832               if (pp->state == PP_Error)
00833                 return MHD_NO;
00834               else
00835                 goto END;
00836             }
00837           state_changed = 1;
00838           break;
00839         case PP_PerformCheckMultipart:
00840           if ((pp->content_type != NULL) &&
00841               (0 == strncasecmp (pp->content_type,
00842                                  "multipart/mixed",
00843                                  strlen ("multipart/mixed"))))
00844             {
00845               pp->nested_boundary = strstr (pp->content_type, "boundary=");
00846               if (pp->nested_boundary == NULL)
00847                 {
00848                   pp->state = PP_Error;
00849                   return MHD_NO;
00850                 }
00851               pp->nested_boundary =
00852                 strdup (&pp->nested_boundary[strlen ("boundary=")]);
00853               if (pp->nested_boundary == NULL)
00854                 {
00855                   /* out of memory */
00856                   pp->state = PP_Error;
00857                   return MHD_NO;
00858                 }
00859               /* free old content type, we will need that field
00860                  for the content type of the nested elements */
00861               free (pp->content_type);
00862               pp->content_type = NULL;
00863               pp->nlen = strlen (pp->nested_boundary);
00864               pp->state = PP_Nested_Init;
00865               state_changed = 1;
00866               break;
00867             }
00868           pp->state = PP_ProcessValueToBoundary;
00869           pp->value_offset = 0;
00870           state_changed = 1;
00871           break;
00872         case PP_ProcessValueToBoundary:
00873           if (MHD_NO == process_value_to_boundary (pp,
00874                                                    &ioff,
00875                                                    pp->boundary,
00876                                                    pp->blen,
00877                                                    PP_PerformCleanup,
00878                                                    PP_Done))
00879             {
00880               if (pp->state == PP_Error)
00881                 return MHD_NO;
00882               break;
00883             }
00884           break;
00885         case PP_PerformCleanup:
00886           /* clean up state of one multipart form-data element! */
00887           pp->have = NE_none;
00888           free_unmarked (pp);
00889           if (pp->nested_boundary != NULL)
00890             {
00891               free (pp->nested_boundary);
00892               pp->nested_boundary = NULL;
00893             }
00894           pp->state = PP_ProcessEntryHeaders;
00895           state_changed = 1;
00896           break;
00897         case PP_Nested_Init:
00898           if (pp->nested_boundary == NULL)
00899             {
00900               pp->state = PP_Error;
00901               return MHD_NO;
00902             }
00903           if (MHD_NO == find_boundary (pp,
00904                                        pp->nested_boundary,
00905                                        pp->nlen,
00906                                        &ioff,
00907                                        PP_Nested_PerformMarking,
00908                                        PP_Init /* or PP_Error? */ ))
00909             {
00910               if (pp->state == PP_Error)
00911                 return MHD_NO;
00912               goto END;
00913             }
00914           break;
00915         case PP_Nested_PerformMarking:
00916           /* remember what headers were given
00917              globally */
00918           pp->have = NE_none;
00919           if (pp->content_name != NULL)
00920             pp->have |= NE_content_name;
00921           if (pp->content_type != NULL)
00922             pp->have |= NE_content_type;
00923           if (pp->content_filename != NULL)
00924             pp->have |= NE_content_filename;
00925           if (pp->content_transfer_encoding != NULL)
00926             pp->have |= NE_content_transfer_encoding;
00927           pp->state = PP_Nested_ProcessEntryHeaders;
00928           state_changed = 1;
00929           break;
00930         case PP_Nested_ProcessEntryHeaders:
00931           pp->value_offset = 0;
00932           if (MHD_NO ==
00933               process_multipart_headers (pp, &ioff,
00934                                          PP_Nested_ProcessValueToBoundary))
00935             {
00936               if (pp->state == PP_Error)
00937                 return MHD_NO;
00938               else
00939                 goto END;
00940             }
00941           state_changed = 1;
00942           break;
00943         case PP_Nested_ProcessValueToBoundary:
00944           if (MHD_NO == process_value_to_boundary (pp,
00945                                                    &ioff,
00946                                                    pp->nested_boundary,
00947                                                    pp->nlen,
00948                                                    PP_Nested_PerformCleanup,
00949                                                    PP_Init))
00950             {
00951               if (pp->state == PP_Error)
00952                 return MHD_NO;
00953               break;
00954             }
00955           break;
00956         case PP_Nested_PerformCleanup:
00957           free_unmarked (pp);
00958           pp->state = PP_Nested_ProcessEntryHeaders;
00959           state_changed = 1;
00960           break;
00961         default:
00962           abort ();             /* should never happen! */
00963         }
00964     AGAIN:
00965       if (ioff > 0)
00966         {
00967           memmove (buf, &buf[ioff], pp->buffer_pos - ioff);
00968           pp->buffer_pos -= ioff;
00969           ioff = 0;
00970           state_changed = 1;
00971         }
00972     }
00973 END:
00974   if (ioff != 0)
00975     {
00976       memmove (buf, &buf[ioff], pp->buffer_pos - ioff);
00977       pp->buffer_pos -= ioff;
00978     }
00979   if (poff < post_data_len)
00980     {
00981       pp->state = PP_Error;
00982       return MHD_NO;            /* serious error */
00983     }
00984   return MHD_YES;
00985 }
00986 
01001 int
01002 MHD_post_process (struct MHD_PostProcessor *pp,
01003                   const char *post_data, unsigned int post_data_len)
01004 {
01005   if (post_data_len == 0)
01006     return MHD_YES;
01007   if (pp == NULL)
01008     return MHD_NO;
01009   if (0 == strcasecmp (MHD_HTTP_POST_ENCODING_FORM_URLENCODED, pp->encoding))
01010     return post_process_urlencoded (pp, post_data, post_data_len);
01011   if (0 ==
01012       strncasecmp (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, pp->encoding,
01013                    strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)))
01014     return post_process_multipart (pp, post_data, post_data_len);
01015   /* this should never be reached */
01016   return MHD_NO;
01017 }
01018 
01022 int
01023 MHD_destroy_post_processor (struct MHD_PostProcessor *pp)
01024 {
01025   int ret;
01026 
01027   /* These internal strings need cleaning up since
01028      the post-processing may have been interrupted
01029      at any stage */
01030   if ( (pp->xbuf_pos > 0) ||
01031        (pp->state != PP_Done) )
01032     ret = MHD_NO;
01033   else
01034     ret = MHD_YES;
01035   pp->have = NE_none;
01036   free_unmarked (pp);
01037   if (pp->nested_boundary != NULL)
01038     free (pp->nested_boundary);
01039   free (pp);
01040   return ret;
01041 }
01042 
01043 /* end of postprocessor.c */

Generated on Fri Oct 3 15:37:04 2008 for GNU libmicrohttpd by  doxygen 1.5.6