Browse Source
lots of changes but primarily change the request parser to use a ringbuffer. The ringbuffer is implemented using the shared memory trick.
master
lots of changes but primarily change the request parser to use a ringbuffer. The ringbuffer is implemented using the shared memory trick.
master
26 changed files with 703 additions and 218 deletions
-
8ChangeLog
-
87doc/file-upload.txt
-
75doc/file-upload2.txt
-
30include/http/request/parser.h
-
3include/http/worker.h
-
37include/ringbuffer.h
-
2include/socket.h
-
6src/Makefile.am
-
32src/http/request/parser.c
-
43src/http/request/parser/get_body.c
-
29src/http/request/parser/get_header.c
-
96src/http/request/parser/get_request_line.c
-
131src/http/request/parser/parse.c
-
50src/http/request/parser/read.c
-
9src/http/response/404.c
-
9src/http/response/image.c
-
9src/http/response/me.c
-
1src/http/response/writer/write.c
-
25src/http/worker.c
-
17src/http/worker/process.c
-
21src/rbtest.c
-
117src/ringbuffer.c
-
41src/ringbuffer/rb_read.c
-
8src/server/handle_accept.c
-
5src/socket/accept.c
-
2src/testserver.c
@ -0,0 +1,87 @@ |
|||
POST / HTTP/1.1 |
|||
Host: localhost:11213 |
|||
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:8.0) Gecko/20100101 Firefox/8.0 |
|||
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 |
|||
Accept-Language: de-de,de;q=0.8,en-us;q=0.5,en;q=0.3 |
|||
Accept-Encoding: gzip, deflate |
|||
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 |
|||
Connection: keep-alive |
|||
Referer: http://localhost:11213/ |
|||
Content-Type: multipart/form-data; boundary=---------------------------2713599294882465121951036798 |
|||
Content-Length: 2652 |
|||
|
|||
-----------------------------2713599294882465121951036798 |
|||
Content-Disposition: form-data; name="submitter" |
|||
|
|||
fooo |
|||
-----------------------------2713599294882465121951036798 |
|||
Content-Disposition: form-data; name="pics"; filename="bar.c" |
|||
Content-Type: text/x-csrc |
|||
|
|||
#include <stdio.h> |
|||
|
|||
#define _B64(chr, ref) (chr)==_##ref?__##ref |
|||
#define B64(_) \ |
|||
( _B64(_,A):_B64(_,B):_B64(_,C):_B64(_,D):_B64(_,E):_B64(_,F):_B64(_,G): \ |
|||
_B64(_,H):_B64(_,I):_B64(_,J):_B64(_,K):_B64(_,L):_B64(_,M):_B64(_,N): \ |
|||
_B64(_,O):_B64(_,P):_B64(_,Q):_B64(_,R):_B64(_,S):_B64(_,T):_B64(_,U): \ |
|||
_B64(_,V):_B64(_,W):_B64(_,X):_B64(_,Y):_B64(_,Z):_B64(_,a):_B64(_,b): \ |
|||
_B64(_,c):_B64(_,d):_B64(_,e):_B64(_,f):_B64(_,g):_B64(_,h):_B64(_,i): \ |
|||
_B64(_,j):_B64(_,k):_B64(_,l):_B64(_,m):_B64(_,n):_B64(_,o):_B64(_,p): \ |
|||
_B64(_,q):_B64(_,r):_B64(_,s):_B64(_,t):_B64(_,u):_B64(_,v):_B64(_,w): \ |
|||
_B64(_,x):_B64(_,y):_B64(_,z):_B64(_,0):_B64(_,1):_B64(_,2):_B64(_,3): \ |
|||
_B64(_,4):_B64(_,5):_B64(_,6):_B64(_,7):_B64(_,8):_B64(_,9): \ |
|||
_B64(_,PLUS):_B64(_,SLASH):-1 ) |
|||
|
|||
|
|||
#define B64_8(_) \ |
|||
B64(_),B64(_+1),B64(_+2),B64(_+3),B64(_+4),B64(_+5),B64(_+6),B64(_+7) |
|||
|
|||
#define B64_64(_) \ |
|||
B64_8(_),B64_8(_+8), B64_8(_+16),B64_8(_+24), \ |
|||
B64_8(_+32),B64_8(_+40),B64_8(_+48),B64_8(_+56) |
|||
|
|||
#define IS_BASE64(ch) ( \ |
|||
UCHAR_IN_RANGE((unsigned char)(ch)) \ |
|||
&& 0 <= b64[(unsigned char)(ch)] ) |
|||
|
|||
|
|||
static const char b64str[64] = |
|||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
|||
|
|||
enum b64vals { |
|||
__A=0,__B,__C,__D,__E,__F,__G,__H,__I,__J,__K,__L,__M,__N,__O,__P,__Q,__R, |
|||
__S,__T,__U,__V,__W,__X,__Y,__Z,__a,__b,__c,__d,__e,__f,__g,__h,__i,__j, |
|||
__k,__l,__m,__n,__o,__p,__q,__r,__s,__t,__u,__v,__w,__x,__y,__z,__0,__1, |
|||
__2,__3,__4,__5,__6,__7,__8,__9,__PLUS,__SLASH |
|||
}; |
|||
|
|||
enum b64chars { |
|||
_A='A',_B='B',_C='C',_D='D',_E='E',_F='F',_G='G',_H='H',_I='I',_J='J',_K='K', |
|||
_L='L',_M='M',_N='N',_O='O',_P='P',_Q='Q',_R='R',_S='S',_T='T',_U='U',_V='V', |
|||
_W='W',_X='X',_Y='Y',_Z='Z',_a='a',_b='b',_c='c',_d='d',_e='e',_f='f',_g='g', |
|||
_h='h',_i='i',_j='j',_k='k',_l='l',_m='m',_n='n',_o='o',_p='p',_q='q',_r='r', |
|||
_s='s',_t='t',_u='u',_v='v',_w='w',_x='x',_y='y',_z='z',_0='0',_1='1',_2='2', |
|||
_3='3',_4='4',_5='5',_6='6',_7='7',_8='8',_9='9',_PLUS='+',_SLASH='/' |
|||
}; |
|||
|
|||
#define __46B(chr) __##chr |
|||
inline |
|||
char |
|||
__B64(int val) |
|||
{ |
|||
return b64str[val]; |
|||
} |
|||
|
|||
int main() |
|||
{ |
|||
int i=12; |
|||
char a='k'; |
|||
|
|||
//printf("i => %c | a => %d\n", __B64(12), __46B('k')); |
|||
printf("i => %c | a => %d\n", __B64(i), __46B(a)); |
|||
} |
|||
|
|||
// vim: set ts=4 sw=4: |
|||
|
|||
-----------------------------2713599294882465121951036798-- |
|||
@ -0,0 +1,75 @@ |
|||
-----------------------------2713599294882465121951036798 |
|||
Content-Disposition: form-data; name="submitter" |
|||
|
|||
fooo |
|||
-----------------------------2713599294882465121951036798 |
|||
Content-Disposition: form-data; name="pics"; filename="bar.c" |
|||
Content-Type: text/x-csrc |
|||
|
|||
#include <stdio.h> |
|||
|
|||
#define _B64(chr, ref) (chr)==_##ref?__##ref |
|||
#define B64(_) \ |
|||
( _B64(_,A):_B64(_,B):_B64(_,C):_B64(_,D):_B64(_,E):_B64(_,F):_B64(_,G): \ |
|||
_B64(_,H):_B64(_,I):_B64(_,J):_B64(_,K):_B64(_,L):_B64(_,M):_B64(_,N): \ |
|||
_B64(_,O):_B64(_,P):_B64(_,Q):_B64(_,R):_B64(_,S):_B64(_,T):_B64(_,U): \ |
|||
_B64(_,V):_B64(_,W):_B64(_,X):_B64(_,Y):_B64(_,Z):_B64(_,a):_B64(_,b): \ |
|||
_B64(_,c):_B64(_,d):_B64(_,e):_B64(_,f):_B64(_,g):_B64(_,h):_B64(_,i): \ |
|||
_B64(_,j):_B64(_,k):_B64(_,l):_B64(_,m):_B64(_,n):_B64(_,o):_B64(_,p): \ |
|||
_B64(_,q):_B64(_,r):_B64(_,s):_B64(_,t):_B64(_,u):_B64(_,v):_B64(_,w): \ |
|||
_B64(_,x):_B64(_,y):_B64(_,z):_B64(_,0):_B64(_,1):_B64(_,2):_B64(_,3): \ |
|||
_B64(_,4):_B64(_,5):_B64(_,6):_B64(_,7):_B64(_,8):_B64(_,9): \ |
|||
_B64(_,PLUS):_B64(_,SLASH):-1 ) |
|||
|
|||
|
|||
#define B64_8(_) \ |
|||
B64(_),B64(_+1),B64(_+2),B64(_+3),B64(_+4),B64(_+5),B64(_+6),B64(_+7) |
|||
|
|||
#define B64_64(_) \ |
|||
B64_8(_),B64_8(_+8), B64_8(_+16),B64_8(_+24), \ |
|||
B64_8(_+32),B64_8(_+40),B64_8(_+48),B64_8(_+56) |
|||
|
|||
#define IS_BASE64(ch) ( \ |
|||
UCHAR_IN_RANGE((unsigned char)(ch)) \ |
|||
&& 0 <= b64[(unsigned char)(ch)] ) |
|||
|
|||
|
|||
static const char b64str[64] = |
|||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
|||
|
|||
enum b64vals { |
|||
__A=0,__B,__C,__D,__E,__F,__G,__H,__I,__J,__K,__L,__M,__N,__O,__P,__Q,__R, |
|||
__S,__T,__U,__V,__W,__X,__Y,__Z,__a,__b,__c,__d,__e,__f,__g,__h,__i,__j, |
|||
__k,__l,__m,__n,__o,__p,__q,__r,__s,__t,__u,__v,__w,__x,__y,__z,__0,__1, |
|||
__2,__3,__4,__5,__6,__7,__8,__9,__PLUS,__SLASH |
|||
}; |
|||
|
|||
enum b64chars { |
|||
_A='A',_B='B',_C='C',_D='D',_E='E',_F='F',_G='G',_H='H',_I='I',_J='J',_K='K', |
|||
_L='L',_M='M',_N='N',_O='O',_P='P',_Q='Q',_R='R',_S='S',_T='T',_U='U',_V='V', |
|||
_W='W',_X='X',_Y='Y',_Z='Z',_a='a',_b='b',_c='c',_d='d',_e='e',_f='f',_g='g', |
|||
_h='h',_i='i',_j='j',_k='k',_l='l',_m='m',_n='n',_o='o',_p='p',_q='q',_r='r', |
|||
_s='s',_t='t',_u='u',_v='v',_w='w',_x='x',_y='y',_z='z',_0='0',_1='1',_2='2', |
|||
_3='3',_4='4',_5='5',_6='6',_7='7',_8='8',_9='9',_PLUS='+',_SLASH='/' |
|||
}; |
|||
|
|||
#define __46B(chr) __##chr |
|||
inline |
|||
char |
|||
__B64(int val) |
|||
{ |
|||
return b64str[val]; |
|||
} |
|||
|
|||
int main() |
|||
{ |
|||
int i=12; |
|||
char a='k'; |
|||
|
|||
//printf("i => %c | a => %d\n", __B64(12), __46B('k')); |
|||
printf("i => %c | a => %d\n", __B64(i), __46B(a)); |
|||
} |
|||
|
|||
// vim: set ts=4 sw=4: |
|||
|
|||
-----------------------------2713599294882465121951036798-- |
|||
@ -0,0 +1,37 @@ |
|||
/** |
|||
* my implementation of a ringbuffer. |
|||
* It maps a shared memory object twice directly following |
|||
* thus make it possible to read and write from any |
|||
* position within the buffer without the nasty wrap |
|||
* calculations. |
|||
* This is achived because the same memory region is mapped |
|||
* at the two addresses. |
|||
*/ |
|||
#ifndef __RINGBUFFER_H__ |
|||
#define __RINGBUFFER_H__ |
|||
|
|||
#include <sys/types.h> |
|||
|
|||
#include "class.h" |
|||
|
|||
#define ERBOVRFL 100 |
|||
|
|||
|
|||
CLASS(Ringbuffer) { |
|||
char * shm_name; // shared memory identifier |
|||
|
|||
char * buffer; |
|||
char * mirror; |
|||
|
|||
size_t bsize; |
|||
size_t bused; |
|||
size_t bstart; |
|||
size_t bend; |
|||
}; |
|||
|
|||
ssize_t rbRead(Ringbuffer, int fd); |
|||
ssize_t rbWrite(Ringbuffer, int fd); |
|||
|
|||
#endif // __RINGBUFFER_H__ |
|||
|
|||
// vim: set ts=4 sw=4: |
|||
@ -1,31 +1,95 @@ |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
|
|||
#include "http/message.h" |
|||
#include "http/request.h" |
|||
#include "http/request/parser.h" |
|||
#include "ringbuffer.h" |
|||
|
|||
#define MAX(x,y) ((x) > (y) ? (x) : (y)) |
|||
#define MIN(x,y) ((x) < (y) ? (x) : (y)) |
|||
#define MIN_SIZE(x,y) (MAX(strlen((x)), (y))) |
|||
|
|||
void |
|||
httpRequestParserGetRequestLine(HttpRequest request, char * line) |
|||
enum e_method { |
|||
OPTIONS=0, |
|||
GET, |
|||
HEAD, |
|||
POST, |
|||
PUT, |
|||
DELETE, |
|||
TRACE, |
|||
CONNECT |
|||
}; |
|||
|
|||
#define N_METHODS 8 |
|||
|
|||
static |
|||
const |
|||
char * method[N_METHODS] = { |
|||
"OPTIONS", |
|||
"GET", |
|||
"HEAD", |
|||
"POST", |
|||
"PUT", |
|||
"DELETE", |
|||
"TRACE", |
|||
"CONNECT" |
|||
}; |
|||
|
|||
ssize_t |
|||
httpRequestParserGetRequestLine(HttpRequestParser this, char * cr) |
|||
{ |
|||
HttpRequest request = this->cur_request; |
|||
HttpMessage message = (HttpMessage)request; |
|||
char * method, * uri, * version; |
|||
char * space1, * space2; |
|||
size_t len = cr - this->buffer->buffer - this->buffer->bstart; |
|||
int i; |
|||
|
|||
space1 = memchr( |
|||
this->buffer->buffer + this->buffer->bstart, |
|||
' ', len); |
|||
|
|||
if (NULL == space1) { |
|||
return -1; |
|||
} |
|||
|
|||
len = cr - space1; |
|||
space2 = memchr(space1 + 1, ' ', len); |
|||
|
|||
if (NULL == space2) { |
|||
return -1; |
|||
} |
|||
|
|||
len = space1 - this->buffer->buffer - this->buffer->bstart; |
|||
request->method = calloc(1, len + 1); |
|||
memcpy(request->method, |
|||
this->buffer->buffer + this->buffer->bstart, |
|||
len); |
|||
|
|||
for (i= 0; i< N_METHODS; i++) { |
|||
if (0 == memcmp(method[i], request->method, MIN_SIZE(method[i], len))) { |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (i == N_METHODS) { |
|||
return -1; |
|||
} |
|||
|
|||
method = line; |
|||
len = space2 - space1 - 1; |
|||
request->uri = calloc(1, len + 1); |
|||
memcpy(request->uri, space1 + 1, len); |
|||
|
|||
uri = strchr(line, ' '); |
|||
*uri++ = 0; |
|||
for (; *uri == ' ' && *uri != 0; uri++); |
|||
len = cr - space2 - 1; |
|||
message->version = calloc(1, len + 1); |
|||
memcpy(message->version, space2 + 1, len); |
|||
|
|||
version = strchr(uri, ' '); |
|||
*version++ = 0; |
|||
for (; *version == ' ' && *version != 0; version++); |
|||
if (len+1 != sizeof("HTTP/1.1") || |
|||
0 != memcmp("HTTP/1.", message->version, len-1)) { |
|||
return -1; |
|||
} |
|||
|
|||
request->method = malloc(strlen(method) + 1); |
|||
strcpy(request->method, method); |
|||
request->uri = malloc(strlen(uri) + 1); |
|||
strcpy(request->uri, uri); |
|||
message->version = malloc(strlen(version) + 1); |
|||
strcpy(message->version, method); |
|||
return 1; //* @TODO: return something useful here |
|||
} |
|||
|
|||
// vim: set ts=4 sw=4: |
|||
@ -0,0 +1,21 @@ |
|||
#include <stdio.h> |
|||
|
|||
#include "ringbuffer.h" |
|||
#include "interface/class.h" |
|||
|
|||
int |
|||
main() |
|||
{ |
|||
Ringbuffer buf = new(Ringbuffer, "/rbtest", 1); |
|||
|
|||
strcpy(buf->buffer + buf->bsize - 5, "Dies ist ein foobar test"); |
|||
|
|||
printf("%s\n", buf->buffer); |
|||
printf("%s\n", buf->buffer + buf->bsize - 5); |
|||
|
|||
delete(&buf); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
// vim: set ts=4 sw=4: |
|||
@ -0,0 +1,117 @@ |
|||
#define _POSIX_SOURCE |
|||
#define _POSIX_C_SOURCE 200112L |
|||
|
|||
#include <sys/types.h> |
|||
#include <sys/stat.h> |
|||
#include <sys/mman.h> |
|||
#include <stdarg.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include <unistd.h> |
|||
#include <fcntl.h> |
|||
|
|||
#include "class.h" |
|||
#include "interface/class.h" |
|||
|
|||
#include "ringbuffer.h" |
|||
|
|||
#define PAGES(size, psize) ((size)/(psize)+(0 == (size)%(psize))?0:1) |
|||
|
|||
|
|||
static void dtor(void*); |
|||
|
|||
static |
|||
void |
|||
ctor(void * _this, va_list * params) |
|||
{ |
|||
Ringbuffer this = _this; |
|||
char state = 0; |
|||
char * shm_name = va_arg(*params, char*); |
|||
long psize = sysconf(_SC_PAGESIZE); |
|||
size_t size; |
|||
int shm; |
|||
void * shm_addr; |
|||
|
|||
this->shm_name = malloc(strlen(shm_name) + 1); |
|||
strcpy(this->shm_name, shm_name); |
|||
|
|||
/** |
|||
* align size at page boundary. |
|||
* increase as neccessary |
|||
*/ |
|||
size = va_arg(*params, size_t); |
|||
size = (0 <= size)? 1 : size; |
|||
this->bsize = psize * PAGES(size, psize); |
|||
|
|||
while (0 == state) { |
|||
shm = shm_open(this->shm_name, O_RDWR|O_CREAT|O_EXCL, S_IRWXU); |
|||
if (-1 == shm) { |
|||
break; |
|||
} |
|||
else { |
|||
ftruncate(shm, this->bsize); |
|||
} |
|||
|
|||
shm_addr = mmap (0, this->bsize<<1, |
|||
PROT_READ|PROT_WRITE, MAP_SHARED, shm, 0); |
|||
if (shm_addr == MAP_FAILED) |
|||
break; |
|||
|
|||
munmap(shm_addr, this->bsize<<1); |
|||
|
|||
this->buffer = mmap (shm_addr, this->bsize, |
|||
PROT_READ|PROT_WRITE, MAP_SHARED, shm, 0); |
|||
if (this->buffer == MAP_FAILED) { |
|||
shm_addr = NULL; |
|||
break; |
|||
} |
|||
|
|||
this->mirror = mmap (shm_addr + this->bsize, this->bsize, |
|||
PROT_READ|PROT_WRITE, MAP_SHARED, shm, 0); |
|||
if (this->mirror != shm_addr + this->bsize) { |
|||
shm_addr = NULL; |
|||
break; |
|||
} |
|||
|
|||
state = 1; |
|||
} |
|||
|
|||
if (-1 != shm) { |
|||
shm_unlink(this->shm_name); |
|||
close(shm); |
|||
} |
|||
|
|||
if (1 != state) { |
|||
if (shm_addr) { |
|||
munmap(shm_addr, this->bsize<<1); |
|||
} |
|||
|
|||
dtor(this); |
|||
} |
|||
} |
|||
|
|||
static |
|||
void |
|||
dtor(void * _this) |
|||
{ |
|||
Ringbuffer this = _this; |
|||
|
|||
if (NULL != this->shm_name) { |
|||
free(this->shm_name); |
|||
} |
|||
|
|||
if (this->buffer) { |
|||
munmap(this->buffer, this->bsize); |
|||
this->buffer = NULL; |
|||
} |
|||
|
|||
if (this->mirror) { |
|||
munmap(this->mirror, this->bsize); |
|||
this->mirror = NULL; |
|||
} |
|||
} |
|||
|
|||
INIT_IFACE(Class, ctor, dtor, NULL); |
|||
CREATE_CLASS(Ringbuffer, NULL, IFACE(Class)); |
|||
|
|||
// vim: set ts=4 sw=4: |
|||
@ -0,0 +1,41 @@ |
|||
#include <sys/types.h> |
|||
#include <unistd.h> |
|||
#include <errno.h> |
|||
|
|||
#include "ringbuffer.h" |
|||
|
|||
ssize_t |
|||
rbRead(Ringbuffer this, int fd) |
|||
{ |
|||
ssize_t rrsize = 0; |
|||
size_t rsize = this->bsize - this->bused; |
|||
|
|||
if (0 == rsize) { |
|||
errno = ERBOVRFL; |
|||
return -1; |
|||
} |
|||
|
|||
rrsize = read(fd, this->buffer + this->bend, rsize); |
|||
|
|||
switch (rrsize) { |
|||
case 0: |
|||
rsize = -2; |
|||
|
|||
case -1: |
|||
break; |
|||
|
|||
default: |
|||
this->bend += rrsize; |
|||
this->bused += rrsize; |
|||
|
|||
if (this->bend >= this->bsize) { |
|||
this->bend -= this->bsize; |
|||
} |
|||
|
|||
break; |
|||
} |
|||
|
|||
return rrsize; |
|||
} |
|||
|
|||
// vim: set ts=4 sw=4: |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue