aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWolfgang Draxinger <Wolfgang.Draxinger@draxit.de>2013-06-18 22:14:56 +0200
committerWolfgang Draxinger <Wolfgang.Draxinger@draxit.de>2013-06-18 22:14:56 +0200
commitd8b0fcee5325f54ba48531d265f5d9823ebed9f3 (patch)
treeaa9eeceaec6b5d8e3b52dbe82f0d4f0c38630f0d
parente7b86baeec0ef6f946e2b60a68876eb6f3cdc32e (diff)
parent3293d9eeed04c67669c06bc745ea9ee05012cb7f (diff)
downloadlitheweb-d8b0fcee5325f54ba48531d265f5d9823ebed9f3.tar.gz
litheweb-d8b0fcee5325f54ba48531d265f5d9823ebed9f3.tar.bz2
Merge branch 'master' of github.com:datenwolf/picoweb
-rw-r--r--picohttp.c151
-rw-r--r--picohttp.h25
-rw-r--r--test/bufbsdsocket.c21
3 files changed, 185 insertions, 12 deletions
diff --git a/picohttp.c b/picohttp.c
index eb5decc..790f4b7 100644
--- a/picohttp.c
+++ b/picohttp.c
@@ -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;
}
diff --git a/picohttp.h b/picohttp.h
index 24212e5..568f6b8 100644
--- a/picohttp.h
+++ b/picohttp.h
@@ -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 }
};