Commit cb75a749e948a90ce5141f0f80891ab338dbb356

Authored by Georg Hopp
1 parent 8e4e3dae

start split of request parser

  1 +2012-02-09 22:34:32 +0100 Georg Hopp
  2 +
  3 + * start split of request parser (HEAD, master)
  4 +
1 2012-02-09 11:44:17 +0100 Georg Hopp 5 2012-02-09 11:44:17 +0100 Georg Hopp
2 6
3 - * no more request body debig output (HEAD, master) 7 + * no more request body debig output (origin/master, origin/HEAD)
4 8
5 2012-02-09 11:32:28 +0100 Georg Hopp 9 2012-02-09 11:32:28 +0100 Georg Hopp
6 10
  1 +#ifndef __HTTP_HEADER_H__
  2 +#define __HTTP_HEADER_H__
  3 +
  4 +#include "class.h"
  5 +
  6 +CLASS(HttpHeader) {
  7 + unsigned long hash;
  8 + char * name;
  9 + char * value;
  10 +};
  11 +
  12 +HttpHeader httpHeaderParse(char * line); // @INFO: destructive
  13 +void httpHeaderSort(const HttpHeader [], int);
  14 +char * httpHeaderGet(const HttpHeader [], int, const char *);
  15 +
  16 +#endif // __HTTP_HEADER_H__
  17 +
  18 +// vim: set ts=4 sw=4:
@@ -2,21 +2,18 @@ @@ -2,21 +2,18 @@
2 #define __HTTP_REQUEST_H__ 2 #define __HTTP_REQUEST_H__
3 3
4 #include "class.h" 4 #include "class.h"
  5 +#include "http/header.h"
5 6
6 CLASS(HttpRequest) { 7 CLASS(HttpRequest) {
7 - char * http_version;  
8 - char * uri;  
9 - char * method; 8 + char * method;
  9 + char * uri;
  10 + char * version;
10 11
11 - struct HttpRequestHeader {  
12 - unsigned long hash;  
13 - char * name;  
14 - char * value;  
15 - } header[128];  
16 - int nheader; 12 + HttpHeader header[128];
  13 + int nheader;
17 14
18 - char * body;  
19 - int nbody; 15 + char * body;
  16 + int nbody;
20 }; 17 };
21 18
22 char * 19 char *
  1 +#ifndef __HTTP_RESPONSE_H__
  2 +#define __HTTP_RESPONSE_H__
  3 +
  4 +#include "class.h"
  5 +
  6 +CLASS(HttpResponse) {
  7 + char * http_version;
  8 + char * status;
  9 + char * reson;
  10 +
  11 + HttpHeader header[128];
  12 + int nheader;
  13 +
  14 + char * body;
  15 + int nbody;
  16 +};
  17 +
  18 +char *
  19 +httpRequestHeaderGet(HttpRequest this, const char * name);
  20 +
  21 +#endif /* __HTTP_RESPONSE_H__ */
  22 +
  23 +// vim: set ts=4 sw=4:
@@ -5,7 +5,10 @@ CLASS = class.c interface.c interface/class.c @@ -5,7 +5,10 @@ CLASS = class.c interface.c interface/class.c
5 SOCKET = socket.c socket/accept.c socket/connect.c socket/listen.c 5 SOCKET = socket.c socket/accept.c socket/connect.c socket/listen.c
6 SERVER = server.c server/run.c server/close_conn.c 6 SERVER = server.c server/run.c server/close_conn.c
7 LOGGER = logger.c logger/stderr.c logger/syslog.c interface/logger.c 7 LOGGER = logger.c logger/stderr.c logger/syslog.c interface/logger.c
8 -HTTP = interface/stream_reader.c http/request_parser.c http/request.c http/request_queue.c http/request/header_get.c 8 +HTTP = interface/stream_reader.c http/request/parser.c http/request.c \
  9 + http/request/queue.c http/header.c http/header/get.c \
  10 + http/header/sort.c http/request/parser/get_header.c \
  11 + http/request/parser/parse.c http/request/parser/get_request_line.c
