aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWolfgang Draxinger <Wolfgang.Draxinger@physik.uni-muenchen.de>2013-06-28 18:14:16 +0200
committerWolfgang Draxinger <Wolfgang.Draxinger@physik.uni-muenchen.de>2013-06-28 18:14:16 +0200
commitf9cc5128f5e9eb726b8562d33067ddce6d65385c (patch)
tree18c2039d9e4c893a9cf244e379b6a8aba5db8d3c
parentffa2fc800d92b40f4a128814ae55b121a7852e58 (diff)
downloadlitheweb-f9cc5128f5e9eb726b8562d33067ddce6d65385c.tar.gz
litheweb-f9cc5128f5e9eb726b8562d33067ddce6d65385c.tar.bz2
multipart code works
-rw-r--r--picohttp.c322
-rw-r--r--picohttp.h46
-rw-r--r--test/bsdsocket.c32
3 files changed, 237 insertions, 163 deletions
diff --git a/picohttp.c b/picohttp.c
index 50a864e..fe50424 100644
--- a/picohttp.c
+++ b/picohttp.c
@@ -35,7 +35,7 @@ static char const PICOHTTP_STR_CONTENT[] = "Content";
static char const PICOHTTP_STR__TYPE[] = "-Type";
static char const PICOHTTP_STR__LENGTH[] = "-Length";
static char const PICOHTTP_STR__CODING[] = "-Coding";
-
+static char const PICOHTTP_STR__DISPOSITION[] = "-Disposition";
static char const PICOHTTP_STR_APPLICATION_[] = "application/";
static char const PICOHTTP_STR_TEXT_[] = "text/";
@@ -52,6 +52,7 @@ static char const PICOHTTP_STR_DATE[] = "Date";
static char const PICOHTTP_STR_EXPECT[] = "Expect";
static char const PICOHTTP_STR_BOUNDARY[] = " boundary=";
+static char const PICOHTTP_STR_NAME__[] = " name=\"";
static char const PICOHTTP_STR_CHUNKED[] = "chunked";
@@ -227,7 +228,7 @@ static int16_t picohttpIoGetPercentCh(
int16_t picohttpGetch(struct picohttpRequest * const req)
{
- /* read HTTP query body, skipping over Chunked Transfer Boundaries
+ /* TODO: skipping over Chunked Transfer Boundaries
* if Chunked Transfer Encoding is used */
uint16_t ch = picohttpIoGetch(req->ioops);
@@ -239,6 +240,22 @@ int16_t picohttpGetch(struct picohttpRequest * const req)
return ch;
}
+int picohttpRead(struct picohttpRequest * const req, size_t len, char * const buf)
+{
+ /* TODO: skipping over Chunked Transfer Boundaries
+ * if Chunked Transfer Encoding is used */
+ int r = picohttpIoRead(req->ioops, len, buf);
+
+ if( 5 < r ) {
+ memmove(req->query.prev_ch + r, req->query.prev_ch, 5-r);
+ memcpy(req->query.prev_ch, buf, r);
+ } else if (0 < r) {
+ memcpy(req->query.prev_ch, buf + len - 5, 5);
+ }
+
+ return r;
+}
+
/* TODO:
* It is possible to do in-place pattern matching on the route definition
* array, without first reading in the URL and then processing it here.
@@ -529,32 +546,43 @@ static int16_t picohttpProcessHTTPVersion (
return ch;
}
-static void picohttpProcessContentType(
- struct picohttpRequest * const req,
- char const *contenttype )
+static uint16_t picohttpProcessContentType(
+ char const **contenttype)
{
- if(!strncmp(contenttype,
+ uint16_t ct = 0;
+ if(!strncmp(*contenttype,
PICOHTTP_STR_APPLICATION_, sizeof(PICOHTTP_STR_APPLICATION_)-1)) {
+ ct = PICOHTTP_CONTENTTYPE_APPLICATION;
}
- if(!strncmp(contenttype,
+ if(!strncmp(*contenttype,
PICOHTTP_STR_TEXT_, sizeof(PICOHTTP_STR_TEXT_)-1)) {
+ ct = PICOHTTP_CONTENTTYPE_TEXT;
}
- if(!strncmp(contenttype, PICOHTTP_STR_MULTIPART_,
+ if(!strncmp(*contenttype, PICOHTTP_STR_MULTIPART_,
sizeof(PICOHTTP_STR_MULTIPART_)-1)) {
- contenttype += sizeof(PICOHTTP_STR_MULTIPART_)-1;
- req->query.contenttype =
- PICOHTTP_CONTENTTYPE_MULTIPART;
+ ct = PICOHTTP_CONTENTTYPE_MULTIPART;
+ *contenttype += sizeof(PICOHTTP_STR_MULTIPART_)-1;
- if(!strncmp(contenttype,PICOHTTP_STR_FORMDATA,
+ if(!strncmp(*contenttype,PICOHTTP_STR_FORMDATA,
sizeof(PICOHTTP_STR_FORMDATA)-1)) {
- contenttype += sizeof(PICOHTTP_STR_FORMDATA)-1;
+ *contenttype += sizeof(PICOHTTP_STR_FORMDATA)-1;
- req->query.contenttype =
- PICOHTTP_CONTENTTYPE_MULTIPART_FORMDATA;
+ ct = PICOHTTP_CONTENTTYPE_MULTIPART_FORMDATA;
}
+ }
+ return ct;
+}
+
+static void picohttpProcessHeaderContentType(
+ struct picohttpRequest * const req,
+ char const *contenttype )
+{
+ req->query.contenttype = picohttpProcessContentType(&contenttype);
+
+ if( PICOHTTP_CONTENTTYPE_MULTIPART == (req->query.contenttype & 0xf000) ) {
char *boundary = strstr(contenttype, PICOHTTP_STR_BOUNDARY);
if(boundary) {
/* see RFC1521 regarding maximum length of boundary */
@@ -569,10 +597,11 @@ static void picohttpProcessContentType(
}
static void picohttpProcessHeaderField(
- struct picohttpRequest * const req,
+ void * const data,
char const *headername,
char const *headervalue)
{
+ struct picohttpRequest * const req = data;
debug_printf("%s: %s\n", headername, headervalue);
if(!strncmp(headername,
PICOHTTP_STR_CONTENT,
@@ -588,7 +617,7 @@ static void picohttpProcessHeaderField(
/* Content Type */
if(!strncmp(headername,
PICOHTTP_STR__TYPE, sizeof(PICOHTTP_STR__TYPE)-1)) {
- picohttpProcessContentType(req, headervalue);
+ picohttpProcessHeaderContentType(req, headervalue);
return;
}
return;
@@ -615,6 +644,7 @@ static void picohttpProcessHeaderField(
static int16_t picohttpProcessHeaders (
struct picohttpRequest * const req,
picohttpHeaderFieldCallback headerfieldcallback,
+ void * const data,
int16_t ch )
{
#define PICOHTTP_HEADERNAME_MAX_LEN 32
@@ -651,7 +681,7 @@ static int16_t picohttpProcessHeaders (
} else {
if( *headername && *headervalue )
headerfieldcallback(
- req,
+ data,
headername,
headervalue );
/* new header field */
@@ -690,7 +720,7 @@ static int16_t picohttpProcessHeaders (
}
if( *headername && *headervalue )
headerfieldcallback(
- req,
+ data,
headername,
headervalue );
@@ -752,7 +782,6 @@ void picohttpProcessRequest (
if( 0 > (ch = picohttpProcessURL(&request, url_max_length, ch)) )
goto http_error;
-
if( !picohttpMatchRoute(&request, routes) || !request.route ) {
ch = -PICOHTTP_STATUS_404_NOT_FOUND;
goto http_error;
@@ -774,7 +803,11 @@ void picohttpProcessRequest (
goto http_error;
}
- if( 0 > (ch = picohttpProcessHeaders(&request, picohttpProcessHeaderField, ch)) )
+ if( 0 > (ch = picohttpProcessHeaders(
+ &request,
+ picohttpProcessHeaderField,
+ &request,
+ ch)) )
goto http_error;
if( '\r' == ch ) {
@@ -788,8 +821,8 @@ void picohttpProcessRequest (
request.query.prev_ch[0] = '\n';
request.query.prev_ch[1] = '\r';
- request.query.prev_ch[2] = '\n';
- request.query.prev_ch[3] = '\r';
+ request.query.prev_ch[2] =
+ request.query.prev_ch[3] =
request.query.prev_ch[4] = 0;
request.status = PICOHTTP_STATUS_200_OK;
@@ -925,6 +958,9 @@ int16_t picohttpMultipartGetch(
struct picohttpMultipart * const mp)
{
uint16_t ch;
+ if( mp->finished ) {
+ return -1;
+ } else
if( 0 < mp->replay ) {
if( mp->replayhead < mp->replay ) {
ch = mp->req->query.multipartboundary[mp->replayhead];
@@ -936,8 +972,6 @@ int16_t picohttpMultipartGetch(
mp->replayhead = 0;
return ch;
}
- } else if( mp->finished ) {
- return -1;
} else {
ch = picohttpGetch(mp->req);
@@ -950,51 +984,18 @@ int16_t picohttpMultipartGetch(
mp->replay = 0;
if( '\r' == ch ) {
- debug_printf("'CR'");
- #if PICOHTTP_CRLFCRLF
- if( '\n' == mp->req->query.prev_ch[1]
- #if PICOHTTP_STRICT_CRLF_MULTIPART_BOUNDARY_PREFIX
- && '\r' == mp->req->query.prev_ch[2]
- #endif
- ) {
- mp->replayhead =
- mp->in_boundary = 2;
- } else
- #endif
- {
- mp->replayhead =
- mp->in_boundary = 0;
- }
+ mp->replayhead =
+ mp->in_boundary = 0;
} else
if( '\n' == ch &&
'\r' == mp->req->query.prev_ch[1] ) {
- debug_printf("'LF'");
- #if PICOHTTP_CRLFCRLF
- if( '\n' == mp->req->query.prev_ch[2]
- #if PICOHTTP_STRICT_CRLF_MULTIPART_BOUNDARY_PREFIX
- && '\r' == mp->req->query.prev_ch[3]
- #endif
- ) {
- mp->replayhead =
- mp->in_boundary = 3;
- } else
- #endif
- {
- mp->replayhead =
- mp->in_boundary = 1;
- }
+ mp->replayhead =
+ mp->in_boundary = 1;
} else
if( '-' == ch &&
'\n' == mp->req->query.prev_ch[1] &&
'\r' == mp->req->query.prev_ch[2]
-#if PICOHTTP_CRLFCRLF
- && '\n' == mp->req->query.prev_ch[3]
- #if PICOHTTP_STRICT_CRLF_MULTIPART_BOUNDARY_PREFIX
- && '\r' == mp->req->query.prev_ch[4]
- #endif
-#endif
) {
- debug_printf("'-'");
mp->replayhead =
mp->in_boundary = 2;
}
@@ -1032,7 +1033,7 @@ int16_t picohttpMultipartGetch(
/* In case the mismatch was due to a <CR> or <LF>
* or '-' character, it must be checked, if this may be
* preceeded by some <CR><LF>* sequence that would
- * allow to be a valid multipart boundary. This
+ * allow to be a valid multipart boundary.
* In that case the exact replay parameters depend
* on the exact combination.
*
@@ -1050,51 +1051,21 @@ int16_t picohttpMultipartGetch(
* is a nasty, convoluted state machine
*/
if( '\r' == ch ) {
- #if PICOHTTP_CRLFCRLF
- if( '\n' == mp->req->query.prev_ch[1]
- #if PICOHTTP_STRICT_CRLF_MULTIPART_BOUNDARY_PREFIX
- && '\r' == mp->req->query.prev_ch[2]
- #endif
- ) {
- mp->replay = mp->in_boundary - 3;
- mp->in_boundary = 3;
- } else
- #endif
- {
- mp->replay = mp->in_boundary - 1;
- mp->in_boundary = 1;
- }
+ mp->replay = mp->in_boundary - 1;
+ mp->in_boundary = 1;
mp->req->query.prev_ch[0] =
mp->req->query.multipartboundary[mp->replay];
} else
if( '\n' == ch &&
'\r' == mp->req->query.prev_ch[1] ) {
- #if PICOHTTP_CRLFCRLF
- if( '\n' == mp->req->query.prev_ch[2]
- #if PICOHTTP_STRICT_CRLF_MULTIPART_BOUNDARY_PREFIX
- && '\r' == mp->req->query.prev_ch[3]
- #endif
- ) {
- mp->replay = mp->in_boundary - 4;
- mp->in_boundary = 4;
- } else
- #endif
- {
- mp->replay = mp->in_boundary - 2;
- mp->in_boundary = 2;
- }
+ mp->replay = mp->in_boundary - 2;
+ mp->in_boundary = 2;
mp->req->query.prev_ch[0] =
mp->req->query.multipartboundary[mp->replay];
} else
if( '-' == ch &&
'\n' == mp->req->query.prev_ch[1] &&
'\r' == mp->req->query.prev_ch[2]
- #if PICOHTTP_CRLFCRLF
- && '\n' == mp->req->query.prev_ch[3]
- #if PICOHTTP_STRICT_CRLF_MULTIPART_BOUNDARY_PREFIX
- && '\r' == mp->req->query.prev_ch[4]
- #endif
- #endif
) {
mp->replay = mp->in_boundary - 4;
mp->in_boundary = 2;
@@ -1113,76 +1084,161 @@ int16_t picohttpMultipartGetch(
return ch;
}
+int picohttpMultipartRead(
+ struct picohttpMultipart * const mp,
+ size_t len,
+ char * const buf)
+{
+/* TODO: Replace this with a dedicated variant processing whole buffers?
+ * Probably a lot of code would be shared with the ...Getch variant
+ * and could be placed into a commonly used function.
+ */
+ uint16_t ch;
+ size_t i;
+ for(i = 0; i < len; i++) {
+ if( 0 > (ch = picohttpMultipartGetch(mp)) ) {
+ if( mp->finished )
+ return 0;
+ else
+ return ch;
+ }
+
+ buf[i] = ch;
+ }
+ return i;
+}
+
+static void picohttpProcessMultipartContentType(
+ struct picohttpMultipart * const mp,
+ char const *contenttype )
+{
+ mp->contenttype = picohttpProcessContentType(&contenttype);
+
+ if( PICOHTTP_CONTENTTYPE_MULTIPART == (mp->contenttype & 0xf000) ) {
+ }
+}
+
+static void picohttpProcessMultipartContentDisposition(
+ struct picohttpMultipart * const mp,
+ char const *disposition )
+{
+ char const *name = strstr(disposition, PICOHTTP_STR_NAME__);
+ if(name) {
+ name += sizeof(PICOHTTP_STR_NAME__)-1;
+ char const * const nameend = strchr(name, '"');
+ if(nameend) {
+ size_t len = nameend - name;
+ if( PICOHTTP_DISPOSITION_NAME_MAX < len )
+ len = PICOHTTP_DISPOSITION_NAME_MAX;
+
+ strncpy(mp->disposition.name, name, len);
+ }
+ }
+}
+
static void picohttpMultipartHeaderField(
- struct picohttpRequest * const req,
+ void * const data,
char const *headername,
char const *headervalue)
{
- debug_printf("%s: %s\n", headername, headervalue);
+ struct picohttpMultipart * const mp = data;
+ if(!strncmp(headername,
+ PICOHTTP_STR_CONTENT,
+ sizeof(PICOHTTP_STR_CONTENT)-1)) {
+ headername += sizeof(PICOHTTP_STR_CONTENT)-1;
+ /* Content Length
+ * TODO: Is this a header actually defined for multipart bodies?
+ * Anyway, even if it's not defined, this has not negative
+ * side effects, so why care about it. Worst it can do it
+ * be usefull later.
+ */
+ if(!strncmp(headername,
+ PICOHTTP_STR__LENGTH, sizeof(PICOHTTP_STR__LENGTH)-1)) {
+ return;
+ }
+
+ /* Content Disposition */
+ if(!strncmp(headername,
+ PICOHTTP_STR__DISPOSITION, sizeof(PICOHTTP_STR__DISPOSITION)-1)) {
+ picohttpProcessMultipartContentDisposition(mp, headervalue);
+ return;
+ }
+
+ /* Content Type */
+ if(!strncmp(headername,
+ PICOHTTP_STR__TYPE, sizeof(PICOHTTP_STR__TYPE)-1)) {
+ picohttpProcessMultipartContentType(mp, headervalue);
+ return;
+ }
+ return;
+ }
+}
+
+struct picohttpMultipart picohttpMultipartStart(
+ struct picohttpRequest * const req)
+{
+ struct picohttpMultipart mp = {
+ .req = req,
+ .finished = 0,
+ .contenttype = 0,
+ .disposition = { .name = {0,} },
+ .in_boundary = 0,
+ .replay = 0,
+ .replayhead = 0
+ };
+
+ return mp;
}
int picohttpMultipartNext(
- struct picohttpRequest * const req,
struct picohttpMultipart * const mp)
{
- mp->req = req;
- mp->finished = 0;
- mp->in_boundary = 0;
- mp->replay = 0;
- mp->replayhead = 0;
+ if( 2 == mp->finished ) {
+ return -1;
+ }
- int16_t ch;
- do {
- ch = picohttpMultipartGetch(mp);
- if( -1 == ch ) {
+ for(;;) {
+ int16_t ch = picohttpMultipartGetch(mp);
+ if( 0 > ch ) {
if( 2 == mp->finished ) {
- debug_printf("\n### last multipart ###\n");
return -1;
}
if( 1 == mp->finished ) {
mp->finished = 0;
- debug_printf("\n--- boundary ---\n");
+ mp->replay = 0;
+ mp->replayhead = 0;
+ mp->in_boundary = 0;
if( 0 > (ch = picohttpMultipartGetch(mp)) )
return ch;
if( 0 > (ch = picohttpProcessHeaders(
- req,
+ mp->req,
picohttpMultipartHeaderField,
+ mp,
ch)) )
return ch;
if( '\r' == ch ) {
- if( 0 > (ch = picohttpIoGetch(req->ioops)) )
+ if( 0 > (ch = picohttpIoGetch(mp->req->ioops)) )
return ch;
if( '\n' != ch ) {
- return -PICOHTTP_STATUS_400_BAD_REQUEST;
+ return -1;
}
}
- req->query.prev_ch[0] = '\n';
- req->query.prev_ch[1] = '\r';
- req->query.prev_ch[2] = '\n';
- req->query.prev_ch[3] = '\r';
- req->query.prev_ch[4] = 0;
+ mp->req->query.prev_ch[0] = '\n';
+ mp->req->query.prev_ch[1] = '\r';
+ mp->req->query.prev_ch[2] =
+ mp->req->query.prev_ch[3] =
+ mp->req->query.prev_ch[4] = 0;
- continue;
+ return 0;
}
}
- #if 1
- switch(ch) {
- case '\r':
- debug_printf(" % .2x = <CR>\n", ch); break;
- case '\n':
- debug_printf(" % .2x = <LF>\n", ch, ch); break;
- default:
- debug_printf(" % .2x = %c\n", ch, ch); break;
- }
- #endif
-
- } while(1);
+ }
- return 0;
+ return -1;
}
diff --git a/picohttp.h b/picohttp.h
index d7bccde..063ebd5 100644
--- a/picohttp.h
+++ b/picohttp.h
@@ -7,32 +7,29 @@
/* max 70 for boundary + 4 chars for "<CR><LF>--" */
#define PICOHTTP_MULTIPARTBOUNDARY_MAX_LEN 74
-#define PICOHTTP_DISPOSITION_NAME_MAX 16
-
-#define PICOHTTP_MAJORVERSION(x) ( (x & 0x7f00) >> 8 )
-#define PICOHTTP_MINORVERSION(x) ( (x & 0x007f) )
+#define PICOHTTP_DISPOSITION_NAME_MAX 48
#define PICOHTTP_METHOD_GET 1
#define PICOHTTP_METHOD_HEAD 2
-#define PICOHTTP_METHOD_POST 3
+#define PICOHTTP_METHOD_POST 4
-#define PICOHTTP_CONTENTTYPE_APPLICATION 0x0000
-#define PICOHTTP_CONTENTTYPE_APPLICATION_OCTETSTREAM 0x0000
+#define PICOHTTP_CONTENTTYPE_APPLICATION 0x1000
+#define PICOHTTP_CONTENTTYPE_APPLICATION_OCTETSTREAM 0x1000
-#define PICOHTTP_CONTENTTYPE_AUDIO 0x1000
-#define PICOHTTP_CONTENTTYPE_IMAGE 0x2000
-#define PICOHTTP_CONTENTTYPE_MESSAGE 0x3000
-#define PICOHTTP_CONTENTTYPE_MODEL 0x4000
+#define PICOHTTP_CONTENTTYPE_AUDIO 0x2000
+#define PICOHTTP_CONTENTTYPE_IMAGE 0x3000
+#define PICOHTTP_CONTENTTYPE_MESSAGE 0x4000
+#define PICOHTTP_CONTENTTYPE_MODEL 0x5000
-#define PICOHTTP_CONTENTTYPE_MULTIPART 0x5000
-#define PICOHTTP_CONTENTTYPE_MULTIPART_FORMDATA 0x5004
+#define PICOHTTP_CONTENTTYPE_MULTIPART 0x6000
+#define PICOHTTP_CONTENTTYPE_MULTIPART_FORMDATA 0x6004
-#define PICOHTTP_CONTENTTYPE_TEXT 0x6000
-#define PICOHTTP_CONTENTTYPE_TEXT_CSV 0x6003
-#define PICOHTTP_CONTENTTYPE_TEXT_HTML 0x6004
-#define PICOHTTP_CONTENTTYPE_TEXT_PLAIN 0x6006
+#define PICOHTTP_CONTENTTYPE_TEXT 0x7000
+#define PICOHTTP_CONTENTTYPE_TEXT_CSV 0x7003
+#define PICOHTTP_CONTENTTYPE_TEXT_HTML 0x7004
+#define PICOHTTP_CONTENTTYPE_TEXT_PLAIN 0x7006
-#define PICOHTTP_CONTENTTYPE_VIDEO 0x7000
+#define PICOHTTP_CONTENTTYPE_VIDEO 0x8000
#define PICOHTTP_CODING_IDENTITY 0
#define PICOHTTP_CODING_COMPRESS 1
@@ -52,7 +49,7 @@
struct picohttpIoOps {
int (*read)(size_t /*count*/, char* /*buf*/, void*);
int (*write)(size_t /*count*/, char const* /*buf*/, void*);
- int16_t (*getch)(void*); // returns -1 on error
+ int16_t (*getch)(void*); // returns negative value on error
int (*putch)(char, void*);
int (*flush)(void*);
void *data;
@@ -158,7 +155,7 @@ struct picohttpMultipart {
};
typedef void (*picohttpHeaderFieldCallback)(
- struct picohttpRequest *req,
+ void * const data,
char const *headername,
char const *headervalue);
@@ -179,11 +176,18 @@ int picohttpResponseWrite (
int16_t picohttpGetch(struct picohttpRequest * const req);
+struct picohttpMultipart picohttpMultipartStart(
+ struct picohttpRequest * const req);
+
int picohttpMultipartNext(
- struct picohttpRequest * const req,
struct picohttpMultipart * const mp);
int16_t picohttpMultipartGetch(
struct picohttpMultipart * const mp);
+int picohttpMultipartRead(
+ struct picohttpMultipart * const mp,
+ size_t len,
+ char * const buf);
+
#endif/*PICOHTTP_H_HEADERGUARD*/
diff --git a/test/bsdsocket.c b/test/bsdsocket.c
index 9665e1a..e090054 100644
--- a/test/bsdsocket.c
+++ b/test/bsdsocket.c
@@ -107,12 +107,13 @@ void rhRoot(struct picohttpRequest *req)
char http_test[] =
"<html><head><title>handling request /</title></head><body>\n"
-"<a href=\"/test\">/test</a>"
-"<form action=\"/upload\" enctype=\"multipart/form-data\" method=\"post\">"
-"<label for=\"file1\">File: </label><input type=\"file\" name=\"file1\"></input>"
-"<label for=\"file2\">File: </label><input type=\"file\" name=\"file2\"></input>"
-"<input type=\"submit\" value=\"Upload\"></input>"
-"</form>"
+"<a href=\"/test\">/test</a>\n"
+"<form action=\"/upload\" enctype=\"multipart/form-data\" method=\"post\">\n"
+"<label for=\"name\">Name: </label><input type=\"text\" name=\"name\"></input><br/>\n"
+"<label for=\"file1\">File: </label><input type=\"file\" name=\"file1\"></input><br/>\n"
+"<label for=\"file2\">File: </label><input type=\"file\" name=\"file2\"></input><br/>\n"
+"<input type=\"submit\" value=\"Upload\"></input>\n"
+"</form>\n"
"</body></html>\n";
picohttpResponseWrite(req, sizeof(http_test)-1, http_test);
@@ -141,8 +142,21 @@ void rhUpload(struct picohttpRequest *req)
char http_test[] = "handling request /upload";
- struct picohttpMultipart mp;
- picohttpMultipartNext(req, &mp);
+ struct picohttpMultipart mp = picohttpMultipartStart(req);
+
+ while( !picohttpMultipartNext(&mp) ) {
+ fprintf(stderr, "processing form field \"%s\"\n", mp.disposition.name);
+ for(int16_t ch = picohttpMultipartGetch(&mp);
+ 0 <= ch;
+ ch = picohttpMultipartGetch(&mp) ) {
+ fputc(ch, stderr);
+ }
+ if( !mp.finished ) {
+ break;
+ }
+ }
+ if( !mp.finished ) {
+ }
picohttpResponseWrite(req, sizeof(http_test)-1, http_test);
if(req->urltail) {
@@ -206,7 +220,7 @@ int main(int argc, char *argv[])
struct picohttpURLRoute routes[] = {
{ "/test", 0, rhTest, 16, PICOHTTP_METHOD_GET },
- { "/upload|", 0, rhUpload, 0, PICOHTTP_METHOD_GET },
+ { "/upload", 0, rhUpload, 16, PICOHTTP_METHOD_POST },
{ "/|", 0, rhRoot, 0, PICOHTTP_METHOD_GET },
{ NULL, 0, 0, 0, 0 }
};