Blame src/microhttpd/postprocessor.c

Packit 875988
/*
Packit 875988
     This file is part of libmicrohttpd
Packit 875988
     Copyright (C) 2007-2013 Daniel Pittman and Christian Grothoff
Packit 875988
Packit 875988
     This library is free software; you can redistribute it and/or
Packit 875988
     modify it under the terms of the GNU Lesser General Public
Packit 875988
     License as published by the Free Software Foundation; either
Packit 875988
     version 2.1 of the License, or (at your option) any later version.
Packit 875988
Packit 875988
     This library is distributed in the hope that it will be useful,
Packit 875988
     but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 875988
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 875988
     Lesser General Public License for more details.
Packit 875988
Packit 875988
     You should have received a copy of the GNU Lesser General Public
Packit 875988
     License along with this library; if not, write to the Free Software
Packit 875988
     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Packit 875988
*/
Packit 875988
Packit 875988
/**
Packit 875988
 * @file postprocessor.c
Packit 875988
 * @brief  Methods for parsing POST data
Packit 875988
 * @author Christian Grothoff
Packit 875988
 */
Packit 875988
Packit 875988
#include "internal.h"
Packit 875988
#include "mhd_str.h"
Packit 875988
#include "mhd_compat.h"
Packit 875988
Packit 875988
/**
Packit 875988
 * Size of on-stack buffer that we use for un-escaping of the value.
Packit 875988
 * We use a pretty small value to be nice to the stack on embedded
Packit 875988
 * systems.
Packit 875988
 */
Packit 875988
#define XBUF_SIZE 512
Packit 875988
Packit 875988
/**
Packit 875988
 * States in the PP parser's state machine.
Packit 875988
 */
Packit 875988
enum PP_State
Packit 875988
{
Packit 875988
  /* general states */
Packit 875988
  PP_Error,
Packit 875988
  PP_Done,
Packit 875988
  PP_Init,
Packit 875988
  PP_NextBoundary,
Packit 875988
Packit 875988
  /* url encoding-states */
Packit 875988
  PP_ProcessValue,
Packit 875988
  PP_ExpectNewLine,
Packit 875988
Packit 875988
  /* post encoding-states  */
Packit 875988
  PP_ProcessEntryHeaders,
Packit 875988
  PP_PerformCheckMultipart,
Packit 875988
  PP_ProcessValueToBoundary,
Packit 875988
  PP_PerformCleanup,
Packit 875988
Packit 875988
  /* nested post-encoding states */
Packit 875988
  PP_Nested_Init,
Packit 875988
  PP_Nested_PerformMarking,
Packit 875988
  PP_Nested_ProcessEntryHeaders,
Packit 875988
  PP_Nested_ProcessValueToBoundary,
Packit 875988
  PP_Nested_PerformCleanup
Packit 875988
Packit 875988
};
Packit 875988
Packit 875988
Packit 875988
enum RN_State
Packit 875988
{
Packit 875988
  /**
Packit 875988
   * No RN-preprocessing in this state.
Packit 875988
   */
Packit 875988
  RN_Inactive = 0,
Packit 875988
Packit 875988
  /**
Packit 875988
   * If the next character is CR, skip it.  Otherwise,
Packit 875988
   * just go inactive.
Packit 875988
   */
Packit 875988
  RN_OptN = 1,
Packit 875988
Packit 875988
  /**
Packit 875988
   * Expect LFCR (and only LFCR).  As always, we also
Packit 875988
   * expect only LF or only CR.
Packit 875988
   */
Packit 875988
  RN_Full = 2,
Packit 875988
Packit 875988
  /**
Packit 875988
   * Expect either LFCR or '--'LFCR.  If '--'LFCR, transition into dash-state
Packit 875988
   * for the main state machine
Packit 875988
   */
Packit 875988
  RN_Dash = 3,
Packit 875988
Packit 875988
  /**
Packit 875988
   * Got a single dash, expect second dash.
Packit 875988
   */
Packit 875988
  RN_Dash2 = 4
Packit 875988
};
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Bits for the globally known fields that
Packit 875988
 * should not be deleted when we exit the
Packit 875988
 * nested state.
Packit 875988
 */
Packit 875988
enum NE_State
Packit 875988
{
Packit 875988
  NE_none = 0,
Packit 875988
  NE_content_name = 1,
Packit 875988
  NE_content_type = 2,
Packit 875988
  NE_content_filename = 4,
Packit 875988
  NE_content_transfer_encoding = 8
Packit 875988
};
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Internal state of the post-processor.  Note that the fields
Packit 875988
 * are sorted by type to enable optimal packing by the compiler.
Packit 875988
 */
Packit 875988
struct MHD_PostProcessor
Packit 875988
{
Packit 875988
Packit 875988
  /**
Packit 875988
   * The connection for which we are doing
Packit 875988
   * POST processing.
Packit 875988
   */
Packit 875988
  struct MHD_Connection *connection;
Packit 875988
Packit 875988
  /**
Packit 875988
   * Function to call with POST data.
Packit 875988
   */
Packit 875988
  MHD_PostDataIterator ikvi;
Packit 875988
Packit 875988
  /**
Packit 875988
   * Extra argument to ikvi.
Packit 875988
   */
Packit 875988
  void *cls;
Packit 875988
Packit 875988
  /**
Packit 875988
   * Encoding as given by the headers of the
Packit 875988
   * connection.
Packit 875988
   */
Packit 875988
  const char *encoding;
Packit 875988
Packit 875988
  /**
Packit 875988
   * Primary boundary (points into encoding string)
Packit 875988
   */
Packit 875988
  const char *boundary;
Packit 875988
Packit 875988
  /**
Packit 875988
   * Nested boundary (if we have multipart/mixed encoding).
Packit 875988
   */
Packit 875988
  char *nested_boundary;
Packit 875988
Packit 875988
  /**
Packit 875988
   * Pointer to the name given in disposition.
Packit 875988
   */
Packit 875988
  char *content_name;
Packit 875988
Packit 875988
  /**
Packit 875988
   * Pointer to the (current) content type.
Packit 875988
   */
Packit 875988
  char *content_type;
Packit 875988
Packit 875988
  /**
Packit 875988
   * Pointer to the (current) filename.
Packit 875988
   */
Packit 875988
  char *content_filename;
Packit 875988
Packit 875988
  /**
Packit 875988
   * Pointer to the (current) encoding.
Packit 875988
   */
Packit 875988
  char *content_transfer_encoding;
Packit 875988
Packit 875988
  /**
Packit 875988
   * Unprocessed value bytes due to escape
Packit 875988
   * sequences (URL-encoding only).
Packit 875988
   */
Packit 875988
  char xbuf[8];
Packit 875988
Packit 875988
  /**
Packit 875988
   * Size of our buffer for the key.
Packit 875988
   */
Packit 875988
  size_t buffer_size;
Packit 875988
Packit 875988
  /**
Packit 875988
   * Current position in the key buffer.
Packit 875988
   */
Packit 875988
  size_t buffer_pos;
Packit 875988
Packit 875988
  /**
Packit 875988
   * Current position in @e xbuf.
Packit 875988
   */
Packit 875988
  size_t xbuf_pos;
Packit 875988
Packit 875988
  /**
Packit 875988
   * Current offset in the value being processed.
Packit 875988
   */
Packit 875988
  uint64_t value_offset;
Packit 875988
Packit 875988
  /**
Packit 875988
   * strlen(boundary) -- if boundary != NULL.
Packit 875988
   */
Packit 875988
  size_t blen;
Packit 875988
Packit 875988
  /**
Packit 875988
   * strlen(nested_boundary) -- if nested_boundary != NULL.
Packit 875988
   */
Packit 875988
  size_t nlen;
Packit 875988
Packit 875988
  /**
Packit 875988
   * Do we have to call the 'ikvi' callback when processing the
Packit 875988
   * multipart post body even if the size of the payload is zero?
Packit 875988
   * Set to #MHD_YES whenever we parse a new multiparty entry header,
Packit 875988
   * and to #MHD_NO the first time we call the 'ikvi' callback.
Packit 875988
   * Used to ensure that we do always call 'ikvi' even if the
Packit 875988
   * payload is empty (but not more than once).
Packit 875988
   */
Packit 875988
  int must_ikvi;
Packit 875988
Packit 875988
  /**
Packit 875988
   * State of the parser.
Packit 875988
   */
Packit 875988
  enum PP_State state;
Packit 875988
Packit 875988
  /**
Packit 875988
   * Side-state-machine: skip LRCR (or just LF).
Packit 875988
   * Set to 0 if we are not in skip mode.  Set to 2
Packit 875988
   * if a LFCR is expected, set to 1 if a CR should
Packit 875988
   * be skipped if it is the next character.
Packit 875988
   */
Packit 875988
  enum RN_State skip_rn;
Packit 875988
Packit 875988
  /**
Packit 875988
   * If we are in skip_rn with "dash" mode and
Packit 875988
   * do find 2 dashes, what state do we go into?
Packit 875988
   */
Packit 875988
  enum PP_State dash_state;
Packit 875988
Packit 875988
  /**
Packit 875988
   * Which headers are global? (used to tell which
Packit 875988
   * headers were only valid for the nested multipart).
Packit 875988
   */
Packit 875988
  enum NE_State have;
Packit 875988
Packit 875988
};
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Create a `struct MHD_PostProcessor`.
Packit 875988
 *
