Commit 20af2baa6fa8fa10ca9620eaee7ca0499b35f959
1 parent
95d12d80
separated the server completely from the http processing
Showing
21 changed files
with
204 additions
and
113 deletions
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 *); | ... | ... |
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: | ... | ... |
src/http/worker.c
0 → 100644
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: | ... | ... |
src/http/worker/process.c
0 → 100644
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: | ... | ... |
src/http/worker/write.c
0 → 100644
... | ... | @@ -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