From 77be505fad9fbcea02b27cb89a196b1f230fe42f Mon Sep 17 00:00:00 2001 From: Wolfgang Draxinger Date: Thu, 20 Jun 2013 21:21:54 +0200 Subject: multipart separation works (almost) --- picohttp.c | 146 +++++++++++++++++++++++++++++++++++++++++-------------- picohttp.h | 14 ++++-- test/bsdsocket.c | 4 ++ 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. or just + * are accepted. + * However multipart boundaries must be preceeded by + * a 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 #include -#define PICOHTTP_MULTIPARTBOUNDARY_MAX_LEN 70 +/* max 70 for boundary + 4 chars for "--" */ +#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); -- cgit v1.2.3