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 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 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 2 #define __HTTP_REQUEST_H__
3 3
4 4 #include "class.h"
  5 +#include "http/header.h"
5 6
6 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 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 5 SOCKET = socket.c socket/accept.c socket/connect.c socket/listen.c
6 6 SERVER = server.c server/run.c server/close_conn.c
7 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 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 26 HttpRequest this = _this;
27 27 int i;
28 28
29   - _free((void **)&(this->http_version));
  29 + _free((void **)&(this->version));
30 30 _free((void **)&(this->uri));
31 31 _free((void **)&(this->method));
32 32
33 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 38 _free((void **)&(this->body));
... ...
1   -#include <stdlib.h>
2 1 #include <string.h>
3 2 #include <stdlib.h>
4   -#include <stdio.h>
5   -#include <unistd.h>
6   -#include <ctype.h>
7 3 #include <sys/types.h>
8 4
9 5 #include "class.h"
... ... @@ -13,9 +9,7 @@
13 9 #include "http/request.h"
14 10 #include "http/request_queue.h"
15 11
16   -static
17   -void
18   -httpRequestParserParse(HttpRequestParser);
  12 +void httpRequestParserParse(HttpRequestParser);
19 13
20 14 static
21 15 void
... ... @@ -103,221 +97,4 @@ INIT_IFACE(Class, ctor, dtor, _clone);
103 97 INIT_IFACE(StreamReader, get_data);
104 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 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