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
Georg Hopp 14 years ago
parent
commit
e8a21ace31
  1. 8
      ChangeLog
  2. 87
      doc/file-upload.txt
  3. 75
      doc/file-upload2.txt
  4. 30
      include/http/request/parser.h
  5. 3
      include/http/worker.h
  6. 37
      include/ringbuffer.h
  7. 2
      include/socket.h
  8. 6
      src/Makefile.am
  9. 32
      src/http/request/parser.c
  10. 43
      src/http/request/parser/get_body.c
  11. 29
      src/http/request/parser/get_header.c
  12. 96
      src/http/request/parser/get_request_line.c
  13. 131
      src/http/request/parser/parse.c
  14. 50
      src/http/request/parser/read.c
  15. 9
      src/http/response/404.c
  16. 9
      src/http/response/image.c
  17. 9
      src/http/response/me.c
  18. 1
      src/http/response/writer/write.c
  19. 25
      src/http/worker.c
  20. 17
      src/http/worker/process.c
  21. 21
      src/rbtest.c
  22. 117
      src/ringbuffer.c
  23. 41
      src/ringbuffer/rb_read.c
  24. 8
      src/server/handle_accept.c
  25. 5
      src/socket/accept.c
  26. 2
      src/testserver.c

8
ChangeLog

@ -1,10 +1,14 @@
2012-02-18 20:12:27 +0100 Georg Hopp
* lots of changes but primarily change the request parser to use a ringbuffer. The ringbuffer is implemented using the shared memory trick. (HEAD, master)
2012-02-15 12:30:33 +0100 Georg Hopp 2012-02-15 12:30:33 +0100 Georg Hopp
* some more cleanups in the server code. Removing not needed header includes (HEAD, master)
* some more cleanups in the server code. Removing not needed header includes (origin/master, origin/HEAD)
2012-02-15 12:17:39 +0100 Georg Hopp 2012-02-15 12:17:39 +0100 Georg Hopp
* Merge branch 'master' of 192.168.100.2:/var/lib/git/server (origin/master, origin/HEAD)
* Merge branch 'master' of 192.168.100.2:/var/lib/git/server
2012-02-15 12:17:00 +0100 Georg Hopp 2012-02-15 12:17:00 +0100 Georg Hopp

87
doc/file-upload.txt

@ -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--

75
doc/file-upload2.txt

@ -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--

30
include/http/request/parser.h

@ -4,11 +4,21 @@
#include "class.h" #include "class.h"
#include "http/request.h" #include "http/request.h"
#include "http/message/queue.h" #include "http/message/queue.h"
#include "ringbuffer.h"
#define HTTP_REQUEST_PARSER_READ_CHUNK 1024
#define HTTP_REQUEST_PARSER_MAX_BUF 131072
#define REMAINS(pars) \
((pars)->buffer_used - ((pars)->cur_data - (pars)->buffer))
/**
* limits to stop invalid requests from killing
* the server.
* If any of these limits is reached the server
* will send an error message and kill the connection
* immediate.
*
* The given limits include any trailing \r\n
*/
#define HTTP_REQUEST_LINE_MAX 8192
#define HTTP_REQUEST_HEADER_LINE_MAX 2048
typedef enum e_HttpRequestState { typedef enum e_HttpRequestState {
@ -21,11 +31,7 @@ typedef enum e_HttpRequestState {
CLASS(HttpRequestParser) { CLASS(HttpRequestParser) {
char * buffer;
char * cur_data;
size_t buffer_used;
size_t buffer_size;
Ringbuffer buffer;
HttpMessageQueue request_queue; HttpMessageQueue request_queue;
HttpRequest cur_request; HttpRequest cur_request;
@ -34,11 +40,11 @@ CLASS(HttpRequestParser) {
}; };
ssize_t httpRequestParserRead(HttpRequestParser, int); ssize_t httpRequestParserRead(HttpRequestParser, int);
ssize_t httpRequestParserParse(HttpRequestParser);
void httpRequestParserGetBody(HttpRequestParser);
ssize_t httpRequestParserParse(HttpRequestParser, int);
void httpRequestParserGetRequestLine(HttpRequest, char *);
void httpRequestParserGetHeader(HttpRequest, char *);
ssize_t httpRequestParserGetRequestLine(HttpRequestParser, char *);
ssize_t httpRequestParserGetHeader(HttpRequestParser, char *);
void httpRequestParserGetBody(HttpRequestParser);
#endif /* __HTTP_REQUEST_PARSER_H__ */ #endif /* __HTTP_REQUEST_PARSER_H__ */

3
include/http/worker.h

@ -8,6 +8,9 @@
#include "http/response/writer.h" #include "http/response/writer.h"
CLASS(HttpWorker) { CLASS(HttpWorker) {
char * remoteAddr;
int handle;
HttpRequestParser parser; HttpRequestParser parser;
HttpResponseWriter writer; HttpResponseWriter writer;
}; };

37
include/ringbuffer.h

@ -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:

2
include/socket.h

@ -15,7 +15,7 @@ CLASS(Sock) {
void socketConnect(Sock this, const char * addr); void socketConnect(Sock this, const char * addr);
void socketListen(Sock this, int backlog); void socketListen(Sock this, int backlog);
Sock socketAccept(Sock this, char remoteAddr[16]);
Sock socketAccept(Sock this, char (*remoteAddr)[]);
#endif // __SOCKET_H__ #endif // __SOCKET_H__

6
src/Makefile.am

@ -5,6 +5,7 @@ IFACE = interface/class.c interface/stream_reader.c interface/logger.c \
interface/stream_writer.c interface/http_intro.c \ interface/stream_writer.c interface/http_intro.c \
interface/subject.c interface/observer.c interface/subject.c interface/observer.c
CLASS = class.c interface.c CLASS = class.c interface.c
RB = ringbuffer.c ringbuffer/rb_read.c
SOCKET = socket.c socket/accept.c socket/connect.c socket/listen.c SOCKET = socket.c socket/accept.c socket/connect.c socket/listen.c
SERVER = server.c server/run.c server/close_conn.c SERVER = server.c server/run.c server/close_conn.c
LOGGER = logger.c logger/stderr.c logger/syslog.c LOGGER = logger.c logger/stderr.c logger/syslog.c
@ -21,7 +22,7 @@ HEADER = http/header.c http/header/get.c http/header/add.c \
http/header/size_get.c http/header/to_string.c http/header/size_get.c http/header/to_string.c
PARSER = http/request/parser.c http/request/parser/get_header.c \ PARSER = http/request/parser.c http/request/parser/get_header.c \
http/request/parser/parse.c http/request/parser/get_request_line.c \ http/request/parser/parse.c http/request/parser/get_request_line.c \
http/request/parser/read.c http/request/parser/get_body.c
http/request/parser/get_body.c
AM_CFLAGS = -Wall -I ../include/ AM_CFLAGS = -Wall -I ../include/
@ -30,6 +31,7 @@ bin_PROGRAMS = testserver
testserver_SOURCES = testserver.c \ testserver_SOURCES = testserver.c \
$(IFACE) $(CLASS) $(SOCKET) $(SERVER) $(LOGGER) $(MSG) $(REQ) \ $(IFACE) $(CLASS) $(SOCKET) $(SERVER) $(LOGGER) $(MSG) $(REQ) \
$(WRITER) $(RESP) $(HEADER) $(PARSER) $(WORKER) \
$(WRITER) $(RESP) $(HEADER) $(PARSER) $(WORKER) $(RB) \
signalHandling.c daemonize.c signalHandling.c daemonize.c
testserver_CFLAGS = -Wall -I ../include/ testserver_CFLAGS = -Wall -I ../include/
testserver_LDFLAGS = -lrt

32
src/http/request/parser.c

@ -10,6 +10,7 @@
#include "http/request/parser.h" #include "http/request/parser.h"
#include "http/message/queue.h" #include "http/message/queue.h"
#include "http/request.h" #include "http/request.h"
#include "ringbuffer.h"
static static
@ -17,11 +18,10 @@ void
ctor(void * _this, va_list * params) ctor(void * _this, va_list * params)
{ {
HttpRequestParser this = _this; HttpRequestParser this = _this;
char * shm_name = va_arg(*params, char*);
this->buffer = new(Ringbuffer, shm_name, HTTP_REQUEST_LINE_MAX);
this->request_queue = new(HttpMessageQueue); this->request_queue = new(HttpMessageQueue);
this->buffer = malloc(HTTP_REQUEST_PARSER_READ_CHUNK);
this->buffer[0] = 0;
} }
static static
@ -30,36 +30,16 @@ dtor(void * _this)
{ {
HttpRequestParser this = _this; HttpRequestParser this = _this;
free(this->buffer);
delete(&(this->request_queue)); delete(&(this->request_queue));
delete(&(this->buffer));
if (NULL != this->cur_request) if (NULL != this->cur_request)
delete(&(this->cur_request)); delete(&(this->cur_request));
} }
static
void
_clone(void * _this, void * _base)
{
HttpRequestParser this = _this;
HttpRequestParser base = _base;
size_t chunks;
/**
* every parser has its own queue...
*/
this->request_queue = new(HttpMessageQueue);
this->buffer_used = base->buffer_used;
chunks = this->buffer_used / HTTP_REQUEST_PARSER_READ_CHUNK;
chunks++;
this->buffer = malloc(chunks * HTTP_REQUEST_PARSER_READ_CHUNK);
memcpy(this->buffer, base->buffer, this->buffer_used);
}
INIT_IFACE(Class, ctor, dtor, _clone);
INIT_IFACE(StreamReader, (fptr_streamReaderRead)httpRequestParserRead);
INIT_IFACE(Class, ctor, dtor, NULL);
INIT_IFACE(StreamReader, (fptr_streamReaderRead)httpRequestParserParse);
CREATE_CLASS(HttpRequestParser, NULL, IFACE(Class), IFACE(StreamReader)); CREATE_CLASS(HttpRequestParser, NULL, IFACE(Class), IFACE(StreamReader));
// vim: set ts=4 sw=4: // vim: set ts=4 sw=4:

43
src/http/request/parser/get_body.c

@ -4,33 +4,50 @@
#include "http/message.h" #include "http/message.h"
#include "http/request/parser.h" #include "http/request/parser.h"
#define MAX(x,y) ((x) > (y) ? (x) : (y))
/**
* @TODO: not final...input buffer handling not final
*/
void void
httpRequestParserGetBody(HttpRequestParser this) httpRequestParserGetBody(HttpRequestParser this)
{ {
HttpMessage message = (HttpMessage)(this->cur_request); HttpMessage message = (HttpMessage)(this->cur_request);
char * nbody;
char * str_nbody;
int nbody;
int len;
if (0 == message->nbody) {
nbody = httpHeaderGet(
str_nbody = httpHeaderGet(
&(message->header), &(message->header),
"Content-Length"); "Content-Length");
if (NULL == nbody) {
if (NULL == str_nbody) {
this->state = HTTP_REQUEST_DONE; this->state = HTTP_REQUEST_DONE;
return;
return -1;
} }
else {
nbody = atoi(str_nbody);
if (0 == message->nbody) {
message->type = HTTP_MESSAGE_BUFFERED; message->type = HTTP_MESSAGE_BUFFERED;
message->nbody = atoi(nbody);
if (0 < nbody)
message->body = malloc(nbody);
} }
len = MAX(nbody - message->nbody, this->buffer->bused);
memcpy(message->body + message->nbody,
this->buffer->buffer + this->buffer->bstart,
len);
message->nbody += len;
this->buffer->bstart += len;
if (this->buffer->bstart >= this->buffer->bsize) {
this->buffer->bstart -= this->buffer->bsize;
} }
this->buffer->bused -= len;
if (REMAINS(this) >= message->nbody) {
message->body = calloc(1, message->nbody + 1);
memcpy(message->body,
this->cur_data,
message->nbody);
this->cur_data += message->nbody;
if (message->nbody == nbody) {
this->state = HTTP_REQUEST_DONE; this->state = HTTP_REQUEST_DONE;
} }
} }

29
src/http/request/parser/get_header.c

@ -1,3 +1,5 @@
#include <stdlib.h>
#include <string.h>
#include <search.h> #include <search.h>
#include <ctype.h> #include <ctype.h>
#include <stdio.h> #include <stdio.h>
@ -6,17 +8,32 @@
#include "interface/class.h" #include "interface/class.h"
#include "http/header.h" #include "http/header.h"
#include "http/message.h" #include "http/message.h"
#include "http/request/parser.h"
#include "ringbuffer.h"
void
httpRequestParserGetHeader(HttpMessage request, char * line)
ssize_t
httpRequestParserGetHeader(HttpRequestParser this, char * cr)
{ {
char * name = line;
char * value = strchr(line, ':');
HttpMessage message = (HttpMessage)this->cur_request;
char * value;
char * name = this->buffer->buffer + this->buffer->bstart;
size_t len = cr - name;
value = memchr(
this->buffer->buffer + this->buffer->bstart,
':', len);
if (NULL == value) {
return -1;
}
*cr = 0;
*(value++) = 0; *(value++) = 0;
for (; *value == ' ' && *value != 0; value++);
while(' ' == *value) value++;
httpHeaderAdd(&(message->header), new(HttpHeader, name, value));
httpHeaderAdd(&(request->header), new(HttpHeader, name, value));
return 1; //* @TODO: return something useful here
} }
// vim: set ts=4 sw=4: // vim: set ts=4 sw=4:

96
src/http/request/parser/get_request_line.c

@ -1,31 +1,95 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "http/message.h"
#include "http/request.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; 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: // vim: set ts=4 sw=4:

131
src/http/request/parser/parse.c

@ -3,112 +3,147 @@
#include <unistd.h> #include <unistd.h>
#include <ctype.h> #include <ctype.h>
#include "http/request.h"
#include "http/message.h"
#include "http/request/parser.h" #include "http/request/parser.h"
#include "interface/class.h" #include "interface/class.h"
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
static static
inline inline
char * char *
httpRequestParserGetLine(char ** data)
getLine(HttpRequestParser this)
{ {
char * line_end = strstr(*data, "\r\n");
char * ret = *data;
char * cr = memchr(
this->buffer->buffer + this->buffer->bstart,
'\r',
this->buffer->bused);
if (NULL == line_end) {
return NULL;
}
char * nl = (NULL == cr)? NULL : cr + 1;
*line_end = 0;
*data = line_end + 2;
if (NULL != cr && NULL != nl && '\n' == *nl) {
*cr = 0;
return cr;
}
return ret;
return NULL;
} }
static static
inline inline
void
httpRequestSkip(char ** data)
char
httpRequestSkip(HttpRequestParser this)
{ {
for (; 0 != **data && ! isalpha(**data); (*data)++);
while (this->buffer->bused > 0 &&
! isalpha(this->buffer->buffer[this->buffer->bstart])) {
this->buffer->bstart = (this->buffer->bstart >= this->buffer->bsize)?
0 : this->buffer->bstart + 1;
this->buffer->bused--;
}
return (isalpha(this->buffer->buffer[this->buffer->bstart]))? TRUE : FALSE;
} }
ssize_t ssize_t
httpRequestParserParse(HttpRequestParser this)
httpRequestParserParse(HttpRequestParser this, int fd)
{ {
char * line;
int cont = 1; int cont = 1;
ssize_t ret = this->request_queue->nmsgs;
ssize_t ret;
if (0 > (ret = rbRead(this->buffer, fd))) {
cont = 0;
}
while (cont) { while (cont) {
switch(this->state) { switch(this->state) {
char * line_end;
size_t len;
case HTTP_REQUEST_GARBAGE: case HTTP_REQUEST_GARBAGE:
this->cur_data = this->buffer; // initialize static pointer
httpRequestSkip(&(this->cur_data));
if (httpRequestSkip(this)) {
this->cur_request = new(HttpRequest); this->cur_request = new(HttpRequest);
this->state = HTTP_REQUEST_START; this->state = HTTP_REQUEST_START;
}
else {
cont = 0;
}
break; break;
case HTTP_REQUEST_START: case HTTP_REQUEST_START:
if (NULL == (line = httpRequestParserGetLine(&(this->cur_data)))) {
if (NULL == (line_end = getLine(this))) {
cont = 0; cont = 0;
break; break;
} }
httpRequestParserGetRequestLine(this->cur_request, line);
if (0 > httpRequestParserGetRequestLine(this, line_end)) {
ret = -1;
cont = 0;
break;
}
len = line_end - this->buffer->buffer - this->buffer->bstart + 2;
this->buffer->bstart += len;
if (this->buffer->bstart >= this->buffer->bsize) {
this->buffer->bstart -= this->buffer->bsize;
}
this->buffer->bused -= len;
this->state = HTTP_REQUEST_REQUEST_LINE_DONE; this->state = HTTP_REQUEST_REQUEST_LINE_DONE;
break; break;
case HTTP_REQUEST_REQUEST_LINE_DONE: case HTTP_REQUEST_REQUEST_LINE_DONE:
if (NULL == (line = httpRequestParserGetLine(&(this->cur_data)))) {
if (NULL == (line_end = getLine(this))) {
cont = 0; cont = 0;
break; break;
} }
if (0 == strlen(line)) {
if (0 == line_end - this->buffer->buffer - this->buffer->bstart) {
this->buffer->bstart += 2;
if (this->buffer->bstart >= this->buffer->bsize) {
this->buffer->bstart -= this->buffer->bsize;
}
this->buffer->bused -= 2;
this->state = HTTP_REQUEST_HEADERS_DONE; this->state = HTTP_REQUEST_HEADERS_DONE;
break; break;
} }
httpRequestParserGetHeader(this->cur_request, line);
httpRequestParserGetHeader(this, line_end);
len = line_end - this->buffer->buffer - this->buffer->bstart + 2;
this->buffer->bstart += len;
if (this->buffer->bstart >= this->buffer->bsize) {
this->buffer->bstart -= this->buffer->bsize;
}
this->buffer->bused -= len;
break; break;
case HTTP_REQUEST_HEADERS_DONE: case HTTP_REQUEST_HEADERS_DONE:
/**
* allocate memory according to content-length.
* If content length is to large reject request.
*
* @FUTURE check for multipart mime and handle it
* with temporary file.
*/
httpRequestParserGetBody(this); httpRequestParserGetBody(this);
break; break;
case HTTP_REQUEST_DONE: case HTTP_REQUEST_DONE:
/**
* enqueue current request
*/
this->request_queue->msgs[(this->request_queue->nmsgs)++] = this->request_queue->msgs[(this->request_queue->nmsgs)++] =
(HttpMessage)this->cur_request; (HttpMessage)this->cur_request;
if (! httpMessageHasKeepAlive((HttpMessage)this->cur_request)) {
ret = -2;
}
ret = this->request_queue->nmsgs;
this->cur_request = NULL; this->cur_request = NULL;
/**
* remove processed stuff from input buffer.
*/
memmove(this->buffer, this->cur_data, REMAINS(this));
this->buffer_used -= this->cur_data - this->buffer;
/**
* dont continue loop if input buffer is empty
*/
if (0 == this->buffer_used) {
cont = 0;
}
/**
* prepare for next request
*/
this->state = HTTP_REQUEST_GARBAGE; this->state = HTTP_REQUEST_GARBAGE;
break; break;
@ -118,7 +153,7 @@ httpRequestParserParse(HttpRequestParser this)
} }
} }
return this->request_queue->nmsgs;
return ret;
} }
// vim: set ts=4 sw=4: // vim: set ts=4 sw=4:

50
src/http/request/parser/read.c

@ -3,46 +3,40 @@
#include "http/request/parser.h" #include "http/request/parser.h"
#define MAX(x,y) ((x) > (y) ? (x) : (y))
#define _BSIZE(x) (MAX((x),RESPONSE_WRITER_MAX_BUF))
#define BSIZE _BSIZE(this->nheader+message->nbody)
/**
* @deprecated
*/
ssize_t ssize_t
httpRequestParserRead(HttpRequestParser this, int fd) httpRequestParserRead(HttpRequestParser this, int fd)
{ {
size_t remaining, chunks;
char buffer[1024];
size_t rsize;
ssize_t temp;
ssize_t size = read(fd, buffer, 1024);
this->bend = (this->bsize == this->bend)?
0 : this->bend;
if (0 < size) {
remaining = this->buffer_used % HTTP_REQUEST_PARSER_READ_CHUNK;
remaining = HTTP_REQUEST_PARSER_READ_CHUNK - remaining;
chunks = this->buffer_used / HTTP_REQUEST_PARSER_READ_CHUNK;
rsize = (this->bstart <= this->bend)?
this->bsize - this->bend :
this->bstart - 1;
if (0 >= (temp = read(fd, &(this->buffer[this->bend]), rsize))) {
/** /**
* because a division always rounds down
* chunks holds exactly the currently allocated chunks if
* remaining equals 0 but there is no space left.
* Else chunks holds the actually allocated amount of chunks
* minus 1.
* For this reason chunks always has to be increased by 1.
* this means either we had an rsize of 0 what indicates that
* the buffer ran full without any processing took place or
* the connection was terminated in some way. In both cases
* we want to terminate the connection.
*/ */
chunks++;
if (size >= remaining) {
this->buffer =
realloc(this->buffer, chunks * HTTP_REQUEST_PARSER_READ_CHUNK);
return (0 == temp)? -2 : -1;
} }
memcpy(this->buffer + this->buffer_used, buffer, size);
this->buffer_used += size;
this->buffer[this->buffer_used] = 0;
size = httpRequestParserParse(this);
}
else {
size = (0 == size)? -2 : size;
}
this->bend += temp;
return size;
return temp;
} }
// vim: set ts=4 sw=4: // vim: set ts=4 sw=4:

9
src/http/response/404.c

@ -1,7 +1,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <time.h>
#include "class.h" #include "class.h"
#include "interface/class.h" #include "interface/class.h"
@ -23,8 +22,6 @@
HttpResponse HttpResponse
httpResponse404() httpResponse404()
{ {
time_t t;
struct tm * tmp;
char buffer[200]; char buffer[200];
HttpResponse response; HttpResponse response;
HttpMessage message; HttpMessage message;
@ -46,12 +43,6 @@ httpResponse404()
httpHeaderAdd(&(message->header), httpHeaderAdd(&(message->header),
new(HttpHeader, "Content-Length", buffer)); new(HttpHeader, "Content-Length", buffer));
t = time(NULL);
tmp = localtime(&t);
strftime(buffer, sizeof(buffer), "%a, %d %b %Y %T %Z", tmp);
httpHeaderAdd(&(message->header),
new(HttpHeader, "Date", buffer));
return response; return response;
} }

9
src/http/response/image.c

@ -1,7 +1,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <time.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
@ -16,8 +15,6 @@
HttpResponse HttpResponse
httpResponseImage() httpResponseImage()
{ {
time_t t;
struct tm * tmp;
char buffer[200]; char buffer[200];
struct stat st; struct stat st;
HttpResponse response; HttpResponse response;
@ -40,12 +37,6 @@ httpResponseImage()
httpHeaderAdd(&(message->header), httpHeaderAdd(&(message->header),
new(HttpHeader, "Content-Length", buffer)); new(HttpHeader, "Content-Length", buffer));
t = time(NULL);
tmp = localtime(&t);
strftime(buffer, sizeof(buffer), "%a, %d %b %Y %T %Z", tmp);
httpHeaderAdd(&(message->header),
new(HttpHeader, "Date", buffer));
return response; return response;
} }

9
src/http/response/me.c

@ -1,7 +1,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <time.h>
#include "class.h" #include "class.h"
#include "interface/class.h" #include "interface/class.h"
@ -23,8 +22,6 @@
HttpResponse HttpResponse
httpResponseMe() httpResponseMe()
{ {
time_t t;
struct tm * tmp;
char buffer[200]; char buffer[200];
HttpResponse response; HttpResponse response;
HttpMessage message; HttpMessage message;
@ -46,12 +43,6 @@ httpResponseMe()
httpHeaderAdd(&(message->header), httpHeaderAdd(&(message->header),
new(HttpHeader, "Content-Length", buffer)); new(HttpHeader, "Content-Length", buffer));
t = time(NULL);
tmp = localtime(&t);
strftime(buffer, sizeof(buffer), "%a, %d %b %Y %T %Z", tmp);
httpHeaderAdd(&(message->header),
new(HttpHeader, "Date", buffer));
return response; return response;
} }

1
src/http/response/writer/write.c

@ -74,7 +74,6 @@ httpResponseWriterWrite(HttpResponseWriter this, int fd)
&(this->pipe[this->pend]), &(this->pipe[this->pend]),
&(message->body[this->nbuffer]), &(message->body[this->nbuffer]),
temp); temp);
break; break;
case HTTP_MESSAGE_PIPED: case HTTP_MESSAGE_PIPED:

25
src/http/worker.c

@ -1,4 +1,6 @@
#include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
#include <string.h>
#include "class.h" #include "class.h"
#include "http/worker.h" #include "http/worker.h"
@ -9,13 +11,19 @@
#include "interface/stream_reader.h" #include "interface/stream_reader.h"
#include "interface/stream_writer.h" #include "interface/stream_writer.h"
#define SHMN "/worker_"
static static
void void
ctor(void * _this, va_list * params) ctor(void * _this, va_list * params)
{ {
HttpWorker this = _this; HttpWorker this = _this;
char id[sizeof(SHMN) + 15 + 5];
this->parser = new(HttpRequestParser);
this->remoteAddr = va_arg(*params, char *);
this->handle = va_arg(*params, int);
sprintf(id, SHMN "%s_%05d", this->remoteAddr, this->handle);
this->parser = new(HttpRequestParser, id);
this->writer = new(HttpResponseWriter); this->writer = new(HttpResponseWriter);
} }
@ -29,20 +37,7 @@ dtor(void * _this)
delete(&this->writer); delete(&this->writer);
} }
static
void
_clone(void * _this, void * _base)
{
/**
* TODO: this actually simply creates a new worker
* and ignores the base. Think about this.
*/
va_list foo;
ctor(_this, &foo);
}
INIT_IFACE(Class, ctor, dtor, _clone);
INIT_IFACE(Class, ctor, dtor, NULL);
INIT_IFACE(StreamReader, (fptr_streamReaderRead)httpWorkerProcess); INIT_IFACE(StreamReader, (fptr_streamReaderRead)httpWorkerProcess);
INIT_IFACE(StreamWriter, (fptr_streamWriterWrite)httpWorkerWrite); INIT_IFACE(StreamWriter, (fptr_streamWriterWrite)httpWorkerWrite);
CREATE_CLASS( CREATE_CLASS(

17
src/http/worker/process.c

@ -1,15 +1,23 @@
#include <time.h>
#include "class.h" #include "class.h"
#include "interface/class.h" #include "interface/class.h"
#include "http/worker.h" #include "http/worker.h"
#include "http/request/parser.h" #include "http/request/parser.h"
#include "http/header.h"
#include "http/request.h"
#include "http/message.h"
ssize_t ssize_t
httpWorkerProcess(HttpWorker this, int fd) httpWorkerProcess(HttpWorker this, int fd)
{ {
time_t t;
struct tm * tmp;
char buffer[200];
ssize_t size; ssize_t size;
if (0 < (size = httpRequestParserRead(this->parser, fd))) {
if (0 < (size = httpRequestParserParse(this->parser, fd))) {
int i; int i;
HttpMessageQueue reqq = this->parser->request_queue; HttpMessageQueue reqq = this->parser->request_queue;
HttpMessageQueue respq = this->writer->response_queue; HttpMessageQueue respq = this->writer->response_queue;
@ -45,12 +53,19 @@ httpWorkerProcess(HttpWorker this, int fd)
new(HttpHeader, "Connection", "Close")); new(HttpHeader, "Connection", "Close"));
} }
t = time(NULL);
tmp = localtime(&t);
strftime(buffer, sizeof(buffer), "%a, %d %b %Y %T %Z", tmp);
httpHeaderAdd(&(response->header),
new(HttpHeader, "Date", buffer));
respq->msgs[(respq->nmsgs)++] = response; respq->msgs[(respq->nmsgs)++] = response;
response = NULL; response = NULL;
delete(&(reqq->msgs[i])); delete(&(reqq->msgs[i]));
} }
reqq->nmsgs = 0; reqq->nmsgs = 0;
size = respq->nmsgs;
} }
return size; return size;

