diff options
author | Wolfgang Draxinger <Wolfgang.Draxinger@draxit.de> | 2013-06-18 22:14:56 +0200 |
---|---|---|
committer | Wolfgang Draxinger <Wolfgang.Draxinger@draxit.de> | 2013-06-18 22:14:56 +0200 |
commit | d8b0fcee5325f54ba48531d265f5d9823ebed9f3 (patch) | |
tree | aa9eeceaec6b5d8e3b52dbe82f0d4f0c38630f0d | |
parent | e7b86baeec0ef6f946e2b60a68876eb6f3cdc32e (diff) | |
parent | 3293d9eeed04c67669c06bc745ea9ee05012cb7f (diff) | |
download | litheweb-d8b0fcee5325f54ba48531d265f5d9823ebed9f3.tar.gz litheweb-d8b0fcee5325f54ba48531d265f5d9823ebed9f3.tar.bz2 |
Merge branch 'master' of github.com:datenwolf/picoweb
-rw-r--r-- | picohttp.c | 151 | ||||
-rw-r--r-- | picohttp.h | 25 | ||||
-rw-r--r-- | test/bufbsdsocket.c | 21 |
3 files changed, 185 insertions, 12 deletions
@@ -1,11 +1,22 @@ #include "picohttp.h" +#ifdef HOST_DEBUG +#include <stdio.h> +#define debug_printf(...) do{fprintf(stderr, __VA_ARGS__);}while(0) +#define debug_putc(x) do{fputc(x, stderr);}while(0) +#else +#define debug_printf(...) do{}while(0) +#define debug_putc(x) do{}while(0) +#endif + #include <alloca.h> #include <string.h> +#include <stdlib.h> static char const PICOHTTP_STR_CRLF[] = "\r\n"; static char const PICOHTTP_STR_CLSP[] = ": "; static char const PICOHTTP_STR_HTTP_[] = "HTTP/"; +static char const PICOHTTP_STR_HOST[] = "Host"; static char const PICOHTTP_STR_SERVER[] = "Server"; static char const PICOHTTP_STR_PICOWEB[] = "picoweb/0.1"; @@ -17,6 +28,13 @@ 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_APPLICATION_[] = "application/"; +static char const PICOHTTP_STR_TEXT_[] = "text/"; +static char const PICOHTTP_STR_MULTIPART_[] = "multipart/"; + +static char const PICOHTTP_STR_FORMDATA[] = "form-data"; + static char const PICOHTTP_STR_CACHECONTROL[] = "Cache-Control"; static char const PICOHTTP_STR_CONNECTION[] = "Connection"; @@ -26,6 +44,8 @@ static char const PICOHTTP_STR_DATE[] = "Date"; static char const PICOHTTP_STR_EXPECT[] = "Expect"; +static char const PICOHTTP_STR_BOUNDARY[] = " boundary="; + #if !defined(PICOHTTP_CONFIG_HAVE_LIBDJB) /* Number formating functions modified from libdjb by * Daniel J. Bernstein, packaged at http://www.fefe.de/djb/ @@ -207,7 +227,7 @@ uint16_t picohttpGetch(struct picohttpRequest * const req) * 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. * - * Implement this to imporove memory footprint reduction. + * Implement this to improve memory footprint reduction. */ static size_t picohttpMatchURL( char const * const urlhead, @@ -492,23 +512,130 @@ static int16_t picohttpProcessHTTPVersion ( return ch; } +static void picohttpProcessContentType( + struct picohttpRequest * const req, + char const *contenttype ) +{ + if(!strncmp(contenttype, + PICOHTTP_STR_APPLICATION_, sizeof(PICOHTTP_STR_APPLICATION_)-1)) { + } + + if(!strncmp(contenttype, + PICOHTTP_STR_TEXT_, sizeof(PICOHTTP_STR_TEXT_)-1)) { + } + + if(!strncmp(contenttype, PICOHTTP_STR_MULTIPART_, + sizeof(PICOHTTP_STR_MULTIPART_)-1)) { + req->query.contenttype.type = PICOHTTP_CONTENTTYPE_MULTIPART; + contenttype += sizeof(PICOHTTP_STR_MULTIPART_)-1; + + if(!strncmp(contenttype,PICOHTTP_STR_FORMDATA, + sizeof(PICOHTTP_STR_FORMDATA)-1)) { + req->query.contenttype.subtype = + PICOHTTP_CONTENTTYPE_MULTIPART_SUBTYPE_FORM_DATA; + contenttype += sizeof(PICOHTTP_STR_FORMDATA)-1; + } + char *boundary = strstr(contenttype, PICOHTTP_STR_BOUNDARY); + if(boundary) { + /* see RFC1521 regarding maximum length of boundary */ + strncpy(req->query.multipartboundary, + boundary + sizeof(PICOHTTP_STR_BOUNDARY)-1, + PICOHTTP_MULTIPARTBOUNDARY_MAX_LEN); + } + } +} + +static void picohttpProcessHeaderField( + struct picohttpRequest * const req, + char const * const headername, + char const * const headervalue) +{ + debug_printf("%s: %s\n", headername, headervalue); + if(!strncmp(headername, + PICOHTTP_STR_CONTENT, + sizeof(PICOHTTP_STR_CONTENT)-1)) { + /* Content Length */ + if(!strncmp(headername + sizeof(PICOHTTP_STR_CONTENT)-1, + PICOHTTP_STR__LENGTH, sizeof(PICOHTTP_STR__LENGTH)-1)) { + req->query.contentlength = atol(headervalue); + } + + /* Content Type */ + if(!strncmp(headername + sizeof(PICOHTTP_STR_CONTENT)-1, + PICOHTTP_STR__TYPE, sizeof(PICOHTTP_STR__TYPE)-1)) { + picohttpProcessContentType(req, headervalue); + } + } +} + static int16_t picohttpProcessHeaders ( struct picohttpRequest * const req, int16_t ch ) { #define PICOHTTP_HEADERNAME_MAX_LEN 32 - char headername[PICOHTTP_HEADERNAME_MAX_LEN] = {0,}; + char headername[PICOHTTP_HEADERNAME_MAX_LEN+1] = {0,}; +#define PICOHTTP_HEADERVALUE_MAX_LEN 224 + char headervalue[PICOHTTP_HEADERVALUE_MAX_LEN+1] = {0,}; + char *hn; + char *hv; - - /* FIXME: Add Header handling here */ + /* TODO: Add Header handling here */ while( !picohttpIsCRLF(ch) ) { - while( !picohttpIsCRLF( ch=picohttpIoSkipSpace(req->ioops, ch)) ){ - if( 0 > ( ch=picohttpIoGetch(req->ioops) ) ) { - return -PICOHTTP_STATUS_500_INTERNAL_SERVER_ERROR; + /* Beginning of new header line */ + if( 0 < ch && !picohttpIsCRLF(ch) ){ + /* new header field OR field continuation */ + if( picohttpIsLWS(ch) ) { + /* continuation */ + /* skip space */ + if( 0 > (ch = picohttpIoSkipSpace(req->ioops, ch)) ) + return -PICOHTTP_STATUS_500_INTERNAL_SERVER_ERROR; + + /* read until EOL */ + for(; + 0 < ch && !picohttpIsCRLF(ch); + hv = (hv - headervalue) < + PICOHTTP_HEADERVALUE_MAX_LEN ? + hv+1 : 0 ) { + /* add to header field content */ + + if(hv) + *hv = ch; + + ch = picohttpIoGetch(req->ioops); + } + } else { + if( *headername && *headervalue ) + picohttpProcessHeaderField( + req, + headername, + headervalue ); + /* new header field */ + memset(headername, 0, PICOHTTP_HEADERNAME_MAX_LEN+1); + hn = headername; + + memset(headervalue, 0, PICOHTTP_HEADERVALUE_MAX_LEN+1); + hv = headervalue; + /* read until ':' or EOL */ + for(; + 0 < ch && ':' != ch && !picohttpIsCRLF(ch); + hn = (hn - headername) < + PICOHTTP_HEADERNAME_MAX_LEN ? + hn+1 : 0 ) { + /* add to header name */ + if(hn) + *hn = ch; + + ch = picohttpIoGetch(req->ioops); + } } + } + if( 0 > ch ) { + return -PICOHTTP_STATUS_500_INTERNAL_SERVER_ERROR; } - - ch = picohttpIoSkipOverCRLF(req->ioops, ch); + if( picohttpIsCRLF(ch) ) + ch = picohttpIoSkipOverCRLF(req->ioops, ch); + else + ch = picohttpIoGetch(req->ioops); if( 0 > ch ) { return -PICOHTTP_STATUS_500_INTERNAL_SERVER_ERROR; } @@ -516,6 +643,12 @@ static int16_t picohttpProcessHeaders ( return -PICOHTTP_STATUS_400_BAD_REQUEST; } } + if( *headername && *headervalue ) + picohttpProcessHeaderField( + req, + headername, + headervalue ); + return ch; } @@ -5,6 +5,8 @@ #include <stddef.h> #include <stdint.h> +#define PICOHTTP_MULTIPARTBOUNDARY_MAX_LEN 70 + #define PICOHTTP_MAJORVERSION(x) ( (x & 0x7f00) >> 8 ) #define PICOHTTP_MINORVERSION(x) ( (x & 0x007f) ) @@ -12,6 +14,21 @@ #define PICOHTTP_METHOD_HEAD 2 #define PICOHTTP_METHOD_POST 3 +#define PICOHTTP_CONTENTTYPE_APPLICATION 0 +#define PICOHTTP_CONTENTTYPE_AUDIO 1 +#define PICOHTTP_CONTENTTYPE_IMAGE 2 +#define PICOHTTP_CONTENTTYPE_MESSAGE 3 +#define PICOHTTP_CONTENTTYPE_MODEL 4 +#define PICOHTTP_CONTENTTYPE_MULTIPART 5 +#define PICOHTTP_CONTENTTYPE_TEXT 6 +#define PICOHTTP_CONTENTTYPE_VIDEO 7 + +#define PICOHTTP_CONTENTTYPE_TEXT_SUBTYPE_CSV 3 +#define PICOHTTP_CONTENTTYPE_TEXT_SUBTYPE_HTML 4 +#define PICOHTTP_CONTENTTYPE_TEXT_SUBTYPE_PLAIN 6 + +#define PICOHTTP_CONTENTTYPE_MULTIPART_SUBTYPE_FORM_DATA 4 + #define PICOHTTP_CODING_IDENTITY 0 #define PICOHTTP_CODING_COMPRESS 1 #define PICOHTTP_CODING_DEFLATE 2 @@ -103,10 +120,14 @@ struct picohttpRequest { uint8_t minor; } httpversion; struct { - char const *contenttype; + struct { + uint16_t type:4; + uint16_t subtype:12; + } contenttype; size_t contentlength; - uint8_t contentcoding; + uint8_t contentencoding; uint8_t te; + char multipartboundary[PICOHTTP_MULTIPARTBOUNDARY_MAX_LEN+1]; } query; struct { char const *contenttype; diff --git a/test/bufbsdsocket.c b/test/bufbsdsocket.c index 97c3526..596bc3d 100644 --- a/test/bufbsdsocket.c +++ b/test/bufbsdsocket.c @@ -143,7 +143,14 @@ void rhRoot(struct picohttpRequest *req) req->response.contenttype = "text/html"; - char http_test[] = "<html><head><title>handling request /</title></head>\n<body><a href=\"/test\">/test</a></body></html>\n"; + 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=\"file\">File: </label><input type=\"file\" name=\"file\"></input>" +"<input type=\"submit\" value=\"Upload\"></input>" +"</form>" +"</body></html>\n"; picohttpResponseWrite(req, sizeof(http_test)-1, http_test); } @@ -159,6 +166,17 @@ void rhTest(struct picohttpRequest *req) } } +void rhUpload(struct picohttpRequest *req) +{ + fprintf(stderr, "handling request /upload%s\n", req->urltail); + + char http_test[] = "handling request /upload"; + picohttpResponseWrite(req, sizeof(http_test)-1, http_test); + if(req->urltail) { + picohttpResponseWrite(req, strlen(req->urltail), req->urltail); + } +} + static uint8_t const favicon_ico[] = { 0x00,0x00,0x01,0x00,0x01,0x00,0x10,0x10,0x10,0x00,0x01,0x00,0x04,0x00,0x28,0x01, 0x00,0x00,0x16,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x20,0x00, @@ -248,6 +266,7 @@ int main(int argc, char *argv[]) struct picohttpURLRoute routes[] = { {"/favicon.ico|", 0, rhFavicon, 0, PICOHTTP_METHOD_GET}, { "/test", 0, rhTest, 16, PICOHTTP_METHOD_GET }, + { "/upload|", 0, rhUpload, 0, PICOHTTP_METHOD_GET }, { "/|", 0, rhRoot, 0, PICOHTTP_METHOD_GET }, { NULL, 0, 0, 0, 0 } }; |