Commit 20af2baa6fa8fa10ca9620eaee7ca0499b35f959

Authored by Georg Hopp
1 parent 95d12d80

separated the server completely from the http processing

  1 +2012-02-15 09:38:32 +0100 Georg Hopp
  2 +
  3 + * separated the server completely from the http processing (HEAD, master)
  4 +
1 5 2012-02-15 06:19:52 +0100 Georg Hopp
2 6
3   - * add subject/observer interface (HEAD, master)
  7 + * add subject/observer interface
4 8
5 9 2012-02-15 04:55:46 +0100 Georg Hopp
6 10
7   - * fix infinite busy loop in run (origin/master, origin/HEAD)
  11 + * fix infinite busy loop in run
8 12
9 13 2012-02-15 04:44:38 +0100 Georg Hopp
10 14
... ...
1 1 VERY BIG TODO:
2 2 - give a contructor a way to fail, so that no object will be created at all
  3 +
  4 +- right now i will use long polling ajax calls when feedback from to the client
  5 + is needed. In the long term this should be changed to websockets (ws). But
  6 + right now ws specification is not final anyway. :)
... ...
... ... @@ -34,7 +34,7 @@ CLASS(HttpRequestParser) {
34 34 };
35 35
36 36 size_t httpRequestParserRead(HttpRequestParser, int);
37   -void httpRequestParserParse(HttpRequestParser);
  37 +size_t httpRequestParserParse(HttpRequestParser);
38 38 void httpRequestParserGetBody(HttpRequestParser);
39 39
40 40 void httpRequestParserGetRequestLine(HttpRequest, char *);
... ...
... ... @@ -29,7 +29,7 @@ CLASS(HttpResponseWriter) {
29 29 HttpResponseState state;
30 30 };
31 31
32   -HttpResponse httpResponseWriterWrite(HttpResponseWriter, int);
  32 +size_t httpResponseWriterWrite(HttpResponseWriter, int);
33 33
34 34 #endif // __HTTP_RESPONSE_WRITER_H__
35 35
... ...
1 1 #ifndef __HTTP_WORKER_H__
2 2 #define __HTTP_WORKER_H__
3 3
  4 +#include <sys/types.h>
  5 +
4 6 #include "class.h"
5 7 #include "http/request/parser.h"
  8 +#include "http/response/writer.h"
6 9
7 10 CLASS(HttpWorker) {
8   - HttpRequestParser parser;
  11 + HttpRequestParser parser;
  12 + HttpResponseWriter writer;
9 13 };
10 14
  15 +size_t httpWorkerProcess(HttpWorker, int);
  16 +size_t httpWorkerWrite(HttpWorker, int);
  17 +
11 18 #endif // __HTTP_WORKER_H__
12 19
13 20 // vim: set ts=4 sw=4:
... ...
... ... @@ -27,13 +27,15 @@ CLASS(Server) {
27 27 Logger logger;
28 28 Sock sock;
29 29
  30 + void * worker;
  31 +
30 32 nfds_t nfds;
31 33 struct pollfd fds[POLL_FD_NSIZE];
32 34
33 35 struct {
34 36 Sock sock;
35   - void * reader;
36   - void * writer;
  37 +
  38 + void * worker;
37 39
38 40 char keep_alive;
39 41 } conns[POLL_FD_NSIZE];
... ...
... ... @@ -15,6 +15,7 @@ RESP = http/response.c \
15 15 http/response/404.c \
16 16 http/response/image.c \
17 17 http/response/me.c
  18 +WORKER = http/worker.c http/worker/process.c http/worker/write.c
18 19 WRITER = http/response/writer.c http/response/writer/write.c
19 20 HEADER = http/header.c http/header/get.c http/header/add.c \
20 21 http/header/size_get.c http/header/to_string.c
... ... @@ -29,5 +30,6 @@ bin_PROGRAMS = testserver
29 30
30 31 testserver_SOURCES = testserver.c \
31 32 $(IFACE) $(CLASS) $(SOCKET) $(SERVER) $(LOGGER) $(MSG) $(REQ) \
32   - $(WRITER) $(RESP) $(HEADER) $(PARSER) signalHandling.c daemonize.c
  33 + $(WRITER) $(RESP) $(HEADER) $(PARSER) $(WORKER) \
  34 + signalHandling.c daemonize.c
33 35 testserver_CFLAGS = -Wall -I ../include/
... ...
... ... @@ -59,8 +59,7 @@ _clone(void * _this, void * _base)
59 59 }
60 60
61 61 INIT_IFACE(Class, ctor, dtor, _clone);
62   -INIT_IFACE(StreamReader,
63   - (fptr_streamReaderRead)httpRequestParserRead);
  62 +INIT_IFACE(StreamReader, (fptr_streamReaderRead)httpRequestParserRead);