9 12
10 AM_CFLAGS = -Wall -I ../include/ 13 AM_CFLAGS = -Wall -I ../include/
11 14
  1 +#include <stdlib.h>
  2 +#include <string.h>
  3 +#include <ctype.h>
  4 +
  5 +#include "class.h"
  6 +#include "interface/class.h"
  7 +
  8 +#include "http/header.h"
  9 +
  10 +/**
  11 + * SDBM hashing algorithm:
  12 + *
  13 + * this algorithm was created for sdbm (a public-domain reimplementation of
  14 + * ndbm) database library. it was found to do well in scrambling bits,
  15 + * causing better distribution of the keys and fewer splits. it also happens
  16 + * to be a good general hashing function with good distribution. the actual
  17 + * function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below
  18 + * is the faster version used in gawk. [there is even a faster, duff-device
  19 + * version] the magic constant 65599 was picked out of thin air while
  20 + * experimenting with different constants, and turns out to be a prime. this
  21 + * is one of the algorithms used in berkeley db (see sleepycat) and elsewhere.
  22 + */
  23 +static
  24 +inline
  25 +unsigned long
  26 +sdbm(unsigned char * str)
  27 +{
  28 + unsigned long hash = 0;
  29 + int c;
  30 +
  31 + while ((c = tolower(*str++)))
  32 + hash = c + (hash << 6) + (hash << 16) - hash;
  33 +
  34 + return hash;
  35 +}
  36 +
  37 +static
  38 +void
  39 +ctor(void * _this, va_list * params) {
  40 + HttpHeader this = _this;
  41 + char * name;
  42 + char * value;
  43 +
  44 + name = va_arg(* params, char *);
  45 + value = va_arg(* params, char *);
  46 +
  47 + this->name = malloc(strlen(name) + 1);
  48 + strcpy(this->name, name);
  49 +
  50 + this->hash = sdbm((unsigned char *)name);
  51 +
  52 + this->value = malloc(strlen(value) + 1);
  53 + strcpy(this->value, value);
  54 +}
  55 +
  56 +static
  57 +void
  58 +dtor(void * _this)
  59 +{
  60 + HttpHeader this = _this;
  61 +
  62 + free(this->name);
  63 + free(this->value);
  64 +}
  65 +
  66 +INIT_IFACE(Class, ctor, dtor, NULL);
  67 +CREATE_CLASS(HttpHeader, NULL, IFACE(Class));
  68 +
  69 +// vim: set ts=4 sw=4:
  1 +#include <stdlib.h>
  2 +#include <ctype.h>
  3 +
  4 +#include "http/header.h"
  5 +
  6 +static
  7 +inline
  8 +unsigned long
  9 +sdbm(const unsigned char * str)
  10 +{
  11 + unsigned long hash = 0;
  12 + int c;
  13 +
  14 + while ((c = tolower(*str++)))
  15 + hash = c + (hash << 6) + (hash << 16) - hash;
  16 +
  17 + return hash;
  18 +}
  19 +
  20 +static
  21 +inline
  22 +int
  23 +comp (const void * _a, const void * _b)
  24 +{
  25 + unsigned long a = *(unsigned long *)_a;
  26 + const HttpHeader b = *(const HttpHeader *)_b;
  27 + return (a < b->hash)? -1 : (a > b->hash)? 1 : 0;
  28 +}
  29 +
  30 +char *
  31 +httpHeaderGet(const HttpHeader header[], int nheader, const char * name)
  32 +{
  33 + unsigned long hash = sdbm((unsigned char *)name);
  34 + HttpHeader found;
  35 +
  36 + found = bsearch(&hash, header, nheader, sizeof(HttpHeader), comp);
  37 +
  38 + return (NULL != found)? found->value : NULL;
  39 +}
  40 +
  41 +// vim: set ts=4 sw=4:
  1 +#include "http/header.h"
  2 +
  3 +static
  4 +inline
  5 +int
  6 +comp (const void * _a, const void * _b)
  7 +{
  8 + const HttpHeader a = *(const HttpHeader *)_a;
  9 + const HttpHeader b = *(const HttpHeader *)_b;
  10 + return (a->hash < b->hash)? -1 : (a->hash > b->hash)? 1 : 0;
  11 +}
  12 +
  13 +void
  14 +httpHeaderSort(const HttpHeader header[], int nheader)
  15 +{
  16 + qsort(header, nheader, sizeof(HttpHeader), comp);
  17 +}
  18 +
  19 +// vim: set ts=4 sw=4:
@@ -26,13 +26,13 @@ dtor(void * _this) @@ -26,13 +26,13 @@ dtor(void * _this)
26 HttpRequest this = _this; 26 HttpRequest this = _this;
27 int i; 27 int i;
28 28
29 - _free((void **)&(this->http_version)); 29 + _free((void **)&(this->version));
30 _free((void **)&(this->uri)); 30 _free((void **)&(this->uri));
31 _free((void **)&(this->method)); 31 _free((void **)&(this->method));
32 32
33 for (i=0; i<128; i++) { 33 for (i=0; i<128; i++) {
34 - _free((void **)&((this->header)[i].name));  
35 - _free((void **)&((this->header)[i].value)); 34 + if (NULL == (this->header)[i]) break;
  35 + delete(&(this->header)[i]);
36 } 36 }
37 37
38 _free((void **)&(this->body)); 38 _free((void **)&(this->body));
1 -#include <stdlib.h>  
2 #include <string.h> 1 #include <string.h>
3 #include <stdlib.h> 2 #include <stdlib.h>
4 -#include <stdio.h>  
5 -#include <unistd.h>  
6 -#include <ctype.h>  
7 #include <sys/types.h> 3 #include <sys/types.h>
8 4
9 #include "class.h" 5 #include "class.h"
@@ -13,9 +9,7 @@ @@ -13,9 +9,7 @@
13 #include "http/request.h" 9 #include "http/request.h"
14 #include "http/request_queue.h" 10 #include "http/request_queue.h"
15 11
16 -static  
17 -void  
18 -httpRequestParserParse(HttpRequestParser); 12 +void httpRequestParserParse(HttpRequestParser);
19 13
20 static 14 static
21 void 15 void
@@ -103,221 +97,4 @@ INIT_IFACE(Class, ctor, dtor, _clone); @@ -103,221 +97,4 @@ INIT_IFACE(Class, ctor, dtor, _clone);
103 INIT_IFACE(StreamReader, get_data); 97 INIT_IFACE(StreamReader, get_data);
104 CREATE_CLASS(HttpRequestParser, NULL, IFACE(Class), IFACE(StreamReader)); 98 CREATE_CLASS(HttpRequestParser, NULL, IFACE(Class), IFACE(StreamReader));
105 99
106 -static  
107 -inline  
108 -char *  
109 -httpRequestLineGet(char ** data)  
110 -{  
111 - char * line_end = strstr(*data, "\r\n");  
112 - char * ret = *data;  
113 -  
114 - if (NULL == line_end) {  
115 - return NULL;  
116 - }  
117 -  
118 - *line_end = 0;  
119 - *data = line_end + 2;  
120 -  
121 - return ret;  
122 -}  
123 -  
124 -static  
125 -inline  
126 -void  
127 -httpRequestSkip(char ** data)  
128 -{  
129 - for (; 0 != **data && ! isalpha(**data); (*data)++);  
130 -}  
131 -  
132 -/**  
133 - * SDBM hashing algorithm:  
134 - *  
135 - * this algorithm was created for sdbm (a public-domain reimplementation of  
136 - * ndbm) database library. it was found to do well in scrambling bits,  
137 - * causing better distribution of the keys and fewer splits. it also happens  
138 - * to be a good general hashing function with good distribution. the actual  
139 - * function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below  
140 - * is the faster version used in gawk. [there is even a faster, duff-device  
141 - * version] the magic constant 65599 was picked out of thin air while  
142 - * experimenting with different constants, and turns out to be a prime. this  
143 - * is one of the algorithms used in berkeley db (see sleepycat) and elsewhere.  
144 - */  
145 -static  
146 -inline  
147 -unsigned long  
148 -sdbm(unsigned char * str)  
149 -{  
150 - unsigned long hash = 0;  
151 - int c;  
152 -  
153 - while ((c = tolower(*str++)))  
154 - hash = c + (hash << 6) + (hash << 16) - hash;  
155 -  
156 - return hash;  
157 -}  
158 -  
159 -static  
160 -inline  
161 -int  
162 -comp (const void * _a, const void * _b)  
163 -{  
164 - const struct HttpRequestHeader * a = _a;  
165 - const struct HttpRequestHeader * b = _b;  
166 - return (a->hash < b->hash)? -1 : (a->hash > b->hash)? 1 : 0;  
167 -}  
168 -  
169 -static  
170 -void  
171 -httpRequestParserParse(HttpRequestParser this)  
172 -{  
173 - static HttpRequest request = NULL;  
174 - static char * data; // static pointer to unprocessed data  
175 - char * line;  
176 - int cont = 1;  
177 - static int header_idx;  
178 -  
179 - while(cont) {  
180 - switch(this->state) {  
181 - case HTTP_REQUEST_GARBAGE:  
182 - data = this->buffer; // initialize static pointer  
183 - httpRequestSkip(&data);  
184 - request = new(HttpRequest);  
185 -  
186 - this->state = HTTP_REQUEST_START;  
187 - break;  
188 -  
189 - case HTTP_REQUEST_START:  
190 - if (NULL == (line = httpRequestLineGet(&data))) {  
191 - cont = 0;  
192 - break;  
193 - }  
194 -  
195 - {  
196 - char * delim = strchr(line, ' ');  
197 -  
198 - if (NULL != delim) {  
199 - *delim = 0;  
200 - request->method = malloc(strlen(line) + 1);  
201 - strcpy(request->method, line);  
202 - line = delim + 1;  
203 -  
204 - for (; *line == ' ' && *line != 0; line++);  
205 -  
206 - if (0 != *line) {  
207 - delim = strchr(line, ' ');  
208 -  
209 - if (NULL != delim) {  
210 - *delim = 0;  
211 - request->uri = malloc(strlen(line) + 1);  
212 - strcpy(request->uri, line);  
213 - line = delim + 1;  
214 -  
215 - for (; *line == ' ' && *line != 0; line++);  
216 -  
217 - if (0 != *line) {  
218 - request->http_version = malloc(strlen(line) + 1);  
219 - strcpy(request->http_version, line);  
220 - }  
221 - }  
222 - }  
223 - }  
224 - }  
225 -  
226 - header_idx = 0;  
227 - this->state = HTTP_REQUEST_REQUEST_LINE_DONE;  
228 - break;  
229 -  
230 - case HTTP_REQUEST_REQUEST_LINE_DONE:  
231 - if (NULL == (line = httpRequestLineGet(&data))) {  
232 - cont = 0;  
233 - break;  
234 - }  
235 -  
236 - if (0 == strlen(line)) {  
237 - this->state = HTTP_REQUEST_HEADERS_DONE;  
238 - break;  
239 - }  
240 -  
241 - {  
242 - char * delim = strchr(line, ':');  
243 -  
244 - *delim = 0;  
245 - (request->header)[header_idx].name = malloc(strlen(line) + 1);  
246 - strcpy((request->header)[header_idx].name, line);  
247 - (request->header)[header_idx].hash = sdbm((unsigned char *)line);  
248 -  
249 - line = delim + 1;  
250 - for (; *line == ' ' && *line != 0; line++);  
251 -  
252 - (request->header)[header_idx].value = malloc(strlen(line) + 1);  
253 - strcpy((request->header)[header_idx].value, line);  
254 -  
255 - header_idx++;  
256 - request->nheader++;  
257 - }  
258 -  
259 - break;  
260 -  
261 - case HTTP_REQUEST_HEADERS_DONE:  
262 - /**  
263 - * @TODO: here comes the body handling  
264 - */  
265 - qsort(  
266 - request->header,  
267 - request->nheader,  
268 - sizeof(struct HttpRequestHeader),  
269 - comp);  
270 -  
271 - {  
272 - char * bodylen;  
273 -  
274 - bodylen = httpRequestHeaderGet(request, "Content-Length");  
275 -  
276 - if (NULL != bodylen) {  
277 - request->nbody = atoi(bodylen);  
278 - request->body = calloc(1, request->nbody + 1);  
279 - memcpy(request->body, data, request->nbody);  
280 - data += request->nbody;  
281 - }  
282 - }  
283 -  
284 - this->state = HTTP_REQUEST_DONE;  
285 - break;  
286 -  
287 - case HTTP_REQUEST_DONE:  
288 - /**  
289 - * enqueue current request  
290 - */  
291 - this->request_queue->requests[(this->request_queue->nrequests)++] =  
292 - request;  
293 -  
294 - /**  
295 - * remove processed stuff from input buffer.  
296 - */  
297 - memmove(this->buffer,  
298 - data,  
299 - this->buffer_used - (data - this->buffer) + 1);  
300 -  
301 - this->buffer_used -= data - this->buffer;  
302 -  
303 - /**  
304 - * dont continue loop if input buffer is empty  
305 - */  
306 - if (0 == this->buffer_used) {  
307 - cont = 0;  
308 - }  
309 -  
310 - /**  
311 - * prepare for next request  
312 - */  
313 - this->state = HTTP_REQUEST_GARBAGE;  
314 -  
315 - break;  
316 -  
317 - default:  
318 - break;  
319 - }  
320 - }  
321 -}  
322 -  
323 // vim: set ts=4 sw=4: 100 // vim: set ts=4 sw=4:
  1 +#include "class.h"
  2 +#include "interface/class.h"
  3 +#include "http/header.h"
  4 +#include "http/request.h"
  5 +
  6 +void
  7 +httpRequestParserGetHeader(HttpRequest request, char * line)
  8 +{
  9 + char * name = line;
  10 + char * value = strchr(line, ':');
  11 +
  12 + *value = 0;
  13 + for (; *value == ' ' && *value != 0; value++);
  14 +
  15 + (request->header)[request->nheader++] = new(HttpHeader, name, value);
  16 +}
  17 +
  18 +// vim: set ts=4 sw=4:
  1 +#include <string.h>
  2 +
  3 +#include "http/request.h"
  4 +
  5 +
  6 +void
  7 +httpRequestParserGetRequestLine(HttpRequest request, char * line)
  8 +{
  9 + char * method, * uri, * version;
  10 +
  11 + method = line;
  12 +
  13 + uri = strchr(line, ' ');
  14 + *uri++ = 0;
  15 + for (; *uri == ' ' && *uri != 0; uri++);
  16 +
  17 + version = strchr(uri, ' ');
  18 + *version++ = 0;
  19 + for (; *version == ' ' && *version != 0; version++);
  20 +
  21 + request->method = malloc(strlen(method) + 1);
  22 + strcpy(request->method, method);
  23 + request->uri = malloc(strlen(uri) + 1);
  24 + strcpy(request->uri, uri);
  25 + request->version = malloc(strlen(version) + 1);
  26 + strcpy(request->version, method);
  27 +}
  28 +
  29 +// vim: set ts=4 sw=4:
  1 +#include <stdlib.h>
  2 +#include <string.h>
  3 +#include <unistd.h>
  4 +#include <ctype.h>
  5 +
  6 +#include "http/request_parser.h"
  7 +#include "interface/class.h"
  8 +
  9 +
  10 +#define REMAINS(pars,done) \
  11 + ((pars)->buffer_used - ((done) - (pars)->buffer))
  12 +
  13 +
  14 +static
  15 +inline
  16 +char *
  17 +httpRequestParserGetLine(char ** data)
  18 +{
  19 + char * line_end = strstr(*data, "\r\n");
  20 + char * ret = *data;
  21 +
  22 + if (NULL == line_end) {
  23 + return NULL;
  24 + }
  25 +
  26 + *line_end = 0;
  27 + *data = line_end + 2;
  28 +
  29 + return ret;
  30 +}
  31 +
  32 +static
  33 +inline
  34 +void
  35 +httpRequestSkip(char ** data)
  36 +{
  37 + for (; 0 != **data && ! isalpha(**data); (*data)++);
  38 +}
  39 +
  40 +void httpRequestParserGetRequestLine(HttpRequest, char *);
  41 +
  42 +void
  43 +httpRequestParserParse(HttpRequestParser this)
  44 +{
  45 + static HttpRequest request = NULL;
  46 + static char * data; // static pointer to unprocessed data
  47 + char * line;
  48 + int cont = 1;
  49 +
  50 + while(cont) {
  51 + switch(this->state) {
  52 + case HTTP_REQUEST_GARBAGE:
  53 + data = this->buffer; // initialize static pointer
  54 + httpRequestSkip(&data);
  55 + request = new(HttpRequest);
  56 +
  57 + this->state = HTTP_REQUEST_START;
  58 + break;
  59 +
  60 + case HTTP_REQUEST_START:
  61 + if (NULL == (line = httpRequestParserGetLine(&data))) {
  62 + cont = 0;
  63 + break;
  64 + }
  65 +
  66 + httpRequestParserGetRequestLine(request, line);
  67 +
  68 + this->state = HTTP_REQUEST_REQUEST_LINE_DONE;
  69 + break;
  70 +
  71 + case HTTP_REQUEST_REQUEST_LINE_DONE:
  72 + if (NULL == (line = httpRequestParserGetLine(&data))) {
  73 + cont = 0;
  74 + break;
  75 + }
  76 +
  77 + if (0 == strlen(line)) {
  78 + this->state = HTTP_REQUEST_HEADERS_DONE;
  79 + break;
  80 + }
  81 +
  82 + httpRequestParserGetHeader(request, line);
  83 + break;
  84 +
  85 + case HTTP_REQUEST_HEADERS_DONE:
  86 + httpHeaderSort(request->header, request->nheader);
  87 +
  88 + {
  89 + char * nbody;
  90 +
  91 + if (0 == request->nbody) {
  92 + nbody = httpHeaderGet(
  93 + request->header,
  94 + request->nheader,
  95 + "Content-Length");
  96 +
  97 + if (NULL == nbody) {
  98 + this->state = HTTP_REQUEST_DONE;
  99 + break;
  100 + }
  101 + else {
  102 + request->nbody = atoi(nbody);
  103 + }
  104 + }
  105 +
  106 + if (REMAINS(this, data) >= request->nbody) {
  107 + request->body = calloc(1, request->nbody + 1);
  108 + memcpy(request->body, data, request->nbody);
  109 + data += request->nbody;
  110 + this->state = HTTP_REQUEST_DONE;
  111 + }
  112 + }
  113 +
  114 + break;
  115 +
  116 + case HTTP_REQUEST_DONE:
  117 + /**
  118 + * enqueue current request
  119 + */
  120 + this->request_queue->requests[(this->request_queue->nrequests)++] =
  121 + request;
  122 +
  123 + /**
  124 + * remove processed stuff from input buffer.
  125 + */
  126 + memmove(this->buffer, data, REMAINS(this, data));
  127 +
  128 + this->buffer_used -= data - this->buffer;
  129 +
  130 + /**
  131 + * dont continue loop if input buffer is empty
  132 + */
  133 + if (0 == this->buffer_used) {
  134 + cont = 0;
  135 + }
  136 +
  137 + /**
  138 + * prepare for next request
  139 + */
  140 + this->state = HTTP_REQUEST_GARBAGE;
  141 +
  142 + break;
  143 +
  144 + default:
  145 + break;
  146 + }
  147 + }
  148 +}
  149 +
  150 +// vim: set ts=4 sw=4:
Please register or login to post a comment