21
src/rbtest.c

@ -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:

117
src/ringbuffer.c

@ -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:

41
src/ringbuffer/rb_read.c

@ -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:

8
src/server/handle_accept.c

@ -1,20 +1,22 @@
#include <errno.h> #include <errno.h>
#include "http/worker.h"
static static
int int
serverHandleAccept(Server this) serverHandleAccept(Server this)
{ {
char remoteAddr[16] = "";
char remoteAddr[16] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
Sock acc; Sock acc;
acc = socketAccept(this->sock, remoteAddr);
acc = socketAccept(this->sock, &remoteAddr);
if (-1 != acc->handle) { if (-1 != acc->handle) {
//* save the socket handle //* save the socket handle
(this->conns)[acc->handle].sock = acc; (this->conns)[acc->handle].sock = acc;
//* clone reader //* clone reader
(this->conns)[acc->handle].worker = clone(this->worker);
(this->conns)[acc->handle].worker = new(HttpWorker, remoteAddr, acc->handle);
(this->fds)[this->nfds].fd = acc->handle; (this->fds)[this->nfds].fd = acc->handle;
(this->fds)[this->nfds].events = POLLIN; (this->fds)[this->nfds].events = POLLIN;

5
src/socket/accept.c

@ -6,7 +6,7 @@
#include "interface/logger.h" #include "interface/logger.h"
Sock Sock
socketAccept(Sock this, char remoteAddr[16])
socketAccept(Sock this, char (*remoteAddr)[])
{ {
Sock sock; /* Socket for client */ Sock sock; /* Socket for client */
unsigned int len; /* Length of client address data structure */ unsigned int len; /* Length of client address data structure */
@ -33,8 +33,9 @@ socketAccept(Sock this, char remoteAddr[16])
loggerLog(this->log, LOGGER_WARNING, loggerLog(this->log, LOGGER_WARNING,
"error accepting connection: %s", strerror(errno)); "error accepting connection: %s", strerror(errno));
} else { } else {
memcpy(*remoteAddr, inet_ntoa((sock->addr).sin_addr), 15);
loggerLog(this->log, LOGGER_INFO, loggerLog(this->log, LOGGER_INFO,
"handling client %s\n", inet_ntoa((sock->addr).sin_addr));
"handling client %s\n", *remoteAddr);
} }
return sock; return sock;

2
src/testserver.c

@ -19,7 +19,7 @@ int
main() main()
{ {
Logger logger = new(LoggerSyslog, LOGGER_ERR); Logger logger = new(LoggerSyslog, LOGGER_ERR);
HttpWorker worker = new(HttpWorker);
HttpWorker worker = new(HttpWorker, "", 0);
Server server = new(Server, logger, worker, 11212, SOMAXCONN); Server server = new(Server, logger, worker, 11212, SOMAXCONN);
struct rlimit limit = {RLIM_INFINITY, RLIM_INFINITY}; struct rlimit limit = {RLIM_INFINITY, RLIM_INFINITY};

Loading…
Cancel
Save