Packit 875988
 * A `struct MHD_PostProcessor` can be used to (incrementally) parse
Packit 875988
 * the data portion of a POST request.  Note that some buggy browsers
Packit 875988
 * fail to set the encoding type.  If you want to support those, you
Packit 875988
 * may have to call #MHD_set_connection_value with the proper encoding
Packit 875988
 * type before creating a post processor (if no supported encoding
Packit 875988
 * type is set, this function will fail).
Packit 875988
 *
Packit 875988
 * @param connection the connection on which the POST is
Packit 875988
 *        happening (used to determine the POST format)
Packit 875988
 * @param buffer_size maximum number of bytes to use for
Packit 875988
 *        internal buffering (used only for the parsing,
Packit 875988
 *        specifically the parsing of the keys).  A
Packit 875988
 *        tiny value (256-1024) should be sufficient.
Packit 875988
 *        Do NOT use a value smaller than 256.  For good
Packit 875988
 *        performance, use 32 or 64k (i.e. 65536).
Packit 875988
 * @param iter iterator to be called with the parsed data,
Packit 875988
 *        Must NOT be NULL.
Packit 875988
 * @param iter_cls first argument to @a iter
Packit 875988
 * @return NULL on error (out of memory, unsupported encoding),
Packit 875988
 *         otherwise a PP handle
Packit 875988
 * @ingroup request
Packit 875988
 */
Packit 875988
struct MHD_PostProcessor *
Packit 875988
MHD_create_post_processor (struct MHD_Connection *connection,
Packit 875988
                           size_t buffer_size,
Packit 875988
                           MHD_PostDataIterator iter,
Packit 875988
                           void *iter_cls)
