[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[GNUnet-SVN] r6132 - in libmicrohttpd: . src/daemon
From: |
gnunet |
Subject: |
[GNUnet-SVN] r6132 - in libmicrohttpd: . src/daemon |
Date: |
Wed, 30 Jan 2008 23:16:41 -0700 (MST) |
Author: grothoff
Date: 2008-01-30 23:16:41 -0700 (Wed, 30 Jan 2008)
New Revision: 6132
Modified:
libmicrohttpd/ChangeLog
libmicrohttpd/src/daemon/postprocessor.c
libmicrohttpd/src/daemon/postprocessor_test.c
Log:
finished support for nested multiparts
Modified: libmicrohttpd/ChangeLog
===================================================================
--- libmicrohttpd/ChangeLog 2008-01-30 21:13:59 UTC (rev 6131)
+++ libmicrohttpd/ChangeLog 2008-01-31 06:16:41 UTC (rev 6132)
@@ -1,3 +1,6 @@
+Wed Jan 30 23:15:44 MST 2008
+ Added support for nested multiparts to post processor. -CG
+
Mon Jan 21 11:59:46 MST 2008
Added option to limit number of concurrent connections
accepted from the same IP address. -CG
Modified: libmicrohttpd/src/daemon/postprocessor.c
===================================================================
--- libmicrohttpd/src/daemon/postprocessor.c 2008-01-30 21:13:59 UTC (rev
6131)
+++ libmicrohttpd/src/daemon/postprocessor.c 2008-01-31 06:16:41 UTC (rev
6132)
@@ -26,28 +26,87 @@
#include "internal.h"
/**
+ * Size of on-stack buffer that we use for un-escaping of the value.
+ */
+#define XBUF_SIZE 1024
+
+/**
* States in the PP parser's state machine.
*/
enum PP_State
{
- PP_Init = 0,
- PP_HaveKey = 1,
- PP_ExpectNewLine = 2,
- PP_ExpectNewLineR = 3,
- PP_ExpectNewLineN = 4,
- PP_ExpectNewLineNOPT = 5,
- PP_Headers = 6,
- PP_SkipRN = 7,
- PP_SkipN = 8,
- PP_ValueToBoundary = 9,
- PP_FinalDash = 10,
- PP_FinalRN = 11,
- PP_FinalN = 12,
- PP_Error = 9999,
+ /* general states */
+ PP_Error,
+ PP_Done,
+ PP_Init,
+
+ /* url encoding-states*/
+ PP_ProcessValue,
+ PP_ExpectNewLine,
+
+ /* post encoding-states */
+ PP_ProcessEntryHeaders,
+ PP_PerformCheckMultipart,
+ PP_ProcessValueToBoundary,
+ PP_PerformCleanup,
+
+ /* nested post-encoding states */
+ PP_Nested_Init,
+ PP_Nested_PerformMarking,
+ PP_Nested_ProcessEntryHeaders,
+ PP_Nested_ProcessValueToBoundary,
+ PP_Nested_PerformCleanup,
+
};
+enum RN_State
+{
+ /**
+ * No RN-preprocessing in this state.
+ */
+ RN_Inactive = 0,
+
+ /**
+ * If the next character is '\n', skip it. Otherwise,
+ * just go inactive.
+ */
+ RN_OptN = 1,
+
+ /**
+ * Expect '\r\n' (and only '\r\n'). As always, we also
+ * expect only '\r' or only '\n'.
+ */
+ RN_Full = 2,
+
+ /**
+ * Expect either '\r\n' or '--\r\n'. If '--\r\n', transition into dash-state
+ * for the main state machine
+ */
+ RN_Dash = 3,
+
+ /**
+ * Got a single dash, expect second dash.
+ */
+ RN_Dash2 = 4,
+};
+
/**
- * Internal state of the post-processor.
+ * Bits for the globally known fields that
+ * should not be deleted when we exit the
+ * nested state.
+ */
+enum NE_State
+{
+ NE_none = 0,
+ NE_content_name = 1,
+ NE_content_type = 2,
+ NE_content_filename = 4,
+ NE_content_transfer_encoding = 8,
+};
+
+/**
+ * Internal state of the post-processor. Note that the fields
+ * are sorted by type to enable optimal packing by the compiler.
*/
struct MHD_PostProcessor
{
@@ -75,9 +134,19 @@
const char *encoding;
/**
+ * Primary boundary (points into encoding string)
+ */
+ const char * boundary;
+
+ /**
+ * Nested boundary (if we have multipart/mixed encoding).
+ */
+ char * nested_boundary;
+
+ /**
* Pointer to the name given in disposition.
*/
- char *content_disposition;
+ char *content_name;
/**
* Pointer to the (current) content type.
@@ -87,12 +156,12 @@
/**
* Pointer to the (current) filename.
*/
- char *filename;
+ char *content_filename;
/**
* Pointer to the (current) encoding.
*/
- char *transfer_encoding;
+ char *content_transfer_encoding;
/**
* Unprocessed value bytes due to escape
@@ -121,10 +190,40 @@
unsigned int value_offset;
/**
+ * strlen(boundary) -- if boundary != NULL.
+ */
+ size_t blen;
+
+ /**
+ * strlen(nested_boundary) -- if nested_boundary != NULL.
+ */
+ size_t nlen;
+
+ /**
* State of the parser.
*/
enum PP_State state;
+ /**
+ * Side-state-machine: skip '\r\n' (or just '\n').
+ * Set to 0 if we are not in skip mode. Set to 2
+ * if a '\r\n' is expected, set to 1 if a '\n' should
+ * be skipped if it is the next character.
+ */
+ enum RN_State skip_rn;
+
+ /**
+ * If we are in skip_rn with "dash" mode and
+ * do find 2 dashes, what state do we go into?
+ */
+ enum PP_State dash_state;
+
+ /**
+ * Which headers are global? (used to tell which
+ * headers were only valid for the nested multipart).
+ */
+ enum NE_State have;
+
};
@@ -153,6 +252,8 @@
{
struct MHD_PostProcessor *ret;
const char *encoding;
+ const char *boundary;
+ size_t blen;
if ((buffer_size < 256) || (connection == NULL) || (ikvi == NULL))
abort ();
@@ -161,30 +262,42 @@
MHD_HTTP_HEADER_CONTENT_TYPE);
if (encoding == NULL)
return NULL;
- if ((0 != strcasecmp (MHD_HTTP_POST_ENCODING_FORM_URLENCODED,
- encoding)) &&
- (0 != strncasecmp (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, encoding,
- strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA))))
- return NULL;
+ boundary = NULL;
+ if (0 != strcasecmp (MHD_HTTP_POST_ENCODING_FORM_URLENCODED,
+ encoding))
+ {
+ if (0 != strncasecmp (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA,
encoding,
+ strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)))
+ return NULL;
+ boundary =
+ &encoding[strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)];
+ /* Q: should this be "strcasestr"? */
+ if (NULL != strstr (boundary, "boundary="))
+ boundary = strstr (boundary, "boundary=") + strlen ("boundary=");
+ else
+ return NULL; /* failed to determine boundary */
+ blen = strlen (boundary);
+ if ( (blen == 0) ||
+ (blen * 2 + 2 > buffer_size) )
+ return NULL; /* (will be) out of memory or invalid boundary */
+ }
ret = malloc (sizeof (struct MHD_PostProcessor) + buffer_size + 1);
if (ret == NULL)
return NULL;
- memset (ret, 0, sizeof (struct MHD_PostProcessor));
+ memset (ret, 0, sizeof (struct MHD_PostProcessor) + buffer_size + 1);
ret->connection = connection;
ret->ikvi = ikvi;
ret->cls = cls;
ret->encoding = encoding;
ret->buffer_size = buffer_size;
ret->state = PP_Init;
+ ret->blen = blen;
+ ret->boundary = boundary;
+ ret->skip_rn = RN_Inactive;
return ret;
}
/**
- * On-stack buffer that we use for un-escaping of the value.
- */
-#define XBUF_SIZE 1024
-
-/**
* Process url-encoded POST data.
*/
static int
@@ -205,6 +318,12 @@
{
switch (pp->state)
{
+ case PP_Error:
+ return MHD_NO;
+ case PP_Done:
+ /* did not expect to receive more data */
+ pp->state = PP_Error;
+ return MHD_NO;
case PP_Init:
equals = 0;
while ((equals + poff < post_data_len) &&
@@ -223,10 +342,10 @@
pp->buffer_pos = 0; /* reset for next key */
MHD_http_unescape (buf);
poff += equals + 1;
- pp->state = PP_HaveKey;
+ pp->state = PP_ProcessValue;
pp->value_offset = 0;
break;
- case PP_HaveKey:
+ case PP_ProcessValue:
/* obtain rest of value from previous iteration */
memcpy (xbuf, pp->xbuf, pp->xbuf_pos);
xoff = pp->xbuf_pos;
@@ -301,12 +420,10 @@
{
poff++;
/* we are done, report error if we receive any more... */
- pp->state = PP_Error;
+ pp->state = PP_Done;
return MHD_YES;
}
return MHD_NO;
- case PP_Error:
- return MHD_NO;
default:
abort (); /* should never happen! */
}
@@ -323,6 +440,8 @@
static int
try_match_header (const char *prefix, char *line, char **suffix)
{
+ if (NULL != *suffix)
+ return MHD_NO;
while(*line != 0)
{
if (0 == strncasecmp (prefix, line, strlen (prefix)))
@@ -335,290 +454,534 @@
return MHD_NO;
}
+static int
+find_boundary(struct MHD_PostProcessor * pp,
+ const char * boundary,
+ size_t blen,
+ unsigned int * ioffptr,
+ enum PP_State next_state,
+ enum PP_State next_dash_state)
+{
+ char * buf = (char*) &pp[1];
+
+ if (pp->buffer_pos < 2 + blen)
+ {
+ if (pp->buffer_pos == pp->buffer_size)
+ pp->state = PP_Error; /* out of memory */
+ return MHD_NO; /* not enough data */
+ }
+ if ( (0 != memcmp ("--", buf, 2)) ||
+ (0 != memcmp (&buf[2], boundary, blen)))
+ {
+ pp->state = PP_Error;
+ return MHD_NO; /* expected boundary */
+ }
+ /* remove boundary from buffer */
+ (*ioffptr) += 2 + blen;
+ /* next: start with headers */
+ pp->skip_rn = RN_Dash;
+ pp->state = next_state;
+ pp->dash_state = next_dash_state;
+ return MHD_YES;
+}
+
/**
- * Decode multipart POST data.
+ * In buf, there maybe an expression
+ * '$key="$value"'. If that is the case,
+ * copy a copy of $value to destination.
+ *
+ * If destination is already non-NULL,
+ * do nothing.
+ */
+static void
+try_get_value(const char * buf,
+ const char * key,
+ char ** destination)
+{
+ const char * spos;
+ const char * bpos;
+ const char * endv;
+ size_t klen;
+ size_t vlen;
+
+ if (NULL != *destination)
+ return;
+ bpos = buf;
+ klen = strlen(key);
+ while (NULL != (spos = strstr(bpos, key)))
+ {
+ if ( (spos[klen] != '=') ||
+ ( (spos != buf) &&
+ (spos[-1] != ' ') ) )
+ {
+ /* no match */
+ bpos = spos + 1;
+ continue;
+ }
+ if (spos[klen + 1] != '"')
+ return; /* not quoted */
+ if (NULL == (endv = strstr(&spos[klen+2], "\"")))
+ return; /* no end-quote */
+ vlen = endv - spos - klen - 1;
+ *destination = malloc(vlen);
+ if (NULL == *destination)
+ return; /* out of memory */
+ (*destination)[vlen - 1] = '\0';
+ memcpy(*destination,
+ &spos[klen + 2],
+ vlen - 1);
+ return; /* success */
+ }
+}
+
+/**
+ * Go over the headers of the part and update
+ * the fields in "pp" according to what we find.
+ * If we are at the end of the headers (as indicated
+ * by an empty line), transition into next_state.
+ *
+ * @param ioffptr set to how many bytes have been
+ * processed
+ * @return MHD_YES if we can continue processing,
+ * MHD_NO on error or if we do not have
+ * enough data yet
+ */
+static int
+process_multipart_headers(struct MHD_PostProcessor * pp,
+ unsigned int * ioffptr,
+ enum PP_State next_state)
+{
+ char * buf = (char*) &pp[1];
+ unsigned int newline;
+
+ newline = 0;
+ while ((newline < pp->buffer_pos) &&
+ (buf[newline] != '\r') &&
+ (buf[newline] != '\n'))
+ newline++;
+ if (newline == pp->buffer_size)
+ {
+ pp->state = PP_Error;
+ return MHD_NO; /* out of memory */
+ }
+ if (newline == pp->buffer_pos)
+ return MHD_NO; /* will need more data */
+ if (newline == 0)
+ {
+ /* empty line - end of headers */
+ pp->skip_rn = RN_Full;
+ pp->state = next_state;
+ return MHD_YES;
+ }
+ /* got an actual header */
+ if (buf[newline] == '\r')
+ pp->skip_rn = RN_OptN;
+ buf[newline] = '\0';
+ if (0 == strncasecmp("Content-disposition: ",
+ buf,
+ strlen("Content-disposition: ")))
+ {
+ try_get_value(&buf[strlen("Content-disposition: ")],
+ "name",
+ &pp->content_name);
+ try_get_value(&buf[strlen("Content-disposition: ")],
+ "filename",
+ &pp->content_filename);
+ }
+ else
+ {
+ try_match_header ("Content-type: ", buf, &pp->content_type);
+ try_match_header ("Content-Transfer-Encoding: ",
+ buf, &pp->content_transfer_encoding);
+}
+ (*ioffptr) += newline + 1;
+ return MHD_YES;
+}
+
+/**
+ * We have the value until we hit the given boundary;
+ * process accordingly.
*
- * TODO: If the content-type is multipart/mixed, we do not do anything
- * special. However, we should probably break the individual values
- * apart and give them to the callback individually (will require some
- * additional states & state).
- *
- * See http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4
+ * @param boundary the boundary to look for
+ * @param blen strlen(boundary)
+ * @param next_state what state to go into after the
+ * boundary was found
+ * @param next_dash_state state to go into if the next
+ * boundary ends with "--"
+ * @return MHD_YES if we can continue processing,
+ * MHD_NO on error or if we do not have
+ * enough data yet
*/
static int
+process_value_to_boundary(struct MHD_PostProcessor * pp,
+ unsigned int * ioffptr,
+ const char * boundary,
+ size_t blen,
+ enum PP_State next_state,
+ enum PP_State next_dash_state)
+{
+ char * buf = (char*) &pp[1];
+ unsigned int newline;
+
+ /* all data in buf until the boundary
+ (\r\n--+boundary) is part of the value */
+ newline = 0;
+ while (1)
+ {
+ while ((newline + 4 < pp->buffer_pos) &&
+ (0 != memcmp ("\r\n--", &buf[newline], 4)))
+ newline++;
+ if (newline + pp->blen + 4 <= pp->buffer_pos)
+ {
+ /* can check boundary */
+ if (0 != memcmp (&buf[newline + 4], boundary, pp->blen))
+ {
+ /* no boundary, "\r\n--" is part of content, skip */
+ newline += 4;
+ continue;
+ }
+ else
+ {
+ /* boundary found, process until newline then
+ skip boundary and go back to init */
+ pp->skip_rn = RN_Dash;
+ pp->state = next_state;
+ pp->dash_state = next_dash_state;
+ (*ioffptr) += pp->blen + 4; /* skip boundary as well */
+ break;
+ }
+ }
+ else
+ {
+ /* cannot check for boundary, process content that
+ we have and check again later; except, if we have
+ no content, abort (out of memory) */
+ if ( (newline == 0) &&
+ (pp->buffer_pos == pp->buffer_size) )
+ {
+ pp->state = PP_Error;
+ return MHD_NO;
+ }
+ return MHD_NO;
+ }
+ }
+ /* newline is either at beginning of boundary or
+ at least at the last character that we are sure
+ is not part of the boundary */
+ if (MHD_NO == pp->ikvi (pp->cls,
+ MHD_POSTDATA_KIND,
+ pp->content_name,
+ pp->content_filename,
+ pp->content_type,
+ pp->content_transfer_encoding,
+ buf,
+ pp->value_offset, newline))
+ {
+ pp->state = PP_Error;
+ return MHD_NO;
+ }
+ pp->value_offset += newline;
+ (*ioffptr) += newline;
+ return MHD_YES;
+}
+
+static void
+free_unmarked(struct MHD_PostProcessor * pp)
+{
+ if ( (pp->content_name != NULL) &&
+ (0 == (pp->have & NE_content_name)) )
+ {
+ free(pp->content_name);
+ pp->content_name = NULL;
+ }
+ if ( (pp->content_type != NULL) &&
+ (0 == (pp->have & NE_content_type)) )
+ {
+ free(pp->content_type);
+ pp->content_type = NULL;
+ }
+ if ( (pp->content_filename != NULL) &&
+ (0 == (pp->have & NE_content_filename)) )
+ {
+ free(pp->content_filename);
+ pp->content_filename = NULL;
+ }
+ if ( (pp->content_transfer_encoding != NULL) &&
+ (0 == (pp->have & NE_content_transfer_encoding)) )
+ {
+ free(pp->content_transfer_encoding);
+ pp->content_transfer_encoding = NULL;
+ }
+}
+
+/**
+ * Decode multipart POST data.
+ */
+static int
post_process_multipart (struct MHD_PostProcessor *pp,
const char *post_data, unsigned int post_data_len)
{
char *buf;
- const char *boundary;
unsigned int max;
unsigned int ioff;
unsigned int poff;
- unsigned int newline;
- unsigned int endquote;
- size_t blen;
buf = (char *) &pp[1];
ioff = 0;
poff = 0;
- boundary =
- &pp->encoding[strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)];
- /* Q: should this be "strcasestr"? */
- if (NULL != strstr (boundary, "boundary="))
- boundary = strstr (boundary, "boundary=") + strlen ("boundary=");
- else
- return MHD_NO; /* failed to determine boundary */
- blen = strlen (boundary);
- if (blen * 2 + 2 > pp->buffer_size)
- return MHD_NO; /* (will be) out of memory */
- while ((poff < post_data_len) || (pp->buffer_pos > ioff))
+ max = 1;
+ while ( (poff < post_data_len) ||
+ ( (pp->buffer_pos > 0) &&
+ (max != 0) ) )
{
- /* first, move data to our internal buffer */
+ /* first, move as much input data
+ as possible to our internal buffer */
max = pp->buffer_size - pp->buffer_pos;
- if ((max < ioff) && (max < post_data_len - poff))
- {
- memmove (buf, &buf[ioff], pp->buffer_pos - ioff);
- pp->buffer_pos -= ioff;
- ioff = 0;
- max = pp->buffer_size - pp->buffer_pos;
- }
if (max > post_data_len - poff)
max = post_data_len - poff;
memcpy (&buf[pp->buffer_pos], &post_data[poff], max);
poff += max;
pp->buffer_pos += max;
+ if ( (max == 0) &&
+ (poff < post_data_len) )
+ {
+ pp->state = PP_Error;
+ return MHD_NO; /* out of memory */
+ }
+ /* first state machine for '\r'-'\n' and '--' handling */
+ switch (pp->skip_rn)
+ {
+ case RN_Inactive:
+ break;
+ case RN_OptN:
+ if (buf[0] == '\n')
+ {
+ ioff++;
+ pp->skip_rn = RN_Inactive;
+ goto AGAIN;
+ }
+ case RN_Dash:
+ if (buf[0] == '-')
+ {
+ ioff++;
+ pp->skip_rn = RN_Dash2;
+ goto AGAIN;
+ }
+ pp->skip_rn = RN_Full;
+ /* fall-through! */
+ case RN_Full:
+ if (buf[0] == '\r')
+ {
+ if ( (pp->buffer_pos > 1) &&
+ (buf[1] == '\n') )
+ {
+ pp->skip_rn = RN_Inactive;
+ ioff += 2;
+ }
+ else
+ {
+ pp->skip_rn = RN_OptN;
+ ioff++;
+ }
+ goto AGAIN;
+ }
+ if (buf[0] == '\n')
+ {
+ ioff++;
+ pp->skip_rn = RN_Inactive;
+ goto AGAIN;
+ }
+ pp->skip_rn = RN_Inactive;
+ pp->state = PP_Error;
+ return MHD_NO; /* no '\r\n' */
+ case RN_Dash2:
+ if (buf[0] == '-')
+ {
+ ioff++;
+ pp->skip_rn = RN_Full;
+ pp->state = pp->dash_state;
+ goto AGAIN;
+ }
+ pp->state = PP_Error;
+ break;
+ }
+
+ /* main state engine */
switch (pp->state)
- {
- case PP_Init:
- /* we're looking for the boundary */
- if (pp->buffer_pos < 2 + blen + ioff)
- goto END;
- if ((0 != memcmp ("--", &buf[ioff], 2)) ||
- (0 != memcmp (&buf[ioff + 2], boundary, blen)))
- return MHD_NO; /* expected boundary */
-
- /* remove boundary from buffer */
- ioff += 2 + blen;
-
- /* next: start with headers */
- pp->state = PP_ExpectNewLineR;
+ {
+ case PP_Error:
+ return MHD_NO;
+ case PP_Done:
+ /* did not expect to receive more data */
+ pp->state = PP_Error;
+ return MHD_NO;
+ case PP_Init:
+ if (MHD_NO == find_boundary(pp,
+ pp->boundary,
+ pp->blen,
+ &ioff,
+ PP_ProcessEntryHeaders,
+ PP_Done))
+ {
+ if (pp->state == PP_Error)
+ return MHD_NO;
+ goto END;
+ }
+ break;
+ case PP_ProcessEntryHeaders:
+ if (MHD_NO == process_multipart_headers(pp, &ioff,
PP_PerformCheckMultipart))
+ {
+ if (pp->state == PP_Error)
+ return MHD_NO;
+ else
+ goto END;
+ }
+ max = 1;
break;
- case PP_ExpectNewLineR:
- if (buf[ioff] == '-')
- {
- /* last boundary ends with "--" */
- ioff++;
- pp->state = PP_FinalDash;
- break;
- }
- if (buf[ioff] == '\r')
- {
- ioff++;
- pp->state = PP_ExpectNewLineNOPT;
- break;
- }
- /* fall through! */
- case PP_ExpectNewLineN:
- if (buf[ioff] == '\n')
- {
- ioff++;
- pp->state = PP_Headers;
- break;
- }
- return MHD_NO;
- case PP_ExpectNewLineNOPT:
- if (buf[ioff] == '\n')
- {
- ioff++;
- pp->state = PP_Headers;
- break;
- }
- /* fall through! */
- case PP_Headers:
- newline = 0;
- while ((newline + ioff < pp->buffer_pos) &&
- (buf[newline + ioff] != '\r') &&
- (buf[newline + ioff] != '\n'))
- newline++;
- if (newline == pp->buffer_size)
- return MHD_NO; /* out of memory */
- if (newline + ioff == pp->buffer_pos)
- {
- /* try to make more room */
- memmove (buf, &buf[ioff], pp->buffer_pos - ioff);
- pp->buffer_pos -= ioff;
- ioff = 0;
- break;
- }
- if (newline == 0)
- {
- pp->state = PP_SkipRN;
- break;
- }
- buf[ioff + newline] = '\0';
- if ((MHD_YES
- == try_match_header ("Content-Disposition: form-data; name=\"",
- &buf[ioff],
- &pp->content_disposition)) &&
- (pp->content_disposition != NULL) &&
- (0 < strlen (pp->content_disposition)))
- {
- /* find end-quote; then check if we also have a filename! */
- endquote = 0;
- while ((pp->content_disposition[endquote] != '\"') &&
- (pp->content_disposition[endquote] != '\0'))
- endquote++;
- pp->content_disposition[endquote++] = '\0'; /* remove
end-quote */
- if ((MHD_YES
- == try_match_header (" filename=\"",
- &pp->content_disposition[endquote],
- &pp->filename)) &&
- (pp->filename != NULL) && (0 < strlen (pp->filename)))
- pp->filename[strlen (pp->filename) - 1] = '\0'; /* remove
end-quote */
- }
- try_match_header ("Content-Type: ", &buf[ioff], &pp->content_type);
- try_match_header ("Content-Transfer-Encoding: ",
- &buf[ioff], &pp->transfer_encoding);
- ioff += newline + 1;
- pp->state = PP_ExpectNewLineNOPT;
+ case PP_PerformCheckMultipart:
+ if ( (pp->content_type != NULL) &&
+ (0 == strncasecmp(pp->content_type,
+ "multipart/mixed",
+ strlen("multipart/mixed")) ) )
+ {
+ pp->nested_boundary = strstr(pp->content_type,
+ "boundary=");
+ if (pp->nested_boundary == NULL)
+ {
+ pp->state = PP_Error;
+ return MHD_NO;
+ }
+ pp->nested_boundary =
strdup(&pp->nested_boundary[strlen("boundary=")]);
+ if (pp->nested_boundary == NULL)
+ {
+ /* out of memory */
+ pp->state = PP_Error;
+ return MHD_NO;
+ }
+ /* free old content type, we will need that field
+ for the content type of the nested elements */
+ free(pp->content_type);
+ pp->content_type = NULL;
+ pp->nlen = strlen(pp->nested_boundary);
+ pp->state = PP_Nested_Init;
+ max = 1;
+ break;
+ }
+ pp->state = PP_ProcessValueToBoundary;
+ pp->value_offset = 0;
+ max = 1;
+ break;
+ case PP_ProcessValueToBoundary:
+ if (MHD_NO == process_value_to_boundary(pp,
+ &ioff,
+ pp->boundary,
+ pp->blen,
+ PP_PerformCleanup,
+ PP_Done))
+ {
+ if (pp->state == PP_Error)
+ return MHD_NO;
+ break;
+ }
+ break;
+ case PP_PerformCleanup:
+ /* clean up state of one multipart form-data element! */
+ pp->have = NE_none;
+ free_unmarked(pp);
+ if (pp->nested_boundary != NULL)
+ {
+ free (pp->nested_boundary);
+ pp->nested_boundary = NULL;
+ }
+ pp->state = PP_ProcessEntryHeaders;
+ max = 1;
+ break;
+ case PP_Nested_Init:
+ if (pp->nested_boundary == NULL)
+ {
+ pp->state = PP_Error;
+ return MHD_NO;
+ }
+ if (MHD_NO == find_boundary(pp,
+ pp->nested_boundary,
+ pp->nlen,
+ &ioff,
+ PP_Nested_PerformMarking,
+ PP_Init /* or PP_Error? */))
+ {
+ if (pp->state == PP_Error)
+ return MHD_NO;
+ goto END;
+ }
+ break;
+ case PP_Nested_PerformMarking:
+ /* remember what headers were given
+ globally */
+ pp->have = NE_none;
+ if (pp->content_name != NULL)
+ pp->have |= NE_content_name;
+ if (pp->content_type != NULL)
+ pp->have |= NE_content_type;
+ if (pp->content_filename != NULL)
+ pp->have |= NE_content_filename;
+ if (pp->content_transfer_encoding != NULL)
+ pp->have |= NE_content_transfer_encoding;
+ pp->state = PP_Nested_ProcessEntryHeaders;
+ max = 1;
+ break;
+ case PP_Nested_ProcessEntryHeaders:
+ pp->value_offset = 0;
+ if (MHD_NO == process_multipart_headers(pp, &ioff,
PP_Nested_ProcessValueToBoundary))
+ {
+ if (pp->state == PP_Error)
+ return MHD_NO;
+ else
+ goto END;
+ }
+ max = 1;
break;
- case PP_SkipRN:
- if (buf[ioff] == '\r')
- {
- ioff++;
- pp->state = PP_SkipN;
- break;
- }
- /* fall through! */
- case PP_SkipN:
- if (buf[ioff] == '\n')
- {
- ioff++;
- pp->state = PP_ValueToBoundary;
- pp->value_offset = 0;
- break;
- }
- return MHD_NO; /* parse error */
- case PP_ValueToBoundary:
- /* all data in buf until the boundary
- (\r\n--+boundary) is part of the value */
- newline = 0;
- while (1)
- {
- while ((newline + ioff + 4 < pp->buffer_pos) &&
- (0 != memcmp ("\r\n--", &buf[newline + ioff], 4)))
- newline++;
- if (newline + blen + 4 > pp->buffer_size)
- {
- /* boundary not in sight --
- process data, then make room for more! */
- if (MHD_NO == pp->ikvi (pp->cls,
- MHD_POSTDATA_KIND,
- pp->content_disposition,
- pp->filename,
- pp->content_type,
- pp->transfer_encoding,
- &buf[ioff],
- pp->value_offset, newline))
- {
- pp->state = PP_Error;
- break;
- }
- pp->value_offset += newline;
- ioff += newline;
- memmove (buf, &buf[ioff], pp->buffer_pos - ioff);
- pp->buffer_pos -= ioff;
- ioff = 0;
- break;
- }
- if (newline + blen + 4 < pp->buffer_pos)
- {
- /* can check for boundary right now! */
- if (0 == memcmp (&buf[newline + ioff + 4], boundary, blen))
- {
- /* found: process data, then look for more */
- if (MHD_NO == pp->ikvi (pp->cls,
- MHD_POSTDATA_KIND,
- pp->content_disposition,
- pp->filename,
- pp->content_type,
- pp->transfer_encoding,
- &buf[ioff],
- pp->value_offset, newline))
- {
- pp->state = PP_Error;
- break;
- }
-
- /* clean up! */
- if (pp->content_type != NULL)
- {
- free (pp->content_type);
- pp->content_type = NULL;
- }
- if (pp->content_disposition != NULL)
- {
- free (pp->content_disposition);
- pp->content_disposition = NULL;
- }
- if (pp->filename != NULL)
- {
- free (pp->filename);
- pp->filename = NULL;
- }
- if (pp->transfer_encoding != NULL)
- {
- free (pp->transfer_encoding);
- pp->transfer_encoding = NULL;
- }
- pp->value_offset = 0;
- ioff += newline + 2; /* skip data + new line */
- pp->state = PP_Init;
- break;
- }
- /* not the boundary, look further! */
- newline += 4;
- continue;
- }
- goto END;
- }
- break;
- case PP_FinalDash:
- if (buf[ioff] == '-')
- {
- /* last boundary ends with "--" */
- ioff++;
- pp->state = PP_FinalRN;
- break;
- }
- return MHD_NO; /* parse error */
- case PP_FinalRN:
- if (buf[ioff] == '\r')
- {
- ioff++;
- pp->state = PP_FinalN;
- break;
- }
- /* fall through! */
- case PP_FinalN:
- if (buf[ioff] == '\n')
- {
- ioff++;
- pp->state = PP_Error;
- break;
- }
- return MHD_NO; /* parse error */
- case PP_Error:
- return MHD_NO;
+ case PP_Nested_ProcessValueToBoundary:
+ if (MHD_NO == process_value_to_boundary(pp,
+ &ioff,
+ pp->nested_boundary,
+ pp->nlen,
+ PP_Nested_PerformCleanup,
+ PP_Init))
+ {
+ if (pp->state == PP_Error)
+ return MHD_NO;
+ break;
+ }
+ break;
+ case PP_Nested_PerformCleanup:
+ free_unmarked(pp);
+ pp->state = PP_Nested_ProcessEntryHeaders;
+ max = 1;
+ break;
default:
- abort (); /* should never happen! */
-
+ abort (); /* should never happen! */
}
+AGAIN:
+ if (ioff > 0)
+ {
+ memmove (buf, &buf[ioff], pp->buffer_pos - ioff);
+ pp->buffer_pos -= ioff;
+ ioff = 0;
+ max = 1;
+ }
}
END:
- memmove (buf, &buf[ioff], pp->buffer_pos - ioff);
- pp->buffer_pos -= ioff;
+ if (ioff != 0)
+ {
+ memmove (buf, &buf[ioff], pp->buffer_pos - ioff);
+ pp->buffer_pos -= ioff;
+ }
+ if (poff < post_data_len)
+ {
+ pp->state = PP_Error;
+ return MHD_NO; /* serious error */
+ }
return MHD_YES;
}
@@ -661,14 +1024,10 @@
/* These internal strings need cleaning up since
the post-processing may have been interrupted
at any stage */
- if (pp->content_type != NULL)
- free (pp->content_type);
- if (pp->content_disposition != NULL)
- free (pp->content_disposition);
- if (pp->filename != NULL)
- free (pp->filename);
- if (pp->transfer_encoding != NULL)
- free (pp->transfer_encoding);
+ pp->have = NE_none;
+ free_unmarked(pp);
+ if (pp->nested_boundary != NULL)
+ free(pp->nested_boundary);
free (pp);
}
Modified: libmicrohttpd/src/daemon/postprocessor_test.c
===================================================================
--- libmicrohttpd/src/daemon/postprocessor_test.c 2008-01-30 21:13:59 UTC
(rev 6131)
+++ libmicrohttpd/src/daemon/postprocessor_test.c 2008-01-31 06:16:41 UTC
(rev 6132)
@@ -85,9 +85,11 @@
int * want_off = cls;
int idx = *want_off;
+#if 0
fprintf(stderr,
"VC: `%s' `%s' `%s' `%s' `%.*s'\n",
key, filename, content_type, transfer_encoding, size, data);
+#endif
if (size == 0)
return MHD_YES;
if ( (idx < 0) ||
@@ -213,8 +215,9 @@
main (int argc, char *const *argv)
{
unsigned int errorCount = 0;
+
errorCount += test_urlencoding();
- errorCount += test_multipart();
+ errorCount += test_multipart();
errorCount += test_nested_multipart();
if (errorCount != 0)
fprintf (stderr, "Error (code: %u)\n", errorCount);
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] r6132 - in libmicrohttpd: . src/daemon,
gnunet <=