64 63 CREATE_CLASS(HttpRequestParser, NULL, IFACE(Class), IFACE(StreamReader));
65 64
66 65 // vim: set ts=4 sw=4:
... ...
... ... @@ -33,7 +33,7 @@ httpRequestSkip(char ** data)
33 33 for (; 0 != **data && ! isalpha(**data); (*data)++);
34 34 }
35 35
36   -void
  36 +size_t
37 37 httpRequestParserParse(HttpRequestParser this)
38 38 {
39 39 char * line;
... ... @@ -111,6 +111,8 @@ httpRequestParserParse(HttpRequestParser this)
111 111 break;
112 112 }
113 113 }
  114 +
  115 + return this->request_queue->nmsgs;
114 116 }
115 117
116 118 // vim: set ts=4 sw=4:
... ...
... ... @@ -7,10 +7,10 @@
7 7 size_t
8 8 httpRequestParserRead(HttpRequestParser this, int fd)
9 9 {
10   - size_t remaining, chunks;
11   - char buffer[1024];
  10 + size_t remaining, chunks;
  11 + char buffer[1024];
12 12
13   - ssize_t size = read(fd, buffer, 1024);
  13 + size_t size = read(fd, buffer, 1024);
14 14
15 15 if (0 < size) {
16 16 remaining = this->buffer_used % HTTP_REQUEST_PARSER_READ_CHUNK;
... ... @@ -35,7 +35,7 @@ httpRequestParserRead(HttpRequestParser this, int fd)
35 35 this->buffer_used += size;
36 36 this->buffer[this->buffer_used] = 0;
37 37
38   - httpRequestParserParse(this);
  38 + size = httpRequestParserParse(this);
39 39 }
40 40
41 41 return size;
... ...
... ... @@ -38,8 +38,7 @@ _clone(void * _this, void * _base)
38 38 }
39 39
40 40 INIT_IFACE(Class, ctor, dtor, _clone);
41   -INIT_IFACE(StreamWriter,
42   - (fptr_streamWriterWrite)httpResponseWriterWrite);
  41 +INIT_IFACE(StreamWriter, (fptr_streamWriterWrite)httpResponseWriterWrite);
43 42 CREATE_CLASS(HttpResponseWriter, NULL, IFACE(Class), IFACE(StreamWriter));
44 43
45 44 // vim: set ts=4 sw=4:
... ...
... ... @@ -16,19 +16,21 @@
16 16 #define _PSIZE(x) (MAX((x),RESPONSE_WRITER_MAX_BUF))
17 17 #define PSIZE _PSIZE(this->nheader+message->nbody)
18 18
19   -HttpResponse
  19 +size_t
