Commit fa58a6cc8143e592dd489716e3770775fd8b058c
1 parent
ab21de50
make http request and response childs of a common parent http message
Showing
24 changed files
with
696 additions
and
155 deletions
1 | +2012-02-12 12:43:56 +0100 Georg Hopp | |
2 | + | |
3 | + * make http request and response childs of a common parent http message (HEAD, master) | |
4 | + | |
1 | 5 | 2012-02-12 04:13:54 +0100 Georg Hopp |
2 | 6 | |
3 | - * remove now obsoleted header_sort (HEAD, master) | |
7 | + * remove now obsoleted header_sort | |
4 | 8 | |
5 | 9 | 2012-02-12 04:05:38 +0100 Georg Hopp |
6 | 10 | ... | ... |
... | ... | @@ -42,28 +42,44 @@ |
42 | 42 | * @TODO: actually i use gcc feature ## for variadoc... think about |
43 | 43 | * a way to make this standard. |
44 | 44 | */ |
45 | -#define _CALL(object,_iface,method,...) \ | |
46 | - class_ptr class = class_getClass((object)); \ | |
47 | - struct i_##_iface * iface; \ | |
48 | - if (class->init) class->init(); \ | |
49 | - iface = (struct i_##_iface *)class_getInterface(&class, &i_##_iface); \ | |
50 | - while ((NULL == iface || NULL == iface->method) && HAS_PARENT(class)) { \ | |
51 | - class = class->parent; \ | |
52 | - if (class->init) class->init(); \ | |
53 | - iface = (struct i_##_iface *)class_getInterface(&class, &i_##_iface); \ | |
54 | - }; \ | |
55 | - assert(NULL != iface->method); | |
45 | +#define _CALL(object,_iface,method,...) \ | |
46 | + do { \ | |
47 | + class_ptr class = class_getClass((object)); \ | |
48 | + if (class->init) class->init(); \ | |
49 | + iface = (struct i_##_iface *)class_getInterface(&class, &i_##_iface); \ | |
50 | + while ((NULL == iface || NULL == iface->method) && HAS_PARENT(class)) { \ | |
51 | + class = class->parent; \ | |
52 | + if (class->init) class->init(); \ | |
53 | + iface = (struct i_##_iface *)class_getInterface(&class, &i_##_iface); \ | |
54 | + }; \ | |
55 | + assert(NULL != iface->method); \ | |
56 | + } while(0) | |
56 | 57 | |
57 | -#define CALL(object,_iface,method,...) \ | |
58 | - do { \ | |
58 | +#define CALL(object,_iface,method,...) \ | |
59 | + do { \ | |
60 | + struct i_##_iface * iface; \ | |
59 | 61 | _CALL(object, _iface, method, ##__VA_ARGS__); \ |
60 | - iface->method(object, ##__VA_ARGS__); \ | |
62 | + iface->method(object, ##__VA_ARGS__); \ | |
61 | 63 | } while(0) |
62 | 64 | |
63 | -#define RETCALL(object,_iface,method,ret,...) \ | |
64 | - do { \ | |
65 | +#define RETCALL(object,_iface,method,ret,...) \ | |
66 | + do { \ | |
67 | + struct i_##_iface * iface; \ | |
65 | 68 | _CALL(object, _iface, method, ##__VA_ARGS__); \ |
66 | - ret = iface->method(object, ##__VA_ARGS__); \ | |
69 | + ret = iface->method(object, ##__VA_ARGS__); \ | |
70 | + } while(0) | |
71 | + | |
72 | +#define PARENTCALL(object,_iface,method,...) \ | |
73 | + do { \ | |
74 | + struct i_##_iface * iface; \ | |
75 | + class_ptr class = class_getClass((object)); \ | |
76 | + if (class->init) class->init(); \ | |
77 | + assert(HAS_PARENT(class)); \ | |
78 | + class = class->parent; \ | |
79 | + if (class->init) class->init(); \ | |
80 | + iface = (struct i_##_iface *)class_getInterface(&class, &i_##_iface); \ | |
81 | + assert(NULL != iface->method); \ | |
82 | + iface->method(object, ##__VA_ARGS__); \ | |
67 | 83 | } while(0) |
68 | 84 | |
69 | 85 | ... | ... |
include/http/message.h
0 → 100644
1 | +#ifndef __HTTP_MESSAGE__ | |
2 | +#define __HTTP_MESSAGE__ | |
3 | + | |
4 | +#include "class.h" | |
5 | +#include "http/header.h" | |
6 | + | |
7 | +typedef enum e_HttpMessageType { | |
8 | + HTTP_MESSAGE_BUFFERED=0, | |
9 | + HTTP_MESSAGE_PIPED | |
10 | +} HttpMessageType; | |
11 | + | |
12 | + | |
13 | +CLASS(HttpMessage) { | |
14 | + char * version; | |
15 | + | |
16 | + HttpHeader header; | |
17 | + | |
18 | + HttpMessageType type; | |
19 | + union { | |
20 | + char * buffer; | |
21 | + int handle; | |
22 | + } body; | |
23 | + int nbody; | |
24 | +}; | |
25 | + | |
26 | +#endif // __HTTP_MESSAGE__ | |
27 | + | |
28 | +// vim: set ts=4 sw=4: | ... | ... |
... | ... | @@ -2,17 +2,13 @@ |
2 | 2 | #define __HTTP_REQUEST_H__ |
3 | 3 | |
4 | 4 | #include "class.h" |
5 | -#include "http/header.h" | |
5 | +#include "http/message.h" | |
6 | 6 | |
7 | 7 | CLASS(HttpRequest) { |
8 | + EXTENDS(HttpMessage); | |
9 | + | |
8 | 10 | char * method; |
9 | 11 | char * uri; |
10 | - char * version; | |
11 | - | |
12 | - HttpHeader header; | |
13 | - | |
14 | - char * body; | |
15 | - int nbody; | |
16 | 12 | }; |
17 | 13 | |
18 | 14 | char httpRequestHasKeepAlive(HttpRequest); | ... | ... |
... | ... | @@ -7,6 +7,9 @@ |
7 | 7 | |
8 | 8 | #define HTTP_REQUEST_PARSER_READ_CHUNK 1024 |
9 | 9 | |
10 | +#define REMAINS(pars) \ | |
11 | + ((pars)->buffer_used - ((pars)->cur_data - (pars)->buffer)) | |
12 | + | |
10 | 13 | |
11 | 14 | typedef enum e_HttpRequestState { |
12 | 15 | HTTP_REQUEST_GARBAGE=0, |
... | ... | @@ -32,6 +35,8 @@ CLASS(HttpRequestParser) { |
32 | 35 | |
33 | 36 | size_t httpRequestParserRead(HttpRequestParser, int); |
34 | 37 | void httpRequestParserParse(HttpRequestParser); |
38 | +void httpRequestParserGetBody(HttpRequestParser); | |
39 | + | |
35 | 40 | void httpRequestParserGetRequestLine(HttpRequest, char *); |
36 | 41 | void httpRequestParserGetHeader(HttpRequest, char *); |
37 | 42 | ... | ... |
... | ... | @@ -4,18 +4,14 @@ |
4 | 4 | #include <sys/types.h> |
5 | 5 | |
6 | 6 | #include "class.h" |
7 | -#include "http/header.h" | |
7 | +#include "http/message.h" | |
8 | 8 | |
9 | 9 | |
10 | 10 | CLASS(HttpResponse) { |
11 | - char * version; | |
11 | + EXTENDS(HttpMessage); | |
12 | + | |
12 | 13 | unsigned int status; |
13 | 14 | char * reason; |
14 | - | |
15 | - HttpHeader header; | |
16 | - | |
17 | - char * body; | |
18 | - int nbody; | |
19 | 15 | }; |
20 | 16 | |
21 | 17 | HttpResponse httpResponse404(); | ... | ... |
include/http/worker.h
0 → 100644
... | ... | @@ -6,6 +6,7 @@ CLASS = class.c interface.c |
6 | 6 | SOCKET = socket.c socket/accept.c socket/connect.c socket/listen.c |
7 | 7 | SERVER = server.c server/run.c server/close_conn.c |
8 | 8 | LOGGER = logger.c logger/stderr.c logger/syslog.c |
9 | +MSG = http/message.c | |
9 | 10 | REQ = http/request.c http/request/queue.c http/request/has_keep_alive.c |
10 | 11 | RESP = http/response.c http/response/404.c http/response/size_get.c \ |
11 | 12 | http/response/to_string.c |
... | ... | @@ -13,7 +14,7 @@ HEADER = http/header.c http/header/get.c http/header/add.c \ |
13 | 14 | http/header/size_get.c http/header/to_string.c |
14 | 15 | PARSER = http/request/parser.c http/request/parser/get_header.c \ |
15 | 16 | http/request/parser/parse.c http/request/parser/get_request_line.c \ |
16 | - http/request/parser/read.c | |
17 | + http/request/parser/read.c http/request/parser/get_body.c | |
17 | 18 | |
18 | 19 | |
19 | 20 | AM_CFLAGS = -Wall -I ../include/ |
... | ... | @@ -21,6 +22,6 @@ AM_CFLAGS = -Wall -I ../include/ |
21 | 22 | bin_PROGRAMS = testserver |
22 | 23 | |
23 | 24 | testserver_SOURCES = testserver.c \ |
24 | - $(IFACE) $(CLASS) $(SOCKET) $(SERVER) $(LOGGER) $(REQ) \ | |
25 | + $(IFACE) $(CLASS) $(SOCKET) $(SERVER) $(LOGGER) $(MSG) $(REQ) \ | |
25 | 26 | $(RESP) $(HEADER) $(PARSER) signalHandling.c daemonize.c |
26 | 27 | testserver_CFLAGS = -Wall -I ../include/ | ... | ... |
src/http/header/add.c
0 → 100644
1 | +#include <search.h> | |
2 | +#include <stdlib.h> | |
3 | +#include <ctype.h> | |
4 | +#include <stdio.h> | |
5 | + | |
6 | +#include "class.h" | |
7 | +#include "interface/class.h" | |
8 | +#include "http/header.h" | |
9 | + | |
10 | +static | |
11 | +inline | |
12 | +unsigned long | |
13 | +sdbm(const unsigned char * str) | |
14 | +{ | |
15 | + unsigned long hash = 0; | |
16 | + int c; | |
17 | + | |
18 | + while ((c = tolower(*str++))) | |
19 | + hash = c + (hash << 6) + (hash << 16) - hash; | |
20 | + | |
21 | + return hash; | |
22 | +} | |
23 | + | |
24 | +static | |
25 | +inline | |
26 | +int | |
27 | +comp(const void * _a, const void * _b) | |
28 | +{ | |
29 | + HttpHeader a = (HttpHeader)_a; | |
30 | + HttpHeader b = (HttpHeader)_b; | |
31 | + return (a->hash < b->hash)? -1 : (a->hash > b->hash)? 1 : 0; | |
32 | +} | |
33 | + | |
34 | +void | |
35 | +httpHeaderAdd(const HttpHeader * root, HttpHeader header) | |
36 | +{ | |
37 | + HttpHeader * found = tsearch(header, (void **)root, comp); | |
38 | + | |
39 | + if (*found != header) { | |
40 | + puts("uhh, duplicate header set. " | |
41 | + "This is not implemented right now. " | |
42 | + "Keep the first one found."); | |
43 | + delete(&header); | |
44 | + } | |
45 | +} | |
46 | + | |
47 | +// vim: set ts=4 sw=4: | ... | ... |
src/http/message.c
0 → 100644
1 | +#ifndef _GNU_SOURCE | |
2 | +#define _GNU_SOURCE | |
3 | +#endif | |
4 | + | |
5 | +#include <search.h> | |
6 | +#include <stdlib.h> | |
7 | +#include <string.h> | |
8 | +#include <stdarg.h> | |
9 | +#include <unistd.h> | |
10 | + | |
11 | +#include "class.h" | |
12 | +#include "interface/class.h" | |
13 | + | |
14 | +#include "http/message.h" | |
15 | +#include "message/helper.c" | |
16 | + | |
17 | + | |
18 | +static | |
19 | +void | |
20 | +ctor(void * _this, va_list * params) | |
21 | +{ | |
22 | + HttpMessage this = _this; | |
23 | + char * version = va_arg(* params, char *); | |
24 | + | |
25 | + this->version = calloc(1, strlen(version)+1); | |
26 | + strcpy(this->version, version); | |
27 | +} | |
28 | + | |
29 | +static | |
30 | +void | |
31 | +dtor(void * _this) | |
32 | +{ | |
33 | + HttpMessage this = _this; | |
34 | + | |
35 | + _free((void **)&(this->version)); | |
36 | + | |
37 | + /** | |
38 | + * this is a GNU extension...anyway on most non | |
39 | + * GNUish systems i would not use tsearch anyway | |
40 | + * as the trees will be unbalanced. | |
41 | + */ | |
42 | + tdestroy(this->header, tDelete); | |
43 | + | |
44 | + switch (this->type) { | |
45 | + case HTTP_MESSAGE_BUFFERED: | |
46 | + _free((void **)&((this->body).buffer)); | |
47 | + break; | |
48 | + | |
49 | + case HTTP_MESSAGE_PIPED: | |
50 | + close((this->body).handle); | |
51 | + break; | |
52 | + | |
53 | + default: | |
54 | + break; | |
55 | + } | |
56 | +} | |
57 | + | |
58 | +INIT_IFACE(Class, ctor, dtor, NULL); | |
59 | +CREATE_CLASS(HttpMessage, NULL, IFACE(Class)); | |
60 | + | |
61 | +// vim: set ts=4 sw=4: | ... | ... |
src/http/message/helper.c
0 → 100644
1 | +#ifndef __HTTP_MESSAGE_HELPER_C__ | |
2 | +#define __HTTP_MESSAGE_HELPER_C__ | |
3 | + | |
4 | +#include <stdlib.h> | |
5 | + | |
6 | +#include "class.h" | |
7 | +#include "interface/class.h" | |
8 | + | |
9 | + | |
10 | +static | |
11 | +inline | |
12 | +void | |
13 | +_free(void ** data) | |
14 | +{ | |
15 | + if (NULL != *data) { | |
16 | + free(*data); | |
17 | + } | |
18 | +} | |
19 | + | |
20 | +static | |
21 | +inline | |
22 | +void | |
23 | +tDelete(void * node) | |
24 | +{ | |
25 | + delete(&node); | |
26 | +} | |
27 | + | |
28 | +#endif // __HTTP_MESSAGE_HELPER_C__ | |
29 | + | |
30 | +// vim: set ts=4 sw=4: | ... | ... |
1 | -#ifndef _GNU_SOURCE | |
2 | -#define _GNU_SOURCE | |
3 | -#endif | |
4 | - | |
5 | 1 | #include <stdlib.h> |
6 | 2 | #include <stdarg.h> |
7 | -#include <search.h> | |
8 | 3 | |
9 | 4 | #include "class.h" |
10 | 5 | #include "interface/class.h" |
11 | 6 | |
12 | 7 | #include "http/request.h" |
8 | +#include "message/helper.c" | |
13 | 9 | |
14 | 10 | |
15 | 11 | static |
16 | -inline | |
17 | -void | |
18 | -_free(void ** data) | |
19 | -{ | |
20 | - if (NULL != *data) { | |
21 | - free(*data); | |
22 | - } | |
23 | -} | |
24 | - | |
25 | -static | |
26 | -inline | |
27 | -void | |
28 | -tDelete(void * node) | |
29 | -{ | |
30 | - delete(&node); | |
31 | -} | |
32 | - | |
33 | -static | |
34 | 12 | void |
35 | 13 | ctor(void * _this, va_list * params) {} |
36 | 14 | |
... | ... | @@ -40,21 +18,13 @@ dtor(void * _this) |
40 | 18 | { |
41 | 19 | HttpRequest this = _this; |
42 | 20 | |
43 | - _free((void **)&(this->version)); | |
44 | 21 | _free((void **)&(this->uri)); |
45 | 22 | _free((void **)&(this->method)); |
46 | 23 | |
47 | - /** | |
48 | - * this is a GNU extension...anyway on most non | |
49 | - * GNUish systems i would not use tsearch anyway | |
50 | - * as the trees will be unbalanced. | |
51 | - */ | |
52 | - tdestroy(this->header, tDelete); | |
53 | - | |
54 | - _free((void **)&(this->body)); | |
24 | + PARENTCALL(_this, Class, dtor); | |
55 | 25 | } |
56 | 26 | |
57 | 27 | INIT_IFACE(Class, ctor, dtor, NULL); |
58 | -CREATE_CLASS(HttpRequest, NULL, IFACE(Class)); | |
28 | +CREATE_CLASS(HttpRequest, HttpMessage, IFACE(Class)); | |
59 | 29 | |
60 | 30 | // vim: set ts=4 sw=4: | ... | ... |
1 | 1 | #include <string.h> |
2 | 2 | #include <ctype.h> |
3 | 3 | |
4 | +#include "http/message.h" | |
4 | 5 | #include "http/request.h" |
5 | 6 | #include "http/header.h" |
6 | 7 | |
... | ... | @@ -8,10 +9,11 @@ |
8 | 9 | char |
9 | 10 | httpRequestHasKeepAlive(HttpRequest request) |
10 | 11 | { |
11 | - char * header; | |
12 | - char * header_ptr; | |
12 | + HttpMessage message = (HttpMessage)request; | |
13 | + char * header; | |
14 | + char * header_ptr; | |
13 | 15 | |
14 | - header = httpHeaderGet(&(request->header), "connection"); | |
16 | + header = httpHeaderGet(&(message->header), "connection"); | |
15 | 17 | |
16 | 18 | if (NULL == header) { |
17 | 19 | return 0; | ... | ... |
src/http/request/parser/get_body.c
0 → 100644
1 | +#include <stdlib.h> | |
2 | + | |
3 | +#include "http/header.h" | |
4 | +#include "http/message.h" | |
5 | +#include "http/request/parser.h" | |
6 | + | |
7 | +void | |
8 | +httpRequestParserGetBody(HttpRequestParser this) | |
9 | +{ | |
10 | + HttpMessage message = (HttpMessage)(this->cur_request); | |
11 | + char * nbody; | |
12 | + | |
13 | + if (0 == message->nbody) { | |
14 | + nbody = httpHeaderGet( | |
15 | + &(message->header), | |
16 | + "Content-Length"); | |
17 | + | |
18 | + if (NULL == nbody) { | |
19 | + this->state = HTTP_REQUEST_DONE; | |
20 | + return; | |
21 | + } | |
22 | + else { | |
23 | + message->type = HTTP_MESSAGE_BUFFERED; | |
24 | + message->nbody = atoi(nbody); | |
25 | + } | |
26 | + } | |
27 | + | |
28 | + if (REMAINS(this) >= message->nbody) { | |
29 | + (message->body).buffer = calloc(1, message->nbody + 1); | |
30 | + memcpy((message->body).buffer, | |
31 | + this->cur_data, | |
32 | + message->nbody); | |
33 | + this->cur_data += message->nbody; | |
34 | + this->state = HTTP_REQUEST_DONE; | |
35 | + } | |
36 | +} | |
37 | + | |
38 | +// vim: set ts=4 sw=4: | ... | ... |
... | ... | @@ -5,10 +5,10 @@ |
5 | 5 | #include "class.h" |
6 | 6 | #include "interface/class.h" |
7 | 7 | #include "http/header.h" |
8 | -#include "http/request.h" | |
8 | +#include "http/message.h" | |
9 | 9 | |
10 | 10 | void |
11 | -httpRequestParserGetHeader(HttpRequest request, char * line) | |
11 | +httpRequestParserGetHeader(HttpMessage request, char * line) | |
12 | 12 | { |
13 | 13 | char * name = line; |
14 | 14 | char * value = strchr(line, ':'); | ... | ... |
... | ... | @@ -7,6 +7,7 @@ |
7 | 7 | void |
8 | 8 | httpRequestParserGetRequestLine(HttpRequest request, char * line) |
9 | 9 | { |
10 | + HttpMessage message = (HttpMessage)request; | |
10 | 11 | char * method, * uri, * version; |
11 | 12 | |
12 | 13 | method = line; |
... | ... | @@ -23,8 +24,8 @@ httpRequestParserGetRequestLine(HttpRequest request, char * line) |
23 | 24 | strcpy(request->method, method); |
24 | 25 | request->uri = malloc(strlen(uri) + 1); |
25 | 26 | strcpy(request->uri, uri); |
26 | - request->version = malloc(strlen(version) + 1); | |
27 | - strcpy(request->version, method); | |
27 | + message->version = malloc(strlen(version) + 1); | |
28 | + strcpy(message->version, method); | |
28 | 29 | } |
29 | 30 | |
30 | 31 | // vim: set ts=4 sw=4: | ... | ... |
... | ... | @@ -7,10 +7,6 @@ |
7 | 7 | #include "interface/class.h" |
8 | 8 | |
9 | 9 | |
10 | -#define REMAINS(pars) \ | |
11 | - ((pars)->buffer_used - ((pars)->cur_data - (pars)->buffer)) | |
12 | - | |
13 | - | |
14 | 10 | static |
15 | 11 | inline |
16 | 12 | char * |
... | ... | @@ -79,33 +75,7 @@ httpRequestParserParse(HttpRequestParser this) |
79 | 75 | break; |
80 | 76 | |
81 | 77 | case HTTP_REQUEST_HEADERS_DONE: |
82 | - { | |
83 | - char * nbody; | |
84 | - | |
85 | - if (0 == this->cur_request->nbody) { | |
86 | - nbody = httpHeaderGet( | |
87 | - &(this->cur_request->header), | |
88 | - "Content-Length"); | |
89 | - | |
90 | - if (NULL == nbody) { | |
91 | - this->state = HTTP_REQUEST_DONE; | |
92 | - break; | |
93 | - } | |
94 | - else { | |
95 | - this->cur_request->nbody = atoi(nbody); | |
96 | - } | |
97 | - } | |
98 | - | |
99 | - if (REMAINS(this) >= this->cur_request->nbody) { | |
100 | - this->cur_request->body = calloc(1, this->cur_request->nbody + 1); | |
101 | - memcpy(this->cur_request->body, | |
102 | - this->cur_data, | |
103 | - this->cur_request->nbody); | |
104 | - this->cur_data += this->cur_request->nbody; | |
105 | - this->state = HTTP_REQUEST_DONE; | |
106 | - } | |
107 | - } | |
108 | - | |
78 | + httpRequestParserGetBody(this); | |
109 | 79 | break; |
110 | 80 | |
111 | 81 | case HTTP_REQUEST_DONE: | ... | ... |
src/http/request/parser/read.c
0 → 100644
1 | +#include <stdlib.h> | |
2 | +#include <unistd.h> | |
3 | + | |
4 | +#include "http/request/parser.h" | |
5 | + | |
6 | + | |
7 | +size_t | |
8 | +httpRequestParserRead(HttpRequestParser this, int fd) | |
9 | +{ | |
10 | + size_t remaining, chunks; | |
11 | + char buffer[1024]; | |
12 | + | |
13 | + ssize_t size = read(fd, buffer, 1024); | |
14 | + | |
15 | + if (0 < size) { | |
16 | + remaining = this->buffer_used % HTTP_REQUEST_PARSER_READ_CHUNK; | |
17 | + chunks = this->buffer_used / HTTP_REQUEST_PARSER_READ_CHUNK; | |
18 | + | |
19 | + /** | |
20 | + * because a division always rounds down | |
21 | + * chunks holds exactly the currently allocated chunks if | |
22 | + * remaining equals 0 but there is no space left. | |
23 | + * Else chunks holds the actually allocated amount of chunks | |
24 | + * minus 1. | |
25 | + * For this reason chunks always has to be increased by 1. | |
26 | + */ | |
27 | + chunks++; | |
28 | + | |
29 | + if (size >= remaining) { | |
30 | + this->buffer = | |
31 | + realloc(this->buffer, chunks * HTTP_REQUEST_PARSER_READ_CHUNK); | |
32 | + } | |
33 | + | |
34 | + memcpy(this->buffer + this->buffer_used, buffer, size); | |
35 | + this->buffer_used += size; | |
36 | + this->buffer[this->buffer_used] = 0; | |
37 | + | |
38 | + httpRequestParserParse(this); | |
39 | + } | |
40 | + | |
41 | + return size; | |
42 | +} | |
43 | + | |
44 | +// vim: set ts=4 sw=4: | ... | ... |
1 | -#ifndef _GNU_SOURCE | |
2 | -#define _GNU_SOURCE | |
3 | -#endif | |
4 | - | |
5 | -#include <search.h> | |
6 | 1 | #include <stdlib.h> |
7 | 2 | #include <stdarg.h> |
8 | 3 | |
... | ... | @@ -10,60 +5,38 @@ |
10 | 5 | #include "interface/class.h" |
11 | 6 | |
12 | 7 | #include "http/response.h" |
8 | +#include "message/helper.c" | |
13 | 9 | |
14 | 10 | |
15 | 11 | static |
16 | 12 | void |
17 | -_free(void ** data) | |
18 | -{ | |
19 | - if (NULL != *data) { | |
20 | - free(*data); | |
21 | - } | |
22 | -} | |
23 | - | |
24 | -static | |
25 | -void | |
26 | 13 | ctor(void * _this, va_list * params) |
27 | 14 | { |
28 | - char * version; | |
15 | + HttpResponse this = _this; | |
16 | + char * status; | |
29 | 17 | char * reason; |
30 | 18 | |
31 | - HttpResponse this = _this; | |
19 | + PARENTCALL(_this, Class, ctor, params); | |
32 | 20 | |
33 | - version = va_arg(* params, char *); | |
34 | 21 | this->status = va_arg(* params, unsigned int); |
35 | 22 | reason = va_arg(* params, char *); |
36 | 23 | |
37 | - this->version = calloc(1, strlen(version)+1); | |
38 | - strcpy(this->version, version); | |
39 | - | |
40 | 24 | this->reason = calloc(1, strlen(reason)+1); |
41 | 25 | strcpy(this->reason, reason); |
42 | 26 | } |
43 | 27 | |
44 | 28 | static |
45 | -inline | |
46 | -void | |
47 | -tDelete(void * node) | |
48 | -{ | |
49 | - delete(&node); | |
50 | -} | |
51 | - | |
52 | -static | |
53 | 29 | void |
54 | 30 | dtor(void * _this) |
55 | 31 | { |
56 | 32 | HttpResponse this = _this; |
57 | 33 | |
58 | - _free((void **)&(this->version)); | |
59 | 34 | _free((void **)&(this->reason)); |
60 | 35 | |
61 | - tdestroy(this->header, tDelete); | |
62 | - | |
63 | - _free((void **)&(this->body)); | |
36 | + PARENTCALL(_this, Class, dtor); | |
64 | 37 | } |
65 | 38 | |
66 | 39 | INIT_IFACE(Class, ctor, dtor, NULL); |
67 | -CREATE_CLASS(HttpResponse, NULL, IFACE(Class)); | |
40 | +CREATE_CLASS(HttpResponse, HttpMessage, IFACE(Class)); | |
68 | 41 | |
69 | 42 | // vim: set ts=4 sw=4: | ... | ... |
... | ... | @@ -7,6 +7,7 @@ |
7 | 7 | #include "interface/class.h" |
8 | 8 | |
9 | 9 | #include "http/response.h" |
10 | +#include "http/message.h" | |
10 | 11 | #include "http/header.h" |
11 | 12 | |
12 | 13 | |
... | ... | @@ -26,26 +27,29 @@ httpResponse404() |
26 | 27 | struct tm * tmp; |
27 | 28 | char buffer[200]; |
28 | 29 | HttpResponse response; |
30 | + HttpMessage message; | |
29 | 31 | |
30 | 32 | response = new(HttpResponse, "HTTP/1.1", 404, "Not Found"); |
33 | + message = (HttpMessage)response; | |
31 | 34 | |
32 | - httpHeaderAdd(&(response->header), | |
35 | + httpHeaderAdd(&(message->header), | |
33 | 36 | new(HttpHeader, "Content-Type", "text/html")); |
34 | - httpHeaderAdd(&(response->header), | |
37 | + httpHeaderAdd(&(message->header), | |
35 | 38 | new(HttpHeader, "Server", "testserver")); |
36 | 39 | |
37 | - response->nbody = sizeof(RESP_DATA) - 1; | |
38 | - response->body = calloc(1, sizeof(RESP_DATA)); | |
39 | - strcpy(response->body, RESP_DATA); | |
40 | + message->type = HTTP_MESSAGE_BUFFERED; | |
41 | + message->nbody = sizeof(RESP_DATA) - 1; | |
42 | + (message->body).buffer = calloc(1, sizeof(RESP_DATA)); | |
43 | + strcpy((message->body).buffer, RESP_DATA); | |
40 | 44 | |
41 | - sprintf(buffer, "%d", response->nbody); | |
42 | - httpHeaderAdd(&(response->header), | |
45 | + sprintf(buffer, "%d", message->nbody); | |
46 | + httpHeaderAdd(&(message->header), | |
43 | 47 | new(HttpHeader, "Content-Length", buffer)); |
44 | 48 | |
45 | 49 | t = time(NULL); |
46 | 50 | tmp = localtime(&t); |
47 | 51 | strftime(buffer, sizeof(buffer), "%a, %d %b %Y %T %Z", tmp); |
48 | - httpHeaderAdd(&(response->header), | |
52 | + httpHeaderAdd(&(message->header), | |
49 | 53 | new(HttpHeader, "Date", buffer)); |
50 | 54 | |
51 | 55 | return response; | ... | ... |
... | ... | @@ -2,6 +2,7 @@ |
2 | 2 | #include <string.h> |
3 | 3 | #include <sys/types.h> |
4 | 4 | |
5 | +#include "http/message.h" | |
5 | 6 | #include "http/response.h" |
6 | 7 | #include "http/header.h" |
7 | 8 | |
... | ... | @@ -20,16 +21,21 @@ addHeaderSize(const void * node, const VISIT which, const int depth) |
20 | 21 | size_t |
21 | 22 | httpResponseSizeGet(HttpResponse response) |
22 | 23 | { |
24 | + HttpMessage message = (HttpMessage)response; | |
25 | + | |
23 | 26 | size = 0; |
24 | 27 | |
25 | - size += strlen(response->version) + 1; | |
28 | + size += strlen(message->version) + 1; | |
26 | 29 | size += 4; // for status |
27 | 30 | size += strlen(response->reason) + 2; |
28 | 31 | |
29 | - twalk(response->header, addHeaderSize); | |
32 | + twalk(message->header, addHeaderSize); | |
30 | 33 | |
31 | 34 | size += 2; |
32 | - size += response->nbody; | |
35 | + | |
36 | + if (HTTP_MESSAGE_BUFFERED == message->type) { | |
37 | + size += message->nbody; | |
38 | + } | |
33 | 39 | |
34 | 40 | return size; |
35 | 41 | } | ... | ... |
... | ... | @@ -20,13 +20,14 @@ addHeaderString(const void * node, const VISIT which, const int depth) |
20 | 20 | char * |
21 | 21 | httpResponseToString(HttpResponse response, char * _string) |
22 | 22 | { |
23 | - char status[4]; | |
23 | + HttpMessage message = (HttpMessage)response; | |
24 | + char status[4]; | |
24 | 25 | |
25 | 26 | string = _string; |
26 | 27 | |
27 | 28 | snprintf(status, 4, "%d", response->status); |
28 | 29 | |
29 | - strcpy(string, response->version); | |
30 | + strcpy(string, message->version); | |
30 | 31 | string += strlen(string); |
31 | 32 | |
32 | 33 | *string++ = ' '; |
... | ... | @@ -42,12 +43,14 @@ httpResponseToString(HttpResponse response, char * _string) |
42 | 43 | *string++ = '\r'; |
43 | 44 | *string++ = '\n'; |
44 | 45 | |
45 | - twalk(response->header, addHeaderString); | |
46 | + twalk(message->header, addHeaderString); | |
46 | 47 | |
47 | 48 | *string++ = '\r'; |
48 | 49 | *string++ = '\n'; |
49 | 50 | |
50 | - memcpy(string, response->body, response->nbody); | |
51 | + if (HTTP_MESSAGE_BUFFERED == message->type) { | |
52 | + memcpy(string, (message->body).buffer, message->nbody); | |
53 | + } | |
51 | 54 | |
52 | 55 | return string; |
53 | 56 | } | ... | ... |
... | ... | @@ -117,13 +117,13 @@ serverRun(Server this) |
117 | 117 | if (httpRequestHasKeepAlive(queue->requests[j])) { |
118 | 118 | (this->conns)[fd].keep_alive = 1; |
119 | 119 | httpHeaderAdd( |
120 | - &(response->header), | |
120 | + &(((HttpMessage)response)->header), | |
121 | 121 | new(HttpHeader, "Connection", "Keep-Alive")); |
122 | 122 | } |
123 | 123 | else { |
124 | 124 | (this->conns)[fd].keep_alive = 0; |
125 | 125 | httpHeaderAdd( |
126 | - &(response->header), | |
126 | + &(((HttpMessage)response)->header), | |
127 | 127 | new(HttpHeader, "Connection", "Close")); |
128 | 128 | } |
129 | 129 | ... | ... |
tests/tst-tsearch.c
0 → 100644
1 | +/* Test program for tsearch et al. | |
2 | + Copyright (C) 1997, 2000, 2001 Free Software Foundation, Inc. | |
3 | + This file is part of the GNU C Library. | |
4 | + | |
5 | + The GNU C Library is free software; you can redistribute it and/or | |
6 | + modify it under the terms of the GNU Lesser General Public | |
7 | + License as published by the Free Software Foundation; either | |
8 | + version 2.1 of the License, or (at your option) any later version. | |
9 | + | |
10 | + The GNU C Library is distributed in the hope that it will be useful, | |
11 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | + Lesser General Public License for more details. | |
14 | + | |
15 | + You should have received a copy of the GNU Lesser General Public | |
16 | + License along with the GNU C Library; if not, write to the Free | |
17 | + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
18 | + 02111-1307 USA. */ | |
19 | + | |
20 | +#ifndef _GNU_SOURCE | |
21 | +# define _GNU_SOURCE 1 | |
22 | +#endif | |
23 | + | |
24 | +#include <stdio.h> | |
25 | +#include <stdlib.h> | |
26 | +#include <string.h> | |
27 | +#include <search.h> | |
28 | + | |
29 | +#define SEED 0 | |
30 | +#define BALANCED 1 | |
31 | +#define PASSES 100 | |
32 | + | |
33 | +#if BALANCED | |
34 | +#include <math.h> | |
35 | +#define SIZE 1000 | |
36 | +#else | |
37 | +#define SIZE 100 | |
38 | +#endif | |
39 | + | |
40 | +enum order | |
41 | +{ | |
42 | + ascending, | |
43 | + descending, | |
44 | + randomorder | |
45 | +}; | |
46 | + | |
47 | +enum action | |
48 | +{ | |
49 | + build, | |
50 | + build_and_del, | |
51 | + delete, | |
52 | + find | |
53 | +}; | |
54 | + | |
55 | +/* Set to 1 if a test is flunked. */ | |
56 | +static int error = 0; | |
57 | + | |
58 | +/* The keys we add to the tree. */ | |
59 | +static int x[SIZE]; | |
60 | + | |
61 | +/* Pointers into the key array, possibly permutated, to define an order | |
62 | + for insertion/removal. */ | |
63 | +static int y[SIZE]; | |
64 | + | |
65 | +/* Flags set for each element visited during a tree walk. */ | |
66 | +static int z[SIZE]; | |
67 | + | |
68 | +/* Depths for all the elements, to check that the depth is constant for | |
69 | + all three visits. */ | |
70 | +static int depths[SIZE]; | |
71 | + | |
72 | +/* Maximum depth during a tree walk. */ | |
73 | +static int max_depth; | |
74 | + | |
75 | +/* Compare two keys. */ | |
76 | +static int | |
77 | +cmp_fn (const void *a, const void *b) | |
78 | +{ | |
79 | + return *(const int *) a - *(const int *) b; | |
80 | +} | |
81 | + | |
82 | +/* Permute an array of integers. */ | |
83 | +static void | |
84 | +memfry (int *string) | |
85 | +{ | |
86 | + int i; | |
87 | + | |
88 | + for (i = 0; i < SIZE; ++i) | |
89 | + { | |
90 | + int32_t j; | |
91 | + int c; | |
92 | + | |
93 | + j = random () % SIZE; | |
94 | + | |
95 | + c = string[i]; | |
96 | + string[i] = string[j]; | |
97 | + string[j] = c; | |
98 | + } | |
99 | +} | |
100 | + | |
101 | +static void | |
102 | +walk_action (const void *nodep, const VISIT which, const int depth) | |
103 | +{ | |
104 | + int key = **(int **) nodep; | |
105 | + | |
106 | + if (depth > max_depth) | |
107 | + max_depth = depth; | |
108 | + if (which == leaf || which == preorder) | |
109 | + { | |
110 | + ++z[key]; | |
111 | + depths[key] = depth; | |
112 | + } | |
113 | + else | |
114 | + { | |
115 | + if (depths[key] != depth) | |
116 | + { | |
117 | + fputs ("Depth for one element is not constant during tree walk.\n", | |
118 | + stdout); | |
119 | + } | |
120 | + } | |
121 | +} | |
122 | + | |
123 | +static void | |
124 | +walk_tree (void *root, int expected_count) | |
125 | +{ | |
126 | + int i; | |
127 | + | |
128 | + memset (z, 0, sizeof z); | |
129 | + max_depth = 0; | |
130 | + | |
131 | + twalk (root, walk_action); | |
132 | + for (i = 0; i < expected_count; ++i) | |
133 | + if (z[i] != 1) | |
134 | + { | |
135 | + fputs ("Node was not visited.\n", stdout); | |
136 | + error = 1; | |
137 | + } | |
138 | + | |
139 | +#if BALANCED | |
140 | + if (max_depth > log (expected_count) * 2 + 2) | |
141 | +#else | |
142 | + if (max_depth > expected_count) | |
143 | +#endif | |
144 | + { | |
145 | + fputs ("Depth too large during tree walk.\n", stdout); | |
146 | + error = 1; | |
147 | + } | |
148 | +} | |
149 | + | |
150 | +/* Perform an operation on a tree. */ | |
151 | +static void | |
152 | +mangle_tree (enum order how, enum action what, void **root, int lag) | |
153 | +{ | |
154 | + int i; | |
155 | + | |
156 | + if (how == randomorder) | |
157 | + { | |
158 | + for (i = 0; i < SIZE; ++i) | |
159 | + y[i] = i; | |
160 | + memfry (y); | |
161 | + } | |
162 | + | |
163 | + for (i = 0; i < SIZE + lag; ++i) | |
164 | + { | |
165 | + void *elem; | |
166 | + int j, k; | |
167 | + | |
168 | + switch (how) | |
169 | + { | |
170 | + case randomorder: | |
171 | + if (i >= lag) | |
172 | + k = y[i - lag]; | |
173 | + else | |
174 | + /* Ensure that the array index is within bounds. */ | |
175 | + k = y[(SIZE - i - 1 + lag) % SIZE]; | |
176 | + j = y[i % SIZE]; | |
177 | + break; | |
178 | + | |
179 | + case ascending: | |
180 | + k = i - lag; | |
181 | + j = i; | |
182 | + break; | |
183 | + | |
184 | + case descending: | |
185 | + k = SIZE - i - 1 + lag; | |
186 | + j = SIZE - i - 1; | |
187 | + break; | |
188 | + | |
189 | + default: | |
190 | + /* This never should happen, but gcc isn't smart enough to | |
191 | + recognize it. */ | |
192 | + abort (); | |
193 | + } | |
194 | + | |
195 | + switch (what) | |
196 | + { | |
197 | + case build_and_del: | |
198 | + case build: | |
199 | + if (i < SIZE) | |
200 | + { | |
201 | + if (tfind (x + j, (void *const *) root, cmp_fn) != NULL) | |
202 | + { | |
203 | + fputs ("Found element which is not in tree yet.\n", stdout); | |
204 | + error = 1; | |
205 | + } | |
206 | + elem = tsearch (x + j, root, cmp_fn); | |
207 | + if (elem == 0 | |
208 | + || tfind (x + j, (void *const *) root, cmp_fn) == NULL) | |
209 | + { | |
210 | + fputs ("Couldn't find element after it was added.\n", | |
211 | + stdout); | |
212 | + error = 1; | |
213 | + } | |
214 | + } | |
215 | + | |
216 | + if (what == build || i < lag) | |
217 | + break; | |
218 | + | |
219 | + j = k; | |
220 | + /* fall through */ | |
221 | + | |
222 | + case delete: | |
223 | + elem = tfind (x + j, (void *const *) root, cmp_fn); | |
224 | + if (elem == NULL || tdelete (x + j, root, cmp_fn) == NULL) | |
225 | + { | |
226 | + fputs ("Error deleting element.\n", stdout); | |
227 | + error = 1; | |
228 | + } | |
229 | + break; | |
230 | + | |
231 | + case find: | |
232 | + if (tfind (x + j, (void *const *) root, cmp_fn) == NULL) | |
233 | + { | |
234 | + fputs ("Couldn't find element after it was added.\n", stdout); | |
235 | + error = 1; | |
236 | + } | |
237 | + break; | |
238 | + | |
239 | + } | |
240 | + } | |
241 | +} | |
242 | + | |
243 | + | |
244 | +int | |
245 | +main (int argc, char **argv) | |
246 | +{ | |
247 | + int total_error = 0; | |
248 | + static char state[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; | |
249 | + void *root = NULL; | |
250 | + int i, j; | |
251 | + | |
252 | + initstate (SEED, state, 8); | |
253 | + | |
254 | + for (i = 0; i < SIZE; ++i) | |
255 | + x[i] = i; | |
256 | + | |
257 | + /* Do this loop several times to get different permutations for the | |
258 | + random case. */ | |
259 | + fputs ("Series I\n", stdout); | |
260 | + for (i = 0; i < PASSES; ++i) | |
261 | + { | |
262 | + fprintf (stdout, "Pass %d... ", i + 1); | |
263 | + fflush (stdout); | |
264 | + error = 0; | |
265 | + | |
266 | + mangle_tree (ascending, build, &root, 0); | |
267 | + mangle_tree (ascending, find, &root, 0); | |
268 | + mangle_tree (descending, find, &root, 0); | |
269 | + mangle_tree (randomorder, find, &root, 0); | |
270 | + walk_tree (root, SIZE); | |
271 | + mangle_tree (ascending, delete, &root, 0); | |
272 | + | |
273 | + mangle_tree (ascending, build, &root, 0); | |
274 | + walk_tree (root, SIZE); | |
275 | + mangle_tree (descending, delete, &root, 0); | |
276 | + | |
277 | + mangle_tree (ascending, build, &root, 0); | |
278 | + walk_tree (root, SIZE); | |
279 | + mangle_tree (randomorder, delete, &root, 0); | |
280 | + | |
281 | + mangle_tree (descending, build, &root, 0); | |
282 | + mangle_tree (ascending, find, &root, 0); | |
283 | + mangle_tree (descending, find, &root, 0); | |
284 | + mangle_tree (randomorder, find, &root, 0); | |
285 | + walk_tree (root, SIZE); | |
286 | + mangle_tree (descending, delete, &root, 0); | |
287 | + | |
288 | + mangle_tree (descending, build, &root, 0); | |
289 | + walk_tree (root, SIZE); | |
290 | + mangle_tree (descending, delete, &root, 0); | |
291 | + | |
292 | + mangle_tree (descending, build, &root, 0); | |
293 | + walk_tree (root, SIZE); | |
294 | + mangle_tree (randomorder, delete, &root, 0); | |
295 | + | |
296 | + mangle_tree (randomorder, build, &root, 0); | |
297 | + mangle_tree (ascending, find, &root, 0); | |
298 | + mangle_tree (descending, find, &root, 0); | |
299 | + mangle_tree (randomorder, find, &root, 0); | |
300 | + walk_tree (root, SIZE); | |
301 | + mangle_tree (randomorder, delete, &root, 0); | |
302 | + | |
303 | + for (j = 1; j < SIZE; j *= 2) | |
304 | + { | |
305 | + mangle_tree (randomorder, build_and_del, &root, j); | |
306 | + } | |
307 | + | |
308 | + fputs (error ? " failed!\n" : " ok.\n", stdout); | |
309 | + total_error |= error; | |
310 | + } | |
311 | + | |
312 | + fputs ("Series II\n", stdout); | |
313 | + for (i = 1; i < SIZE; i *= 2) | |
314 | + { | |
315 | + fprintf (stdout, "For size %d... ", i); | |
316 | + fflush (stdout); | |
317 | + error = 0; | |
318 | + | |
319 | + mangle_tree (ascending, build_and_del, &root, i); | |
320 | + mangle_tree (descending, build_and_del, &root, i); | |
321 | + mangle_tree (ascending, build_and_del, &root, i); | |
322 | + mangle_tree (descending, build_and_del, &root, i); | |
323 | + mangle_tree (ascending, build_and_del, &root, i); | |
324 | + mangle_tree (descending, build_and_del, &root, i); | |
325 | + mangle_tree (ascending, build_and_del, &root, i); | |
326 | + mangle_tree (descending, build_and_del, &root, i); | |
327 | + | |
328 | + fputs (error ? " failed!\n" : " ok.\n", stdout); | |
329 | + total_error |= error; | |
330 | + } | |
331 | + | |
332 | + return total_error; | |
333 | +} | ... | ... |
Please
register
or
login
to post a comment