aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWolfgang Draxinger <Wolfgang.Draxinger@physik.uni-muenchen.de>2013-06-20 21:21:54 +0200
committerWolfgang Draxinger <Wolfgang.Draxinger@physik.uni-muenchen.de>2013-06-20 21:21:54 +0200
commit77be505fad9fbcea02b27cb89a196b1f230fe42f (patch)
treefc1711115178054714d609d442e50df76c7e997f
parent9de2c281d9a4c350754ceb02c6f4a65134d007ee (diff)
downloadlitheweb-77be505fad9fbcea02b27cb89a196b1f230fe42f.tar.gz
litheweb-77be505fad9fbcea02b27cb89a196b1f230fe42f.tar.bz2
multipart separation works (almost)
-rw-r--r--picohttp.c146
-rw-r--r--picohttp.h14
-rw-r--r--test/bsdsocket.c4
3 files changed, 123 insertions, 41 deletions
diff --git a/picohttp.c b/picohttp.c
index 2cd18a6..8198563 100644
--- a/picohttp.c
+++ b/picohttp.c
@@ -225,11 +225,22 @@ static int16_t picohttpIoGetPercentCh(
return ch;
}
-uint16_t picohttpGetch(struct picohttpRequest * const req)
+int16_t picohttpGetch(struct picohttpRequest * const req)
{
/* read HTTP query body, skipping over Chunked Transfer Boundaries
* if Chunked Transfer Encoding is used */
+ uint16_t ch = picohttpIoGetch(req->ioops);
+ if( 0 <= ch ) {
+ /* use dirty hack?
+ * *((uint32_t*)prev_ch) = *((uint32_t*)prev_ch) >> 8;
+ */
+ req->query.prev_ch[0] = req->query.prev_ch[1];
+ req->query.prev_ch[1] = req->query.prev_ch[2];
+ req->query.prev_ch[2] = ch;
+ }
+
+ return ch;
}
/* TODO:
@@ -766,6 +777,19 @@ void picohttpProcessRequest (
if( 0 > (ch = picohttpProcessHeaders(&request, ch)) )
goto http_error;
+ if( '\r' == ch ) {
+ if( 0 > (ch = picohttpIoGetch(ioops)) )
+ goto http_error;
+ if( '\n' != ch ) {
+ ch = -PICOHTTP_STATUS_400_BAD_REQUEST;
+ goto http_error;
+ }
+ }
+
+ request.query.prev_ch[0] = 0;
+ request.query.prev_ch[1] = '\r';
+ request.query.prev_ch[2] = '\n';
+
request.status = PICOHTTP_STATUS_200_OK;
request.route->handler(&request);
@@ -895,47 +919,95 @@ int picohttpResponseWrite (
return len;
}
-uint16_t picohttpMultipartGetch(
- struct picohttpMultiPart * const mp);
+int16_t picohttpMultipartGetch(
+ struct picohttpMultipart * const mp)
{
- if( mp->replay + mp->in_boundary < 0) {
- uint16_t ch = mp->replay < 1 ? '-' :
- mp->req->query.multipartboundary[mp->replay - 1];
- mp->replay++;
- return ch;
- } else if( mp->finished) {
+ uint16_t ch;
+ if( 0 < mp->replay ) {
+ if( mp->replay <= mp->in_boundary ) {
+ ch = mp->replay < 3 ? '-' :
+ mp->req->query.multipartboundary[mp->replay - 3];
+ mp->replay++;
+ } else {
+ ch = mp->req->query.prev_ch[2];
+ mp->replay = 0;
+ mp->in_boundary = 0;
+ }
+ } else if( mp->finished ) {
return -1;
} else {
- uint16_t ch;
- ch = picohttpIoGetch(mp->req->ioops);
- if( 0 > ch ) {
- return ch;
- }
-
- if( (0 == mp->in_boundary && '\r' == ch) ||
- (1 == mp->in_boundary && '\n' == ch) ||
- (2 < mp->in_boundary && '-' == ch) ||
- (4 < mp->in_boundary &&
- mp->req->query.multipartboundary[mp->in_boundary-4] == ch) ) {
- if( 5 < mp->in_boundary &&
- 0 == mp->req->query.multipartboundary[mp->in_boundary-3] ) {
- /* matched boundary */
- mp->finished = 1;
- return 0;
- }
- mp->in_boundary++;
- ch = picohttpIoGetch(mp->req->ioops);
- if( 0 >= ch ) {
- return -1;
+ ch = picohttpGetch(mp->req);
+ while( 0 <= ch ) {
+ /* picohttp's query and header parsing is forgiving
+ * regarding line termination. <CR><LF> or just <LF>
+ * are accepted.
+ * However multipart boundaries must be preceeded by
+ * a <CR><LF> sequence, we're strict about that.
+ */
+ if( ( 0 == mp->in_boundary && '-' == ch &&
+ '\r' == mp->req->query.prev_ch[0] &&
+ '\n' == mp->req->query.prev_ch[1] ) ||
+ ( 1 == mp->in_boundary && '-' == ch ) ||
+ ( 1 < mp->in_boundary &&
+ mp->req->query.multipartboundary[mp->in_boundary-2] == ch) ) {
+ if( 1 < mp->in_boundary &&
+ 0 == mp->req->query.multipartboundary[mp->in_boundary-1] ) {
+ /* matched boundary */
+ char trail[2];
+ for(int i=0; i<2; i++) {
+ trail[i] = picohttpGetch(mp->req);
+ if( 0 > trail[1] )
+ return -1;
+ }
+
+ if(trail[0] == '\r' && trail[1] == '\n')
+ mp->finished = 1;
+
+ if(trail[0] == '-' && trail[1] == '-')
+ mp->finished = 2;
+
+ return -1;
+ } else {
+ mp->in_boundary++;
+ }
+ } else {
+ if( 0 < mp->in_boundary ) {
+ mp->replay = 1;
+ return '-';
+ }
+ return ch;
}
- } else {
- mp->replay = mp->in_boundary + 1;
- return '-';
+ ch = picohttpGetch(mp->req);
}
}
+ return ch;
}
-
-
-
-
+int picohttpMultipartNext(
+ struct picohttpRequest * const req,
+ struct picohttpMultipart * const mp)
+{
+ mp->req = req;
+ mp->finished = 0;
+ mp->in_boundary = 0;
+ mp->replay = 0;
+
+ int r;
+ for(;;) {
+ r = picohttpMultipartGetch(mp);
+ if( 2 == mp->finished ) {
+ debug_printf("last multipart\n");
+ break;
+ }
+
+ if( 1 == mp->finished ) {
+ mp->replay = 0;
+ mp->in_boundary = 0;
+ mp->finished = 0;
+ }
+
+ debug_printf("% .3d = %c\n", r, r);
+ }
+
+ return 0;
+}
diff --git a/picohttp.h b/picohttp.h
index a60afd2..7c7997d 100644
--- a/picohttp.h
+++ b/picohttp.h
@@ -5,7 +5,8 @@
#include <stddef.h>
#include <stdint.h>
-#define PICOHTTP_MULTIPARTBOUNDARY_MAX_LEN 70
+/* 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 )
@@ -16,6 +17,8 @@
#define PICOHTTP_METHOD_POST 3
#define PICOHTTP_CONTENTTYPE_APPLICATION 0x0000
+#define PICOHTTP_CONTENTTYPE_APPLICATION_OCTETSTREAM 0x0000
+
#define PICOHTTP_CONTENTTYPE_AUDIO 0x1000
#define PICOHTTP_CONTENTTYPE_IMAGE 0x2000
#define PICOHTTP_CONTENTTYPE_MESSAGE 0x3000
@@ -121,6 +124,7 @@ struct picohttpRequest {
uint8_t contentencoding;
uint8_t transferencoding;
char multipartboundary[PICOHTTP_MULTIPARTBOUNDARY_MAX_LEN+1];
+ char prev_ch[3];
} query;
struct {
char const *contenttype;
@@ -143,11 +147,13 @@ struct picohttpRequest {
struct picohttpMultipart {
struct picohttpRequest *req;
+ uint8_t finished;
uint16_t contenttype;
struct {
char name[PICOHTTP_DISPOSITION_NAME_MAX+1];
} disposition;
- uint8_t boundarymatch_counter;
+ int in_boundary;
+ int replay;
};
void picohttpProcessRequest(
@@ -165,13 +171,13 @@ int picohttpResponseWrite (
size_t len,
char const *buf );
-uint16_t picohttpGetch(struct picohttpRequest * const req);
+int16_t picohttpGetch(struct picohttpRequest * const req);
int picohttpMultipartNext(
struct picohttpRequest * const req,
struct picohttpMultipart * const mp);
-uint16_t picohttpMultipartGetch(
+int16_t picohttpMultipartGetch(
struct picohttpMultipart * const mp);
#endif/*PICOHTTP_H_HEADERGUARD*/
diff --git a/test/bsdsocket.c b/test/bsdsocket.c
index bddb5be..63f3d17 100644
--- a/test/bsdsocket.c
+++ b/test/bsdsocket.c
@@ -138,6 +138,10 @@ void rhUpload(struct picohttpRequest *req)
return;
char http_test[] = "handling request /upload";
+
+ struct picohttpMultipart mp;
+ picohttpMultipartNext(req, &mp);
+
picohttpResponseWrite(req, sizeof(http_test)-1, http_test);
if(req->urltail) {
picohttpResponseWrite(req, strlen(req->urltail), req->urltail);