|
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 */
|