Packit 875988
{
Packit 875988
  struct MHD_PostProcessor *ret;
Packit 875988
  const char *encoding;
Packit 875988
  const char *boundary;
Packit 875988
  size_t blen;
Packit 875988
Packit 875988
  if ( (buffer_size < 256) ||
Packit 875988
       (NULL == connection) ||
Packit 875988
       (NULL == iter))
Packit 875988
    mhd_panic (mhd_panic_cls,
Packit 875988
               __FILE__,
Packit 875988
               __LINE__,
Packit 875988
               NULL);
Packit 875988
  encoding = MHD_lookup_connection_value (connection,
Packit 875988
                                          MHD_HEADER_KIND,
Packit 875988
                                          MHD_HTTP_HEADER_CONTENT_TYPE);
Packit 875988
  if (NULL == encoding)
Packit 875988
    return NULL;
Packit 875988
  boundary = NULL;
Packit 875988
  if (! MHD_str_equal_caseless_n_ (MHD_HTTP_POST_ENCODING_FORM_URLENCODED,
Packit 875988
                                   encoding,
Packit 875988
                                   MHD_STATICSTR_LEN_ (MHD_HTTP_POST_ENCODING_FORM_URLENCODED)))
Packit 875988
    {
Packit 875988
      if (! MHD_str_equal_caseless_n_ (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA,
Packit 875988
                                       encoding,
Packit 875988
                                       MHD_STATICSTR_LEN_ (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)))
Packit 875988
        return NULL;
Packit 875988
      boundary =
Packit 875988
        &encoding[MHD_STATICSTR_LEN_ (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)];
Packit 875988
      /* Q: should this be "strcasestr"? */
Packit 875988
      boundary = strstr (boundary, "boundary=");
Packit 875988
      if (NULL == boundary)
Packit 875988
	return NULL; /* failed to determine boundary */
Packit 875988
      boundary += MHD_STATICSTR_LEN_ ("boundary=");
Packit 875988
      blen = strlen (boundary);
Packit 875988
      if ( (blen == 0) ||
Packit 875988
           (blen * 2 + 2 > buffer_size) )
Packit 875988
        return NULL;            /* (will be) out of memory or invalid boundary */
Packit 875988
      if ( (boundary[0] == '"') &&
Packit 875988
           (boundary[blen - 1] == '"') )
Packit 875988
	{
Packit 875988
	  /* remove enclosing quotes */
Packit 875988
	  ++boundary;
Packit 875988
	  blen -= 2;
Packit 875988
	}
Packit 875988
    }
Packit 875988
  else
Packit 875988
    blen = 0;
Packit 875988
  buffer_size += 4; /* round up to get nice block sizes despite boundary search */
Packit 875988
Packit 875988
  /* add +1 to ensure we ALWAYS have a zero-termination at the end */
Packit 875988
  if (NULL == (ret = MHD_calloc_ (1, sizeof (struct MHD_PostProcessor) + buffer_size + 1)))
Packit 875988
    return NULL;
Packit 875988
  ret->connection = connection;
Packit 875988
  ret->ikvi = iter;
Packit 875988
  ret->cls = iter_cls;
Packit 875988
  ret->encoding = encoding;
Packit 875988
  ret->buffer_size = buffer_size;
Packit 875988
  ret->state = PP_Init;
Packit 875988
  ret->blen = blen;
Packit 875988
  ret->boundary = boundary;
Packit 875988
  ret->skip_rn = RN_Inactive;
Packit 875988
  return ret;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Process url-encoded POST data.
Packit 875988
 *
Packit 875988
 * @param pp post processor context
Packit 875988
 * @param post_data upload data
Packit 875988
 * @param post_data_len number of bytes in @a post_data
Packit 875988
 * @return #MHD_YES on success, #MHD_NO if there was an error processing the data
Packit 875988
 */
Packit 875988
static int
Packit 875988
post_process_urlencoded (struct MHD_PostProcessor *pp,
Packit 875988
                         const char *post_data,
Packit 875988
			 size_t post_data_len)
Packit 875988
{
Packit 875988
  size_t equals;
Packit 875988
  size_t amper;
Packit 875988
  size_t poff;
Packit 875988
  size_t xoff;
Packit 875988
  size_t delta;
Packit 875988
  int end_of_value_found;
Packit 875988
  char *buf;
Packit 875988
  char xbuf[XBUF_SIZE + 1];
Packit 875988
Packit 875988
  buf = (char *) &pp[1];
Packit 875988
  poff = 0;
Packit 875988
  while (poff < post_data_len)
Packit 875988
    {
Packit 875988
      switch (pp->state)
Packit 875988
        {
Packit 875988
        case PP_Error:
Packit 875988
          return MHD_NO;
Packit 875988
        case PP_Done:
Packit 875988
          /* did not expect to receive more data */
Packit 875988
          pp->state = PP_Error;
Packit 875988
          return MHD_NO;
Packit 875988
        case PP_Init:
Packit 875988
          equals = 0;
Packit 875988
          while ((equals + poff < post_data_len) &&
Packit 875988
                 (post_data[equals + poff] != '='))
Packit 875988
            equals++;
Packit 875988
          if (equals + pp->buffer_pos > pp->buffer_size)
Packit 875988
            {
Packit 875988
              pp->state = PP_Error;     /* out of memory */
Packit 875988
              return MHD_NO;
Packit 875988
            }
Packit 875988
          memcpy (&buf[pp->buffer_pos], &post_data[poff], equals);
Packit 875988
          pp->buffer_pos += equals;
Packit 875988
          if (equals + poff == post_data_len)
Packit 875988
            return MHD_YES;     /* no '=' yet */
Packit 875988
          buf[pp->buffer_pos] = '\0';   /* 0-terminate key */
Packit 875988
          pp->buffer_pos = 0;   /* reset for next key */
Packit 875988
	  MHD_unescape_plus (buf);
Packit 875988
          MHD_http_unescape (buf);
Packit 875988
          poff += equals + 1;
Packit 875988
          pp->state = PP_ProcessValue;
Packit 875988
          pp->value_offset = 0;
Packit 875988
          break;
Packit 875988
        case PP_ProcessValue:
Packit 875988
          /* obtain rest of value from previous iteration */
Packit 875988
          memcpy (xbuf, pp->xbuf, pp->xbuf_pos);
Packit 875988
          xoff = pp->xbuf_pos;
Packit 875988
          pp->xbuf_pos = 0;
Packit 875988
Packit 875988
          /* find last position in input buffer that is part of the value */
Packit 875988
          amper = 0;
Packit 875988
          while ((amper + poff < post_data_len) &&
Packit 875988
                 (amper < XBUF_SIZE) &&
Packit 875988
                 (post_data[amper + poff] != '&') &&
Packit 875988
                 (post_data[amper + poff] != '\n') &&
Packit 875988
                 (post_data[amper + poff] != '\r'))
Packit 875988
            amper++;
Packit 875988
          end_of_value_found = ((amper + poff < post_data_len) &&
Packit 875988
                                ((post_data[amper + poff] == '&') ||
Packit 875988
                                 (post_data[amper + poff] == '\n') ||
Packit 875988
                                 (post_data[amper + poff] == '\r')));
Packit 875988
          /* compute delta, the maximum number of bytes that we will be able to
Packit 875988
             process right now (either amper-limited of xbuf-size limited) */
Packit 875988
          delta = amper;
Packit 875988
          if (delta > XBUF_SIZE - xoff)
Packit 875988
            delta = XBUF_SIZE - xoff;
Packit 875988
Packit 875988
          /* move input into processing buffer */
Packit 875988
          memcpy (&xbuf[xoff], &post_data[poff], delta);
Packit 875988
          xoff += delta;
Packit 875988
          poff += delta;
Packit 875988
Packit 875988
          /* find if escape sequence is at the end of the processing buffer;
Packit 875988
             if so, exclude those from processing (reduce delta to point at
Packit 875988
             end of processed region) */
Packit 875988
          delta = xoff;
Packit 875988
          if ((delta > 0) &&
Packit 875988
              ('%' == xbuf[delta - 1]))
Packit 875988
            delta--;
Packit 875988
          else if ((delta > 1) &&
Packit 875988
                   ('%' == xbuf[delta - 2]))
Packit 875988
            delta -= 2;
Packit 875988
Packit 875988
          /* if we have an incomplete escape sequence, save it to
Packit 875988
             pp->xbuf for later */
Packit 875988
          if (delta < xoff)
Packit 875988
            {
Packit 875988
              memcpy (pp->xbuf,
Packit 875988
                      &xbuf[delta],
Packit 875988
                      xoff - delta);
Packit 875988
              pp->xbuf_pos = xoff - delta;
Packit 875988
              xoff = delta;
Packit 875988
            }
Packit 875988
Packit 875988
          /* If we have nothing to do (delta == 0) and
Packit 875988
             not just because the value is empty (are
Packit 875988
             waiting for more data), go for next iteration */
Packit 875988
          if ( (0 == xoff) &&
Packit 875988
               (poff == post_data_len))
Packit 875988
            continue;
Packit 875988
Packit 875988
          /* unescape */
Packit 875988
          xbuf[xoff] = '\0';    /* 0-terminate in preparation */
Packit 875988
	  MHD_unescape_plus (xbuf);
Packit 875988
          xoff = MHD_http_unescape (xbuf);
Packit 875988
          /* finally: call application! */
Packit 875988
	  pp->must_ikvi = MHD_NO;
Packit 875988
          if (MHD_NO == pp->ikvi (pp->cls,
Packit 875988
                                  MHD_POSTDATA_KIND,
Packit 875988
                                  (const char *) &pp[1],    /* key */
Packit 875988
                                  NULL,
Packit 875988
                                  NULL,
Packit 875988
                                  NULL,
Packit 875988
                                  xbuf,
Packit 875988
                                  pp->value_offset,
Packit 875988
                                  xoff))
Packit 875988
            {
Packit 875988
              pp->state = PP_Error;
Packit 875988
              return MHD_NO;
Packit 875988
            }
Packit 875988
          pp->value_offset += xoff;
Packit 875988
Packit 875988
          /* are we done with the value? */
Packit 875988
          if (end_of_value_found)
Packit 875988
            {
Packit 875988
              /* we found the end of the value! */
Packit 875988
              if ( ('\n' == post_data[poff]) ||
Packit 875988
                   ('\r' == post_data[poff]) )
Packit 875988
                {
Packit 875988
                  pp->state = PP_ExpectNewLine;
Packit 875988
                }
Packit 875988
              else if ('&' == post_data[poff])
Packit 875988
                {
Packit 875988
                  poff++;       /* skip '&' */
Packit 875988
                  pp->state = PP_Init;
Packit 875988
                }
Packit 875988
            }
Packit 875988
          break;
Packit 875988
        case PP_ExpectNewLine:
Packit 875988
          if ( ('\n' == post_data[poff]) ||
Packit 875988
               ('\r' == post_data[poff]) )
Packit 875988
            {
Packit 875988
              poff++;
Packit 875988
              /* we are done, report error if we receive any more... */
Packit 875988
              pp->state = PP_Done;
Packit 875988
              return MHD_YES;
Packit 875988
            }
Packit 875988
          return MHD_NO;
Packit 875988
        default:
Packit 875988
          mhd_panic (mhd_panic_cls,
Packit 875988
                     __FILE__,
Packit 875988
                     __LINE__,
Packit 875988
                     NULL);          /* should never happen! */
Packit 875988
        }
Packit 875988
    }
Packit 875988
  return MHD_YES;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * If the given line matches the prefix, strdup the
Packit 875988
 * rest of the line into the suffix ptr.
Packit 875988
 *
Packit 875988
 * @param prefix prefix to match
Packit 875988
 * @param line line to match prefix in
Packit 875988
 * @param suffix set to a copy of the rest of the line, starting at the end of the match
Packit 875988
 * @return #MHD_YES if there was a match, #MHD_NO if not
Packit 875988
 */
Packit 875988
static int
Packit 875988
try_match_header (const char *prefix,
Packit 875988
                  char *line,
Packit 875988
                  char **suffix)
Packit 875988
{
Packit 875988
  if (NULL != *suffix)
Packit 875988
    return MHD_NO;
Packit 875988
  while (0 != *line)
Packit 875988
    {
Packit 875988
      if (MHD_str_equal_caseless_n_ (prefix,
Packit 875988
                                     line,
Packit 875988
                                     strlen (prefix)))
Packit 875988
        {
Packit 875988
          *suffix = strdup (&line[strlen (prefix)]);
Packit 875988
          return MHD_YES;
Packit 875988
        }
Packit 875988
      ++line;
Packit 875988
    }
Packit 875988
  return MHD_NO;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 *
Packit 875988
 * @param pp post processor context
Packit 875988
 * @param boundary boundary to look for
Packit 875988
 * @param blen number of bytes in boundary
Packit 875988
 * @param ioffptr set to the end of the boundary if found,
Packit 875988
 *                otherwise incremented by one (FIXME: quirky API!)
Packit 875988
 * @param next_state state to which we should advance the post processor
Packit 875988
 *                   if the boundary is found
Packit 875988
 * @param next_dash_state dash_state to which we should advance the
Packit 875988
 *                   post processor if the boundary is found
Packit 875988
 * @return #MHD_NO if the boundary is not found, #MHD_YES if we did find it
Packit 875988
 */
Packit 875988
static int
Packit 875988
find_boundary (struct MHD_PostProcessor *pp,
Packit 875988
               const char *boundary,
Packit 875988
               size_t blen,
Packit 875988
               size_t *ioffptr,
Packit 875988
               enum PP_State next_state,
Packit 875988
               enum PP_State next_dash_state)
Packit 875988
{
Packit 875988
  char *buf = (char *) &pp[1];
Packit 875988
  const char *dash;
Packit 875988
Packit 875988
  if (pp->buffer_pos < 2 + blen)
Packit 875988
    {
Packit 875988
      if (pp->buffer_pos == pp->buffer_size)
Packit 875988
        pp->state = PP_Error;   /* out of memory */
Packit 875988
      /* ++(*ioffptr); */
Packit 875988
      return MHD_NO;            /* not enough data */
Packit 875988
    }
Packit 875988
  if ( (0 != memcmp ("--",
Packit 875988
                     buf,
Packit 875988
                     2)) ||
Packit 875988
       (0 != memcmp (&buf[2],
Packit 875988
                     boundary,
Packit 875988
                     blen)))
Packit 875988
    {
Packit 875988
      if (pp->state != PP_Init)
Packit 875988
        {
Packit 875988
          /* garbage not allowed */
Packit 875988
          pp->state = PP_Error;
Packit 875988
        }
Packit 875988
      else
Packit 875988
        {
Packit 875988
          /* skip over garbage (RFC 2046, 5.1.1) */
Packit 875988
          dash = memchr (buf,
Packit 875988
                         '-',
Packit 875988
                         pp->buffer_pos);
Packit 875988
          if (NULL == dash)
Packit 875988
            (*ioffptr) += pp->buffer_pos; /* skip entire buffer */
Packit 875988
          else
Packit 875988
            if (dash == buf)
Packit 875988
              (*ioffptr)++; /* at least skip one byte */
Packit 875988
            else
Packit 875988
              (*ioffptr) += dash - buf; /* skip to first possible boundary */
Packit 875988
        }
Packit 875988
      return MHD_NO;            /* expected boundary */
Packit 875988
    }
Packit 875988
  /* remove boundary from buffer */
Packit 875988
  (*ioffptr) += 2 + blen;
Packit 875988
  /* next: start with headers */
Packit 875988
  pp->skip_rn = RN_Dash;
Packit 875988
  pp->state = next_state;
Packit 875988
  pp->dash_state = next_dash_state;
Packit 875988
  return MHD_YES;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * In buf, there maybe an expression '$key="$value"'.  If that is the
Packit 875988
 * case, copy a copy of $value to destination.
Packit 875988
 *
Packit 875988
 * If destination is already non-NULL, do nothing.
Packit 875988
 */
Packit 875988
static void
Packit 875988
try_get_value (const char *buf,
Packit 875988
	       const char *key,
Packit 875988
	       char **destination)
Packit 875988
{
Packit 875988
  const char *spos;
Packit 875988
  const char *bpos;
Packit 875988
  const char *endv;
Packit 875988
  size_t klen;
Packit 875988
  size_t vlen;
Packit 875988
Packit 875988
  if (NULL != *destination)
Packit 875988
    return;
Packit 875988
  bpos = buf;
Packit 875988
  klen = strlen (key);
Packit 875988
  while (NULL != (spos = strstr (bpos, key)))
Packit 875988
    {
Packit 875988
      if ( (spos[klen] != '=') ||
Packit 875988
           ( (spos != buf) &&
Packit 875988
             (spos[-1] != ' ') ) )
Packit 875988
        {
Packit 875988
          /* no match */
Packit 875988
          bpos = spos + 1;
Packit 875988
          continue;
Packit 875988
        }
Packit 875988
      if (spos[klen + 1] != '"')
Packit 875988
        return;                 /* not quoted */
Packit 875988
      if (NULL == (endv = strchr (&spos[klen + 2],
Packit 875988
                                  '\"')))
Packit 875988
        return;                 /* no end-quote */
Packit 875988
      vlen = endv - spos - klen - 1;
Packit 875988
      *destination = malloc (vlen);
Packit 875988
      if (NULL == *destination)
Packit 875988
        return;                 /* out of memory */
Packit 875988
      (*destination)[vlen - 1] = '\0';
Packit 875988
      memcpy (*destination,
Packit 875988
              &spos[klen + 2],
Packit 875988
              vlen - 1);
Packit 875988
      return;                   /* success */
Packit 875988
    }
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Go over the headers of the part and update
Packit 875988
 * the fields in "pp" according to what we find.
Packit 875988
 * If we are at the end of the headers (as indicated
Packit 875988
 * by an empty line), transition into next_state.
Packit 875988
 *
Packit 875988
 * @param pp post processor context
Packit 875988
 * @param ioffptr set to how many bytes have been
Packit 875988
 *                processed
Packit 875988
 * @param next_state state to which the post processor should
Packit 875988
 *                be advanced if we find the end of the headers
Packit 875988
 * @return #MHD_YES if we can continue processing,
Packit 875988
 *         #MHD_NO on error or if we do not have
Packit 875988
 *                enough data yet
Packit 875988
 */
Packit 875988
static int
Packit 875988
process_multipart_headers (struct MHD_PostProcessor *pp,
Packit 875988
                           size_t *ioffptr,
Packit 875988
                           enum PP_State next_state)
Packit 875988
{
Packit 875988
  char *buf = (char *) &pp[1];
Packit 875988
  size_t newline;
Packit 875988
Packit 875988
  newline = 0;
Packit 875988
  while ( (newline < pp->buffer_pos) &&
Packit 875988
          (buf[newline] != '\r') &&
Packit 875988
          (buf[newline] != '\n') )
Packit 875988
    newline++;
Packit 875988
  if (newline == pp->buffer_size)
Packit 875988
    {
Packit 875988
      pp->state = PP_Error;
Packit 875988
      return MHD_NO;            /* out of memory */
Packit 875988
    }
Packit 875988
  if (newline == pp->buffer_pos)
Packit 875988
    return MHD_NO;              /* will need more data */
Packit 875988
  if (0 == newline)
Packit 875988
    {
Packit 875988
      /* empty line - end of headers */
Packit 875988
      pp->skip_rn = RN_Full;
Packit 875988
      pp->state = next_state;
Packit 875988
      return MHD_YES;
Packit 875988
    }
Packit 875988
  /* got an actual header */
Packit 875988
  if (buf[newline] == '\r')
Packit 875988
    pp->skip_rn = RN_OptN;
Packit 875988
  buf[newline] = '\0';
Packit 875988
  if (MHD_str_equal_caseless_n_ ("Content-disposition: ",
Packit 875988
                                 buf,
Packit 875988
                                 MHD_STATICSTR_LEN_ ("Content-disposition: ")))
Packit 875988
    {
Packit 875988
      try_get_value (&buf[MHD_STATICSTR_LEN_ ("Content-disposition: ")],
Packit 875988
                     "name",
Packit 875988
                     &pp->content_name);
Packit 875988
      try_get_value (&buf[MHD_STATICSTR_LEN_ ("Content-disposition: ")],
Packit 875988
                     "filename",
Packit 875988
                     &pp->content_filename);
Packit 875988
    }
Packit 875988
  else
Packit 875988
    {
Packit 875988
      try_match_header ("Content-type: ",
Packit 875988
                        buf,
Packit 875988
                        &pp->content_type);
Packit 875988
      try_match_header ("Content-Transfer-Encoding: ",
Packit 875988
                        buf,
Packit 875988
                        &pp->content_transfer_encoding);
Packit 875988
    }
Packit 875988
  (*ioffptr) += newline + 1;
Packit 875988
  return MHD_YES;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * We have the value until we hit the given boundary;
Packit 875988
 * process accordingly.
Packit 875988
 *
Packit 875988
 * @param pp post processor context
Packit 875988
 * @param ioffptr incremented based on the number of bytes processed
Packit 875988
 * @param boundary the boundary to look for
Packit 875988
 * @param blen strlen(boundary)
Packit 875988
 * @param next_state what state to go into after the
Packit 875988
 *        boundary was found
Packit 875988
 * @param next_dash_state state to go into if the next
Packit 875988
 *        boundary ends with "--"
Packit 875988
 * @return #MHD_YES if we can continue processing,
Packit 875988
 *         #MHD_NO on error or if we do not have
Packit 875988
 *                enough data yet
Packit 875988
 */
Packit 875988
static int
Packit 875988
process_value_to_boundary (struct MHD_PostProcessor *pp,
Packit 875988
                           size_t *ioffptr,
Packit 875988
                           const char *boundary,
Packit 875988
                           size_t blen,
Packit 875988
                           enum PP_State next_state,
Packit 875988
                           enum PP_State next_dash_state)
Packit 875988
{
Packit 875988
  char *buf = (char *) &pp[1];
Packit 875988
  size_t newline;
Packit 875988
  const char *r;
Packit 875988
Packit 875988
  /* all data in buf until the boundary
Packit 875988
     (\r\n--+boundary) is part of the value */
Packit 875988
  newline = 0;
Packit 875988
  while (1)
Packit 875988
    {
Packit 875988
      while (newline + 4 < pp->buffer_pos)
Packit 875988
        {
Packit 875988
          r = memchr (&buf[newline],
Packit 875988
                      '\r',
Packit 875988
                      pp->buffer_pos - newline - 4);
Packit 875988
          if (NULL == r)
Packit 875988
          {
Packit 875988
            newline = pp->buffer_pos - 4;
Packit 875988
            break;
Packit 875988
          }
Packit 875988
          newline = r - buf;
Packit 875988
          if (0 == memcmp ("\r\n--",
Packit 875988
                           &buf[newline],
Packit 875988
                           4))
Packit 875988
            break;
Packit 875988
          newline++;
Packit 875988
        }
Packit 875988
      if (newline + blen + 4 <= pp->buffer_pos)
Packit 875988
        {
Packit 875988
          /* can check boundary */
Packit 875988
          if (0 != memcmp (&buf[newline + 4],
Packit 875988
                           boundary,
Packit 875988
                           blen))
Packit 875988
            {
Packit 875988
              /* no boundary, "\r\n--" is part of content, skip */
Packit 875988
              newline += 4;
Packit 875988
              continue;
Packit 875988
            }
Packit 875988
          else
Packit 875988
            {
Packit 875988
              /* boundary found, process until newline then
Packit 875988
                 skip boundary and go back to init */
Packit 875988
              pp->skip_rn = RN_Dash;
Packit 875988
              pp->state = next_state;
Packit 875988
              pp->dash_state = next_dash_state;
Packit 875988
              (*ioffptr) += blen + 4;       /* skip boundary as well */
Packit 875988
              buf[newline] = '\0';
Packit 875988
              break;
Packit 875988
            }
Packit 875988
        }
Packit 875988
      else
Packit 875988
        {
Packit 875988
          /* cannot check for boundary, process content that
Packit 875988
             we have and check again later; except, if we have
Packit 875988
             no content, abort (out of memory) */
Packit 875988
          if ( (0 == newline) &&
Packit 875988
               (pp->buffer_pos == pp->buffer_size) )
Packit 875988
            {
Packit 875988
              pp->state = PP_Error;
Packit 875988
              return MHD_NO;
Packit 875988
            }
Packit 875988
          break;
Packit 875988
        }
Packit 875988
    }
Packit 875988
  /* newline is either at beginning of boundary or
Packit 875988
     at least at the last character that we are sure
Packit 875988
     is not part of the boundary */
Packit 875988
  if ( ( (MHD_YES == pp->must_ikvi) ||
Packit 875988
	 (0 != newline) ) &&
Packit 875988
       (MHD_NO == pp->ikvi (pp->cls,
Packit 875988
			    MHD_POSTDATA_KIND,
Packit 875988
			    pp->content_name,
Packit 875988
			    pp->content_filename,
Packit 875988
			    pp->content_type,
Packit 875988
			    pp->content_transfer_encoding,
Packit 875988
			    buf,
Packit 875988
                            pp->value_offset,
Packit 875988
                            newline)) )
Packit 875988
    {
Packit 875988
      pp->state = PP_Error;
Packit 875988
      return MHD_NO;
Packit 875988
    }
Packit 875988
  pp->must_ikvi = MHD_NO;
Packit 875988
  pp->value_offset += newline;
Packit 875988
  (*ioffptr) += newline;
Packit 875988
  return MHD_YES;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 *
Packit 875988
 * @param pp post processor context
Packit 875988
 */
Packit 875988
static void
Packit 875988
free_unmarked (struct MHD_PostProcessor *pp)
Packit 875988
{
Packit 875988
  if ( (NULL != pp->content_name) &&
Packit 875988
       (0 == (pp->have & NE_content_name)) )
Packit 875988
    {
Packit 875988
      free (pp->content_name);
Packit 875988
      pp->content_name = NULL;
Packit 875988
    }
Packit 875988
  if ( (NULL != pp->content_type) &&
Packit 875988
       (0 == (pp->have & NE_content_type)) )
Packit 875988
    {
Packit 875988
      free (pp->content_type);
Packit 875988
      pp->content_type = NULL;
Packit 875988
    }
Packit 875988
  if ( (NULL != pp->content_filename) &&
Packit 875988
       (0 == (pp->have & NE_content_filename)) )
Packit 875988
    {
Packit 875988
      free (pp->content_filename);
Packit 875988
      pp->content_filename = NULL;
Packit 875988
    }
Packit 875988
  if ( (NULL != pp->content_transfer_encoding) &&
Packit 875988
       (0 == (pp->have & NE_content_transfer_encoding)) )
Packit 875988
    {
Packit 875988
      free (pp->content_transfer_encoding);
Packit 875988
      pp->content_transfer_encoding = NULL;
Packit 875988
    }
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Decode multipart POST data.
Packit 875988
 *
Packit 875988
 * @param pp post processor context
Packit 875988
 * @param post_data data to decode
Packit 875988
 * @param post_data_len number of bytes in @a post_data
Packit 875988
 * @return #MHD_NO on error,
Packit 875988
 */
Packit 875988
static int
Packit 875988
post_process_multipart (struct MHD_PostProcessor *pp,
Packit 875988
                        const char *post_data,
Packit 875988
			size_t post_data_len)
Packit 875988
{
Packit 875988
  char *buf;
Packit 875988
  size_t max;
Packit 875988
  size_t ioff;
Packit 875988
  size_t poff;
Packit 875988
  int state_changed;
Packit 875988
Packit 875988
  buf = (char *) &pp[1];
Packit 875988
  ioff = 0;
Packit 875988
  poff = 0;
Packit 875988
  state_changed = 1;
Packit 875988
  while ( (poff < post_data_len) ||
Packit 875988
          ( (pp->buffer_pos > 0) &&
Packit 875988
            (0 != state_changed) ) )
Packit 875988
    {
Packit 875988
      /* first, move as much input data
Packit 875988
         as possible to our internal buffer */
Packit 875988
      max = pp->buffer_size - pp->buffer_pos;
Packit 875988
      if (max > post_data_len - poff)
Packit 875988
        max = post_data_len - poff;
Packit 875988
      memcpy (&buf[pp->buffer_pos],
Packit 875988
              &post_data[poff],
Packit 875988
              max);
Packit 875988
      poff += max;
Packit 875988
      pp->buffer_pos += max;
Packit 875988
      if ( (0 == max) &&
Packit 875988
           (0 == state_changed) &&
Packit 875988
           (poff < post_data_len) )
Packit 875988
        {
Packit 875988
          pp->state = PP_Error;
Packit 875988
          return MHD_NO;        /* out of memory */
Packit 875988
        }
Packit 875988
      state_changed = 0;
Packit 875988
Packit 875988
      /* first state machine for '\r'-'\n' and '--' handling */
Packit 875988
      switch (pp->skip_rn)
Packit 875988
        {
Packit 875988
        case RN_Inactive:
Packit 875988
          break;
Packit 875988
        case RN_OptN:
Packit 875988
          if (buf[0] == '\n')
Packit 875988
            {
Packit 875988
              ioff++;
Packit 875988
              pp->skip_rn = RN_Inactive;
Packit 875988
              goto AGAIN;
Packit 875988
            }
Packit 875988
          /* fall-through! */
Packit 875988
        case RN_Dash:
Packit 875988
          if (buf[0] == '-')
Packit 875988
            {
Packit 875988
              ioff++;
Packit 875988
              pp->skip_rn = RN_Dash2;
Packit 875988
              goto AGAIN;
Packit 875988
            }
Packit 875988
          pp->skip_rn = RN_Full;
Packit 875988
          /* fall-through! */
Packit 875988
        case RN_Full:
Packit 875988
          if (buf[0] == '\r')
Packit 875988
            {
Packit 875988
              if ( (pp->buffer_pos > 1) &&
Packit 875988
                   ('\n' == buf[1]) )
Packit 875988
                {
Packit 875988
                  pp->skip_rn = RN_Inactive;
Packit 875988
                  ioff += 2;
Packit 875988
                }
Packit 875988
              else
Packit 875988
                {
Packit 875988
                  pp->skip_rn = RN_OptN;
Packit 875988
                  ioff++;
Packit 875988
                }
Packit 875988
              goto AGAIN;
Packit 875988
            }
Packit 875988
          if (buf[0] == '\n')
Packit 875988
            {
Packit 875988
              ioff++;
Packit 875988
              pp->skip_rn = RN_Inactive;
Packit 875988
              goto AGAIN;
Packit 875988
            }
Packit 875988
          pp->skip_rn = RN_Inactive;
Packit 875988
          pp->state = PP_Error;
Packit 875988
          return MHD_NO;        /* no '\r\n' */
Packit 875988
        case RN_Dash2:
Packit 875988
          if (buf[0] == '-')
Packit 875988
            {
Packit 875988
              ioff++;
Packit 875988
              pp->skip_rn = RN_Full;
Packit 875988
              pp->state = pp->dash_state;
Packit 875988
              goto AGAIN;
Packit 875988
            }
Packit 875988
          pp->state = PP_Error;
Packit 875988
          break;
Packit 875988
        }
Packit 875988
Packit 875988
      /* main state engine */
Packit 875988
      switch (pp->state)
Packit 875988
        {
Packit 875988
        case PP_Error:
Packit 875988
          return MHD_NO;
Packit 875988
        case PP_Done:
Packit 875988
          /* did not expect to receive more data */
Packit 875988
          pp->state = PP_Error;
Packit 875988
          return MHD_NO;
Packit 875988
        case PP_Init:
Packit 875988
          /**
Packit 875988
           * Per RFC2046 5.1.1 NOTE TO IMPLEMENTORS, consume anything
Packit 875988
           * prior to the first multipart boundary:
Packit 875988
           *
Packit 875988
           * > There appears to be room for additional information prior
Packit 875988
           * > to the first boundary delimiter line and following the
Packit 875988
           * > final boundary delimiter line.  These areas should
Packit 875988
           * > generally be left blank, and implementations must ignore
Packit 875988
           * > anything that appears before the first boundary delimiter
Packit 875988
           * > line or after the last one.
Packit 875988
           */
Packit 875988
          (void) find_boundary (pp,
Packit 875988
				pp->boundary,
Packit 875988
				pp->blen,
Packit 875988
				&ioff,
Packit 875988
				PP_ProcessEntryHeaders,
Packit 875988
                                PP_Done);
Packit 875988
          break;
Packit 875988
        case PP_NextBoundary:
Packit 875988
          if (MHD_NO == find_boundary (pp,
Packit 875988
                                       pp->boundary,
Packit 875988
                                       pp->blen,
Packit 875988
                                       &ioff,
Packit 875988
                                       PP_ProcessEntryHeaders,
Packit 875988
                                       PP_Done))
Packit 875988
            {
Packit 875988
              if (pp->state == PP_Error)
Packit 875988
                return MHD_NO;
Packit 875988
              goto END;
Packit 875988
            }
Packit 875988
          break;
Packit 875988
        case PP_ProcessEntryHeaders:
Packit 875988
	  pp->must_ikvi = MHD_YES;
Packit 875988
          if (MHD_NO ==
Packit 875988
              process_multipart_headers (pp,
Packit 875988
                                         &ioff,
Packit 875988
                                         PP_PerformCheckMultipart))
Packit 875988
            {
Packit 875988
              if (pp->state == PP_Error)
Packit 875988
                return MHD_NO;
Packit 875988
              else
Packit 875988
                goto END;
Packit 875988
            }
Packit 875988
          state_changed = 1;
Packit 875988
          break;
Packit 875988
        case PP_PerformCheckMultipart:
Packit 875988
          if ( (NULL != pp->content_type) &&
Packit 875988
               (MHD_str_equal_caseless_n_ (pp->content_type,
Packit 875988
                                           "multipart/mixed",
Packit 875988
                                           MHD_STATICSTR_LEN_ ("multipart/mixed"))))
Packit 875988
            {
Packit 875988
              pp->nested_boundary = strstr (pp->content_type,
Packit 875988
                                            "boundary=");
Packit 875988
              if (NULL == pp->nested_boundary)
Packit 875988
                {
Packit 875988
                  pp->state = PP_Error;
Packit 875988
                  return MHD_NO;
Packit 875988
                }
Packit 875988
              pp->nested_boundary =
Packit 875988
                strdup (&pp->nested_boundary[MHD_STATICSTR_LEN_ ("boundary=")]);
Packit 875988
              if (NULL == pp->nested_boundary)
Packit 875988
                {
Packit 875988
                  /* out of memory */
Packit 875988
                  pp->state = PP_Error;
Packit 875988
                  return MHD_NO;
Packit 875988
                }
Packit 875988
              /* free old content type, we will need that field
Packit 875988
                 for the content type of the nested elements */
Packit 875988
              free (pp->content_type);
Packit 875988
              pp->content_type = NULL;
Packit 875988
              pp->nlen = strlen (pp->nested_boundary);
Packit 875988
              pp->state = PP_Nested_Init;
Packit 875988
              state_changed = 1;
Packit 875988
              break;
Packit 875988
            }
Packit 875988
          pp->state = PP_ProcessValueToBoundary;
Packit 875988
          pp->value_offset = 0;
Packit 875988
          state_changed = 1;
Packit 875988
          break;
Packit 875988
        case PP_ProcessValueToBoundary:
Packit 875988
          if (MHD_NO == process_value_to_boundary (pp,
Packit 875988
                                                   &ioff,
Packit 875988
                                                   pp->boundary,
Packit 875988
                                                   pp->blen,
Packit 875988
                                                   PP_PerformCleanup,
Packit 875988
                                                   PP_Done))
Packit 875988
            {
Packit 875988
              if (pp->state == PP_Error)
Packit 875988
                return MHD_NO;
Packit 875988
              break;
Packit 875988
            }
Packit 875988
          break;
Packit 875988
        case PP_PerformCleanup:
Packit 875988
          /* clean up state of one multipart form-data element! */
Packit 875988
          pp->have = NE_none;
Packit 875988
          free_unmarked (pp);
Packit 875988
          if (NULL != pp->nested_boundary)
Packit 875988
            {
Packit 875988
              free (pp->nested_boundary);
Packit 875988
              pp->nested_boundary = NULL;
Packit 875988
            }
Packit 875988
          pp->state = PP_ProcessEntryHeaders;
Packit 875988
          state_changed = 1;
Packit 875988
          break;
Packit 875988
        case PP_Nested_Init:
Packit 875988
          if (NULL == pp->nested_boundary)
Packit 875988
            {
Packit 875988
              pp->state = PP_Error;
Packit 875988
              return MHD_NO;
Packit 875988
            }
Packit 875988
          if (MHD_NO == find_boundary (pp,
Packit 875988
                                       pp->nested_boundary,
Packit 875988
                                       pp->nlen,
Packit 875988
                                       &ioff,
Packit 875988
                                       PP_Nested_PerformMarking,
Packit 875988
                                       PP_NextBoundary /* or PP_Error? */ ))
Packit 875988
            {
Packit 875988
              if (pp->state == PP_Error)
Packit 875988
                return MHD_NO;
Packit 875988
              goto END;
Packit 875988
            }
Packit 875988
          break;
Packit 875988
        case PP_Nested_PerformMarking:
Packit 875988
          /* remember what headers were given
Packit 875988
             globally */
Packit 875988
          pp->have = NE_none;
Packit 875988
          if (NULL != pp->content_name)
Packit 875988
            pp->have |= NE_content_name;
Packit 875988
          if (NULL != pp->content_type)
Packit 875988
            pp->have |= NE_content_type;
Packit 875988
          if (NULL != pp->content_filename)
Packit 875988
            pp->have |= NE_content_filename;
Packit 875988
          if (NULL != pp->content_transfer_encoding)
Packit 875988
            pp->have |= NE_content_transfer_encoding;
Packit 875988
          pp->state = PP_Nested_ProcessEntryHeaders;
Packit 875988
          state_changed = 1;
Packit 875988
          break;
Packit 875988
        case PP_Nested_ProcessEntryHeaders:
Packit 875988
          pp->value_offset = 0;
Packit 875988
          if (MHD_NO ==
Packit 875988
              process_multipart_headers (pp,
Packit 875988
                                         &ioff,
Packit 875988
                                         PP_Nested_ProcessValueToBoundary))
Packit 875988
            {
Packit 875988
              if (pp->state == PP_Error)
Packit 875988
                return MHD_NO;
Packit 875988
              else
Packit 875988
                goto END;
Packit 875988
            }
Packit 875988
          state_changed = 1;
Packit 875988
          break;
Packit 875988
        case PP_Nested_ProcessValueToBoundary:
Packit 875988
          if (MHD_NO == process_value_to_boundary (pp,
Packit 875988
                                                   &ioff,
Packit 875988
                                                   pp->nested_boundary,
Packit 875988
                                                   pp->nlen,
Packit 875988
                                                   PP_Nested_PerformCleanup,
Packit 875988
                                                   PP_NextBoundary))
Packit 875988
            {
Packit 875988
              if (pp->state == PP_Error)
Packit 875988
                return MHD_NO;
Packit 875988
              break;
Packit 875988
            }
Packit 875988
          break;
Packit 875988
        case PP_Nested_PerformCleanup:
Packit 875988
          free_unmarked (pp);
Packit 875988
          pp->state = PP_Nested_ProcessEntryHeaders;
Packit 875988
          state_changed = 1;
Packit 875988
          break;
Packit 875988
        default:
Packit 875988
          mhd_panic (mhd_panic_cls,
Packit 875988
                     __FILE__,
Packit 875988
                     __LINE__,
Packit 875988
                     NULL);          /* should never happen! */
Packit 875988
        }
Packit 875988
    AGAIN:
Packit 875988
      if (ioff > 0)
Packit 875988
        {
Packit 875988
          memmove (buf,
Packit 875988
                   &buf[ioff],
Packit 875988
                   pp->buffer_pos - ioff);
Packit 875988
          pp->buffer_pos -= ioff;
Packit 875988
          ioff = 0;
Packit 875988
          state_changed = 1;
Packit 875988
        }
Packit 875988
    }
Packit 875988
END:
Packit 875988
  if (0 != ioff)
Packit 875988
    {
Packit 875988
      memmove (buf,
Packit 875988
               &buf[ioff],
Packit 875988
               pp->buffer_pos - ioff);
Packit 875988
      pp->buffer_pos -= ioff;
Packit 875988
    }
Packit 875988
  if (poff < post_data_len)
Packit 875988
    {
Packit 875988
      pp->state = PP_Error;
Packit 875988
      return MHD_NO;            /* serious error */
Packit 875988
    }
Packit 875988
  return MHD_YES;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Parse and process POST data.  Call this function when POST data is
Packit 875988
 * available (usually during an #MHD_AccessHandlerCallback) with the
Packit 875988
 * "upload_data" and "upload_data_size".  Whenever possible, this will
Packit 875988
 * then cause calls to the #MHD_PostDataIterator.
Packit 875988
 *
Packit 875988
 * @param pp the post processor
Packit 875988
 * @param post_data @a post_data_len bytes of POST data
Packit 875988
 * @param post_data_len length of @a post_data
Packit 875988
 * @return #MHD_YES on success, #MHD_NO on error
Packit 875988
 *         (out-of-memory, iterator aborted, parse error)
Packit 875988
 * @ingroup request
Packit 875988
 */
Packit 875988
int
Packit 875988
MHD_post_process (struct MHD_PostProcessor *pp,
Packit 875988
                  const char *post_data,
Packit 875988
                  size_t post_data_len)
Packit 875988
{
Packit 875988
  if (0 == post_data_len)
Packit 875988
    return MHD_YES;
Packit 875988
  if (NULL == pp)
Packit 875988
    return MHD_NO;
Packit 875988
  if (MHD_str_equal_caseless_n_ (MHD_HTTP_POST_ENCODING_FORM_URLENCODED,
Packit 875988
                                 pp->encoding,
Packit 875988
                                 MHD_STATICSTR_LEN_(MHD_HTTP_POST_ENCODING_FORM_URLENCODED)))
Packit 875988
    return post_process_urlencoded (pp,
Packit 875988
                                    post_data,
Packit 875988
                                    post_data_len);
Packit 875988
  if (MHD_str_equal_caseless_n_ (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA,
Packit 875988
                                 pp->encoding,
Packit 875988
                                 MHD_STATICSTR_LEN_ (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)))
Packit 875988
    return post_process_multipart (pp,
Packit 875988
                                   post_data,
Packit 875988
                                   post_data_len);
Packit 875988
  /* this should never be reached */
Packit 875988
  return MHD_NO;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Release PostProcessor resources.
Packit 875988
 *
Packit 875988
 * @param pp post processor context to destroy
Packit 875988
 * @return #MHD_YES if processing completed nicely,
Packit 875988
 *         #MHD_NO if there were spurious characters / formatting
Packit 875988
 *                problems; it is common to ignore the return
Packit 875988
 *                value of this function
Packit 875988
 * @ingroup request
Packit 875988
 */
Packit 875988
int
Packit 875988
MHD_destroy_post_processor (struct MHD_PostProcessor *pp)
Packit 875988
{
Packit 875988
  int ret;
Packit 875988
Packit 875988
  if (NULL == pp)
Packit 875988
    return MHD_YES;
Packit 875988
  if (PP_ProcessValue == pp->state)
Packit 875988
  {
Packit 875988
    /* key without terminated value left at the end of the
Packit 875988
       buffer; fake receiving a termination character to
Packit 875988
       ensure it is also processed */
Packit 875988
    post_process_urlencoded (pp,
Packit 875988
                             "\n",
Packit 875988
                             1);
Packit 875988
  }
Packit 875988
  /* These internal strings need cleaning up since
Packit 875988
     the post-processing may have been interrupted
Packit 875988
     at any stage */
Packit 875988
  if ( (pp->xbuf_pos > 0) ||
Packit 875988
       ( (pp->state != PP_Done) &&
Packit 875988
         (pp->state != PP_ExpectNewLine) ) )
Packit 875988
    ret = MHD_NO;
Packit 875988
  else
Packit 875988
    ret = MHD_YES;
Packit 875988
  pp->have = NE_none;
Packit 875988
  free_unmarked (pp);
Packit 875988
  if (NULL != pp->nested_boundary)
Packit 875988
    free (pp->nested_boundary);
Packit 875988
  free (pp);
Packit 875988
  return ret;
Packit 875988
}
Packit 875988
Packit 875988
/* end of postprocessor.c */