20 20 httpResponseWriterWrite(HttpResponseWriter this, int fd)
21 21 {
22   - HttpMessageQueue respq = this->response_queue;
23   - HttpMessage message = (HttpMessage)this->cur_response;
24   - int cont = 1;
  22 + HttpMessageQueue respq = this->response_queue;
  23 + HttpMessage message = (HttpMessage)this->cur_response;
  24 + size_t processed = (message)? 1 : 0;
  25 + int cont = 1;
25 26
26 27 while (cont) {
27 28 switch (this->state) {
28 29 case HTTP_RESPONSE_GET:
29 30 if (NULL == this->cur_response && 0 < respq->nmsgs) {
30   - message = respq->msgs[0];
  31 + message = respq->msgs[0];
31 32 this->cur_response = (HttpResponse)message;
  33 + processed++;
32 34
33 35 memmove(respq->msgs,
34 36 &(respq->msgs[1]),
... ... @@ -128,19 +130,25 @@ httpResponseWriterWrite(HttpResponseWriter this, int fd)
128 130 this->pstart = 0;
129 131 this->pend = 0;
130 132
131   - if (httpMessageHasKeepAlive(message)) {
132   - delete(&this->cur_response);
133   - }
134   - else {
135   - cont = 0;
  133 + if (! httpMessageHasKeepAlive(message)) {
  134 + /**
  135 + * if the message did not have the keep-alive feature
  136 + * we don't care about further pipelined messages and
  137 + * return the to caller with a 0 indicating that the
  138 + * underlying connection should be closed.
  139 + */
  140 + processed = 0;
  141 + cont = 0;
136 142 }
137 143
  144 + delete(&this->cur_response);
  145 +
138 146 this->state = HTTP_RESPONSE_GET;
139 147 break;
140 148 }
141 149 }
142 150
143   - return this->cur_response;
  151 + return processed;
144 152 }
145 153
146 154 // vim: set ts=4 sw=4:
... ...
  1 +#include <stdarg.h>
  2 +
  3 +#include "class.h"
  4 +#include "http/worker.h"
  5 +#include "http/request/parser.h"
  6 +#include "http/response/writer.h"
  7 +
  8 +#include "interface/class.h"
  9 +#include "interface/stream_reader.h"
  10 +#include "interface/stream_writer.h"
  11 +
  12 +static
  13 +void
  14 +ctor(void * _this, va_list * params)
  15 +{
  16 + HttpWorker this = _this;
  17 +
  18 + this->parser = new(HttpRequestParser);
  19 + this->writer = new(HttpResponseWriter);
  20 +}
  21 +
  22 +static
  23 +void
  24 +dtor(void * _this)
  25 +{
  26 + HttpWorker this = _this;
  27 +
  28 + delete(&this->parser);
  29 + delete(&this->writer);
  30 +}
  31 +
  32 +static
  33 +void
  34 +_clone(void * _this, void * _base)
  35 +{
  36 + /**
  37 + * TODO: this actually simply creates a new worker
  38 + * and ignores the base. Think about this.
  39 + */
  40 + va_list foo;
  41 +
  42 + ctor(_this, &foo);
  43 +}
  44 +
  45 +INIT_IFACE(Class, ctor, dtor, _clone);
  46 +INIT_IFACE(StreamReader, (fptr_streamReaderRead)httpWorkerProcess);
  47 +INIT_IFACE(StreamWriter, (fptr_streamWriterWrite)httpWorkerWrite);
  48 +CREATE_CLASS(
  49 + HttpWorker,
  50 + NULL,
  51 + IFACE(Class),
  52 + IFACE(StreamReader),
  53 + IFACE(StreamWriter));
  54 +
  55 +// vim: set ts=4 sw=4:
... ...
  1 +#include "class.h"
  2 +#include "interface/class.h"
  3 +
  4 +#include "http/worker.h"
  5 +#include "http/request/parser.h"
  6 +
  7 +size_t
  8 +httpWorkerProcess(HttpWorker this, int fd)
  9 +{
  10 + size_t size;
  11 +
  12 + if (0 < (size = httpRequestParserRead(this->parser, fd))) {
  13 + int i;
  14 + HttpMessageQueue reqq = this->parser->request_queue;
  15 + HttpMessageQueue respq = this->writer->response_queue;
  16 +
  17 + for (i=0; i<reqq->nmsgs; i++) {
  18 + /**
  19 + * @TODO: for now simply remove request and send not found.
  20 + * Make this sane.
  21 + */
  22 + HttpRequest request = (HttpRequest)(reqq->msgs[i]);
  23 + HttpMessage response = NULL;
  24 +
  25 + if (0 == strcmp("GET", request->method) &&
  26 + 0 == strcmp("/me/", request->uri)) {
  27 + response = (HttpMessage)httpResponseMe();
  28 + }
  29 + else if (0 == strcmp("GET", request->method) &&
  30 + 0 == strcmp("/image/", request->uri)) {
  31 + response = (HttpMessage)httpResponseImage();
  32 + }
  33 + else {
  34 + response = (HttpMessage)httpResponse404();
  35 + }
  36 +
  37 + if (httpMessageHasKeepAlive(reqq->msgs[i])) {
  38 + httpHeaderAdd(
  39 + &(response->header),
  40 + new(HttpHeader, "Connection", "Keep-Alive"));
  41 + }
  42 + else {
  43 + httpHeaderAdd(
  44 + &(response->header),
  45 + new(HttpHeader, "Connection", "Close"));
  46 + }
  47 +
  48 + respq->msgs[(respq->nmsgs)++] = response;
  49 + response = NULL;
  50 + delete(&(reqq->msgs[i]));
  51 + }
  52 +
  53 + reqq->nmsgs = 0;
  54 + }
  55 +
  56 + return size;
  57 +}
  58 +
  59 +// vim: set ts=4 sw=4:
... ...
  1 +#include <sys/types.h>
  2 +
  3 +#include "http/worker.h"
  4 +#include "http/response/writer.h"
  5 +
  6 +size_t
  7 +httpWorkerWrite(HttpWorker this, int fd)
  8 +{
  9 + return httpResponseWriterWrite(this->writer, fd);
  10 +}
  11 +
  12 +// vim: set ts=4 sw=4:
... ...
... ... @@ -20,6 +20,7 @@ ctor(void * _this, va_list * params)
20 20 int flags;
21 21
22 22 this->logger = va_arg(* params, Logger);
  23 + this->worker = va_arg(* params, void *);
23 24 port = va_arg(* params, int);
24 25 backlog = va_arg(* params, unsigned int);
25 26
... ... @@ -45,8 +46,7 @@ dtor(void * _this)
45 46 for (i=0; i<this->nfds; i++) {
46 47 if (this->sock->handle != (this->fds)[i].fd) {
47 48 delete(&(this->conns[(this->fds)[i].fd]).sock);
48   - delete(&(this->conns[(this->fds)[i].fd]).reader);
49   - delete(&(this->conns[(this->fds)[i].fd]).writer);
  49 + delete(&(this->conns[(this->fds)[i].fd]).worker);
50 50 }
51 51 }
52 52
... ...
... ... @@ -10,8 +10,7 @@ serverCloseConn(Server this, unsigned int i)
10 10 int fd = (this->fds)[i].fd;
11 11
12 12 delete(&((this->conns)[fd].sock));
13   - delete(&((this->conns)[fd].reader));
14   - delete(&((this->conns)[fd].writer));
  13 + delete(&((this->conns)[fd].worker));
15 14
16 15 (this->conns)[fd].keep_alive = 0;
17 16
... ...
... ... @@ -12,8 +12,7 @@ serverHandleAccept(Server this)
12 12 (this->conns)[acc->handle].sock = acc;
13 13
14 14 //* clone reader
15   - (this->conns)[acc->handle].reader = new(HttpRequestParser);
16   - (this->conns)[acc->handle].writer = new(HttpResponseWriter);
  15 + (this->conns)[acc->handle].worker = clone(this->worker);
17 16
18 17 (this->fds)[this->nfds].fd = acc->handle;
19 18 (this->fds)[this->nfds].events = POLLIN;
... ...
... ... @@ -5,7 +5,7 @@ serverRead(Server this, unsigned int i)
5 5 int fd = (this->fds)[i].fd;
6 6 int size;
7 7
8   - if (NULL == (this->conns)[fd].reader) {
  8 + if (NULL == (this->conns)[fd].worker) {
9 9 loggerLog(
10 10 this->logger,
11 11 LOGGER_INFO,
... ... @@ -13,7 +13,7 @@ serverRead(Server this, unsigned int i)
13 13 return -1;
14 14 }
15 15
16   - switch ((size = streamReaderRead((this->conns)[fd].reader, fd))) {
  16 + switch ((size = streamReaderRead((this->conns)[fd].worker, fd))) {
17 17 case 0:
18 18 /*
19 19 * normal close: write remaining data
... ...
... ... @@ -19,14 +19,6 @@
19 19 #include "interface/stream_writer.h"
20 20 #include "interface/logger.h"
21 21
22   -//* @TODO: to be removed
23   -#include "http/request.h"
24   -#include "http/request/parser.h"
25   -#include "http/message/queue.h"
26   -#include "http/response.h"
27   -#include "http/response/writer.h"
28   -//* until here
29   -
30 22 #undef MAX
31 23 #define MAX(x,y) ((x) > (y) ? (x) : (y))
32 24
... ... @@ -94,63 +86,17 @@ serverRun(Server this)
94 86 */
95 87 else {
96 88 nreads--;
97   - /**
98   - * do some other processing
99   - * @TODO: actually this will hard assume that our stream reader
100   - * is a http parser and it has its queue...think about more
101   - * generalizing here.
102   - */
103   - int size;
104   -
105   - if (0 >= (size=serverRead(this, i))) {
106   - serverCloseConn(this, i);
107   - }
108   - else {
109   - int j;
110   - HttpMessageQueue reqq = ((HttpRequestParser) \
111   - (this->conns)[fd].reader)->request_queue;
112   - HttpMessageQueue respq = ((HttpResponseWriter) \
113   - (this->conns)[fd].writer)->response_queue;
114   -
115   - for (j=0; j<reqq->nmsgs; j++) {
116   - /**
117   - * @TODO: for now simply remove request and send not found.
118   - * Make this sane.
119   - */
120   - HttpRequest request = (HttpRequest)(reqq->msgs[j]);
121   - HttpMessage response = NULL;
122   -
123   - if (0 == strcmp("GET", request->method) &&
124   - 0 == strcmp("/me/", request->uri)) {
125   - response = (HttpMessage)httpResponseMe();
126   - }
127   - else if (0 == strcmp("GET", request->method) &&
128   - 0 == strcmp("/image/", request->uri)) {
129   - response = (HttpMessage)httpResponseImage();
130   - }
131   - else {
132   - response = (HttpMessage)httpResponse404();
133   - }
134   -
135   - if (httpMessageHasKeepAlive(reqq->msgs[j])) {
136   - httpHeaderAdd(
137   - &(response->header),
138   - new(HttpHeader, "Connection", "Keep-Alive"));
139   - }
140   - else {
141   - httpHeaderAdd(
142   - &(response->header),
143   - new(HttpHeader, "Connection", "Close"));
144   - }
145   -
146   - respq->msgs[(respq->nmsgs)++] = response;
147   - response = NULL;
148   - delete(&(reqq->msgs[j]));
149 89
150   - (this->fds)[i].events |= POLLOUT;
151   - }
  90 + switch (serverRead(this, i)) {
  91 + case -1:
  92 + serverCloseConn(this, i);
  93 + break;
  94 +
  95 + case 0:
  96 + break;
152 97
153   - reqq->nmsgs = 0;
  98 + default:
  99 + (this->fds)[i].events |= POLLOUT;
154 100 }
155 101 }
156 102 }
... ... @@ -159,22 +105,14 @@ serverRun(Server this)
159 105 * handle writes
160 106 */
161 107 if (0 != ((this->fds)[i].revents & POLLOUT) && 0 < nwrites) {
162   - HttpResponseWriter writer =
163   - (HttpResponseWriter)(this->conns)[fd].writer;
164   - HttpMessage message;
165   -
166 108 events--;
167 109 nwrites--;
168 110
169   - message = (HttpMessage)streamWriterWrite(writer, fd);
170   -
171   - if (NULL == message) {
172   - (this->fds)[i].events &= ~POLLOUT;
173   - }
174   - else {
175   - delete(&message);
  111 + if (0 >= streamWriterWrite((this->conns)[fd].worker, fd)) {
176 112 serverCloseConn(this, i);
177 113 }
  114 +
  115 + (this->fds)[i].events &= ~POLLOUT;
178 116 }
179 117 }
180 118 }
... ...
... ... @@ -7,7 +7,7 @@
7 7
8 8 #include "server.h"
9 9 #include "logger.h"
10   -#include "http/request/parser.h"
  10 +#include "http/worker.h"
11 11
12 12 #include "signalHandling.h"
13 13
... ... @@ -18,8 +18,9 @@ void daemonize(void);
18 18 int
19 19 main()
20 20 {
21   - Logger logger = new(LoggerSyslog, LOGGER_ERR);
22   - Server server = new(Server, logger, 11212, SOMAXCONN);
  21 + Logger logger = new(LoggerSyslog, LOGGER_ERR);
  22 + HttpWorker worker = new(HttpWorker);
  23 + Server server = new(Server, logger, worker, 11212, SOMAXCONN);
23 24
24 25 struct rlimit limit = {RLIM_INFINITY, RLIM_INFINITY};
25 26 setrlimit(RLIMIT_CPU, &limit);
... ... @@ -29,6 +30,7 @@ main()
29 30 serverRun(server);
30 31
31 32 delete(&server);
  33 + delete(&worker);
32 34 delete(&logger);
33 35
34 36 return 0;
... ...
Please register or login to post a comment