Browse Source

change response to tree based header storage and make everything work.

master
Georg Hopp 14 years ago
parent
commit
e67667881f
  1. 8
      ChangeLog
  2. 4
      include/http/header.h
  3. 3
      include/http/request.h
  4. 6
      include/http/request/parser.h
  5. 5
      include/http/response.h
  6. 6
      include/interface.h
  7. 8
      src/Makefile.am
  8. 15
      src/http/header/get.c
  9. 2
      src/http/request/has_keep_alive.c
  10. 12
      src/http/request/header_get.c
  11. 42
      src/http/request/parser.c
  12. 46
      src/http/request/parser/get_header.c
  13. 5
      src/http/request/parser/parse.c
  14. 19
      src/http/response.c
  15. 13
      src/http/response/404.c
  16. 13
      src/http/response/header_set.c
  17. 20
      src/http/response/size_get.c
  18. 29
      src/http/response/to_string.c
  19. 14
      src/server/run.c

8
ChangeLog

@ -1,10 +1,14 @@
2012-02-12 04:05:38 +0100 Georg Hopp
* change response to tree based header storage and make everything work. (HEAD, master)
2012-02-12 00:05:13 +0100 Georg Hopp 2012-02-12 00:05:13 +0100 Georg Hopp
* changed header hashing to use btree (GNU only). @TODO: make this conditional for other systems. Removed the qsort calls on server->fds making O(2nlogn) to O(n) (HEAD, master)
* changed header hashing to use btree (GNU only). @TODO: make this conditional for other systems. Removed the qsort calls on server->fds making O(2nlogn) to O(n) (origin/master, origin/HEAD)
2012-02-11 13:52:32 +0100 Georg Hopp 2012-02-11 13:52:32 +0100 Georg Hopp
* daemonize testserver now (origin/master, origin/HEAD)
* daemonize testserver now
2012-02-11 12:47:01 +0100 Georg Hopp 2012-02-11 12:47:01 +0100 Georg Hopp

4
include/http/header.h

@ -11,8 +11,8 @@ CLASS(HttpHeader) {
HttpHeader httpHeaderParse(char * line); // @INFO: destructive HttpHeader httpHeaderParse(char * line); // @INFO: destructive
void httpHeaderSort(const HttpHeader [], int);
char * httpHeaderGet(const HttpHeader [], int, const char *);
void httpHeaderAdd(const HttpHeader *, HttpHeader);
char * httpHeaderGet(const HttpHeader *, const char *);
size_t httpHeaderSizeGet(HttpHeader); size_t httpHeaderSizeGet(HttpHeader);
size_t httpHeaderToString(HttpHeader, char *); size_t httpHeaderToString(HttpHeader, char *);

3
include/http/request.h

@ -15,9 +15,6 @@ CLASS(HttpRequest) {
int nbody; int nbody;
}; };
void httpHeaderAdd(HttpHeader *, HttpHeader);
char * XhttpHeaderGet(HttpHeader *, const char *);
char * httpRequestHeaderGet(HttpRequest, const char *);
char httpRequestHasKeepAlive(HttpRequest); char httpRequestHasKeepAlive(HttpRequest);
#endif /* __HTTP_REQUEST_H__ */ #endif /* __HTTP_REQUEST_H__ */

6
include/http/request/parser.h

@ -7,6 +7,7 @@
#define HTTP_REQUEST_PARSER_READ_CHUNK 1024 #define HTTP_REQUEST_PARSER_READ_CHUNK 1024
typedef enum e_HttpRequestState { typedef enum e_HttpRequestState {
HTTP_REQUEST_GARBAGE=0, HTTP_REQUEST_GARBAGE=0,
HTTP_REQUEST_START, HTTP_REQUEST_START,
@ -29,6 +30,11 @@ CLASS(HttpRequestParser) {
HttpRequestState state; HttpRequestState state;
}; };
size_t httpRequestParserRead(HttpRequestParser, int);
void httpRequestParserParse(HttpRequestParser);
void httpRequestParserGetRequestLine(HttpRequest, char *);
void httpRequestParserGetHeader(HttpRequest, char *);
#endif /* __HTTP_REQUEST_PARSER_H__ */ #endif /* __HTTP_REQUEST_PARSER_H__ */
// vim: set ts=4 sw=4: // vim: set ts=4 sw=4:

5
include/http/response.h

@ -12,8 +12,7 @@ CLASS(HttpResponse) {
unsigned int status; unsigned int status;
char * reason; char * reason;
HttpHeader header[128];
int nheader;
HttpHeader header;
char * body; char * body;
int nbody; int nbody;
@ -23,7 +22,7 @@ HttpResponse httpResponse404();
void httpResponseHeaderSet(HttpResponse, const char *, const char *); void httpResponseHeaderSet(HttpResponse, const char *, const char *);
size_t httpResponseSizeGet(HttpResponse); size_t httpResponseSizeGet(HttpResponse);
size_t httpResponseToString(HttpResponse, char *);
char * httpResponseToString(HttpResponse, char *);
#endif /* __HTTP_RESPONSE_H__ */ #endif /* __HTTP_RESPONSE_H__ */

6
include/interface.h

@ -6,17 +6,11 @@
#define MAX_IFACE 32 // ATTENTION: every iface_impl will use MAX_IFACE * sizeof(void*) #define MAX_IFACE 32 // ATTENTION: every iface_impl will use MAX_IFACE * sizeof(void*)
#define IFACE(name) ((const struct i_##name const*)&i_##name##_impl) #define IFACE(name) ((const struct i_##name const*)&i_##name##_impl)
#define INIT_IFACE(name,...) \ #define INIT_IFACE(name,...) \
static const struct i_##name i_##name##_impl = {&i_##name,__VA_ARGS__} static const struct i_##name i_##name##_impl = {&i_##name,__VA_ARGS__}
#define NUMARGS(...) (sizeof((const void*[]){__VA_ARGS__})/sizeof(void*)) #define NUMARGS(...) (sizeof((const void*[]){__VA_ARGS__})/sizeof(void*))
#define INIT_IMPL(...) {NUMARGS(__VA_ARGS__), 0, {__VA_ARGS__}} #define INIT_IMPL(...) {NUMARGS(__VA_ARGS__), 0, {__VA_ARGS__}}
#define CREATE_IMPL(...) \
static struct iface_impl iface_impl = INIT_IMPL(__VA_ARGS__)
#define METHOD_GET(iface,method) (iface->method)
struct interface { struct interface {

8
src/Makefile.am

@ -7,13 +7,13 @@ SOCKET = socket.c socket/accept.c socket/connect.c socket/listen.c
SERVER = server.c server/run.c server/close_conn.c SERVER = server.c server/run.c server/close_conn.c
LOGGER = logger.c logger/stderr.c logger/syslog.c LOGGER = logger.c logger/stderr.c logger/syslog.c
REQ = http/request.c http/request/queue.c http/request/has_keep_alive.c REQ = http/request.c http/request/queue.c http/request/has_keep_alive.c
RESP = http/response.c http/response/header_set.c \
http/response/404.c http/response/size_get.c \
RESP = http/response.c http/response/404.c http/response/size_get.c \
http/response/to_string.c http/response/to_string.c
HEADER = http/header.c http/header/get.c http/header/sort.c \
HEADER = http/header.c http/header/get.c http/header/add.c http/header/sort.c \
http/header/size_get.c http/header/to_string.c http/header/size_get.c http/header/to_string.c
PARSER = http/request/parser.c http/request/parser/get_header.c \ PARSER = http/request/parser.c http/request/parser/get_header.c \
http/request/parser/parse.c http/request/parser/get_request_line.c
http/request/parser/parse.c http/request/parser/get_request_line.c \
http/request/parser/read.c
AM_CFLAGS = -Wall -I ../include/ AM_CFLAGS = -Wall -I ../include/

15
src/http/header/get.c

@ -1,3 +1,4 @@
#include <search.h>
#include <stdlib.h> #include <stdlib.h>
#include <ctype.h> #include <ctype.h>
@ -22,18 +23,16 @@ inline
int int
comp(const void * _a, const void * _b) comp(const void * _a, const void * _b)
{ {
unsigned long a = *(unsigned long *)_a;
const HttpHeader b = *(const HttpHeader *)_b;
return (a < b->hash)? -1 : (a > b->hash)? 1 : 0;
HttpHeader a = (HttpHeader)_a;
HttpHeader b = (HttpHeader)_b;
return (a->hash < b->hash)? -1 : (a->hash > b->hash)? 1 : 0;
} }
char * char *
httpHeaderGet(const HttpHeader header[], int nheader, const char * name)
httpHeaderGet(const HttpHeader * root, const char * name)
{ {
unsigned long hash = sdbm((unsigned char *)name);
HttpHeader * found;
found = bsearch(&hash, header, nheader, sizeof(HttpHeader), comp);
struct c_HttpHeader search = {sdbm((const unsigned char*)name), NULL, NULL};
HttpHeader * found = tfind(&search, (void**)root, comp);
return (NULL != found)? (*found)->value : NULL; return (NULL != found)? (*found)->value : NULL;
} }

2
src/http/request/has_keep_alive.c

@ -11,7 +11,7 @@ httpRequestHasKeepAlive(HttpRequest request)
char * header; char * header;
char * header_ptr; char * header_ptr;
header = XhttpHeaderGet(&(request->header), "connection");
header = httpHeaderGet(&(request->header), "connection");
if (NULL == header) { if (NULL == header) {
return 0; return 0;

12
src/http/request/header_get.c

@ -1,12 +0,0 @@
#include <stdlib.h>
#include <ctype.h>
#include "http/request.h"
char *
httpRequestHeaderGet(HttpRequest this, const char * name)
{
return XhttpHeaderGet(&(this->header), name);
}
// vim: set ts=4 sw=4:

42
src/http/request/parser.c

@ -56,47 +56,9 @@ _clone(void * _this, void * _base)
memcpy(this->buffer, base->buffer, this->buffer_used); memcpy(this->buffer, base->buffer, this->buffer_used);
} }
static
size_t
get_data(void * _this, int fd)
{
HttpRequestParser this = _this;
size_t remaining, chunks;
char buffer[1024];
ssize_t size = read(fd, buffer, 1024);
if (0 < size) {
remaining = this->buffer_used % HTTP_REQUEST_PARSER_READ_CHUNK;
chunks = this->buffer_used / HTTP_REQUEST_PARSER_READ_CHUNK;
/**
* because a division always rounds down
* chunks holds exactly the currently allocated chunks if
* remaining equals 0 but there is no space left.
* Else chunks holds the actually allocated amount of chunks
* minus 1.
* For this reason chunks always has to be increased by 1.
*/
chunks++;
if (size >= remaining) {
this->buffer =
realloc(this->buffer, chunks * HTTP_REQUEST_PARSER_READ_CHUNK);
}
memcpy(this->buffer + this->buffer_used, buffer, size);
this->buffer_used += size;
this->buffer[this->buffer_used] = 0;
httpRequestParserParse(this);
}
return size;
}
INIT_IFACE(Class, ctor, dtor, _clone); INIT_IFACE(Class, ctor, dtor, _clone);
INIT_IFACE(StreamReader, get_data);
INIT_IFACE(StreamReader,
(fptr_streamReaderRead)httpRequestParserRead);
CREATE_CLASS(HttpRequestParser, NULL, IFACE(Class), IFACE(StreamReader)); CREATE_CLASS(HttpRequestParser, NULL, IFACE(Class), IFACE(StreamReader));
// vim: set ts=4 sw=4: // vim: set ts=4 sw=4:

46
src/http/request/parser/get_header.c

@ -7,30 +7,6 @@
#include "http/header.h" #include "http/header.h"
#include "http/request.h" #include "http/request.h"
static
inline
unsigned long
sdbm(const unsigned char * str)
{
unsigned long hash = 0;
int c;
while ((c = tolower(*str++)))
hash = c + (hash << 6) + (hash << 16) - hash;
return hash;
}
static
inline
int
comp(const void * _a, const void * _b)
{
HttpHeader a = (HttpHeader)_a;
HttpHeader b = (HttpHeader)_b;
return (a->hash < b->hash)? -1 : (a->hash > b->hash)? 1 : 0;
}
void void
httpRequestParserGetHeader(HttpRequest request, char * line) httpRequestParserGetHeader(HttpRequest request, char * line)
{ {
@ -43,26 +19,4 @@ httpRequestParserGetHeader(HttpRequest request, char * line)
httpHeaderAdd(&(request->header), new(HttpHeader, name, value)); httpHeaderAdd(&(request->header), new(HttpHeader, name, value));
} }
void
httpHeaderAdd(HttpHeader * root, HttpHeader header)
{
HttpHeader * found = tsearch(header, (void **)root, comp);
if (*found != header) {
puts("uhh, duplicate header set. "
"This is not implemented right now. "
"Keep the first one found.");
delete(&header);
}
}
char *
XhttpHeaderGet(HttpHeader * root, const char * name)
{
struct c_HttpHeader search = {sdbm((const unsigned char*)name), NULL, NULL};
HttpHeader * found = tfind(&search, (void **)root, comp);
return (NULL != found)? (*found)->value : NULL;
}
// vim: set ts=4 sw=4: // vim: set ts=4 sw=4:

5
src/http/request/parser/parse.c

@ -37,9 +37,6 @@ httpRequestSkip(char ** data)
for (; 0 != **data && ! isalpha(**data); (*data)++); for (; 0 != **data && ! isalpha(**data); (*data)++);
} }
void httpRequestParserGetRequestLine(HttpRequest, char *);
void httpRequestParserGetHeader(HttpRequest, char *);
void void
httpRequestParserParse(HttpRequestParser this) httpRequestParserParse(HttpRequestParser this)
{ {
@ -86,7 +83,7 @@ httpRequestParserParse(HttpRequestParser this)
char * nbody; char * nbody;
if (0 == this->cur_request->nbody) { if (0 == this->cur_request->nbody) {
nbody = XhttpHeaderGet(
nbody = httpHeaderGet(
&(this->cur_request->header), &(this->cur_request->header),
"Content-Length"); "Content-Length");

19
src/http/response.c

@ -1,3 +1,8 @@
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <search.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
@ -36,20 +41,24 @@ ctor(void * _this, va_list * params)
strcpy(this->reason, reason); strcpy(this->reason, reason);
} }
static
inline
void
tDelete(void * node)
{
delete(&node);
}
static static
void void
dtor(void * _this) dtor(void * _this)
{ {
HttpResponse this = _this; HttpResponse this = _this;
int i;
_free((void **)&(this->version)); _free((void **)&(this->version));
_free((void **)&(this->reason)); _free((void **)&(this->reason));
for (i=0; i<128; i++) {
if (NULL == (this->header)[i]) break;
delete(&(this->header)[i]);
}
tdestroy(this->header, tDelete);
_free((void **)&(this->body)); _free((void **)&(this->body));
} }

13
src/http/response/404.c

@ -7,6 +7,7 @@
#include "interface/class.h" #include "interface/class.h"
#include "http/response.h" #include "http/response.h"
#include "http/header.h"
#define RESP_DATA "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n" \ #define RESP_DATA "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n" \
@ -28,20 +29,24 @@ httpResponse404()
response = new(HttpResponse, "HTTP/1.1", 404, "Not Found"); response = new(HttpResponse, "HTTP/1.1", 404, "Not Found");
httpResponseHeaderSet(response, "Content-Type", "text/html");
httpResponseHeaderSet(response, "Server", "testserver");
httpHeaderAdd(&(response->header),
new(HttpHeader, "Content-Type", "text/html"));
httpHeaderAdd(&(response->header),
new(HttpHeader, "Server", "testserver"));
response->nbody = sizeof(RESP_DATA) - 1; response->nbody = sizeof(RESP_DATA) - 1;
response->body = calloc(1, sizeof(RESP_DATA)); response->body = calloc(1, sizeof(RESP_DATA));
strcpy(response->body, RESP_DATA); strcpy(response->body, RESP_DATA);
sprintf(buffer, "%d", response->nbody); sprintf(buffer, "%d", response->nbody);
httpResponseHeaderSet(response, "Content-Length", buffer);
httpHeaderAdd(&(response->header),
new(HttpHeader, "Content-Length", buffer));
t = time(NULL); t = time(NULL);
tmp = localtime(&t); tmp = localtime(&t);
strftime(buffer, sizeof(buffer), "%a, %d %b %Y %T %Z", tmp); strftime(buffer, sizeof(buffer), "%a, %d %b %Y %T %Z", tmp);
httpResponseHeaderSet(response, "Date", buffer);
httpHeaderAdd(&(response->header),
new(HttpHeader, "Date", buffer));
return response; return response;
} }

13
src/http/response/header_set.c

@ -1,13 +0,0 @@
#include "class.h"
#include "interface/class.h"
#include "http/response.h"
#include "http/header.h"
void
httpResponseHeaderSet(HttpResponse this, const char * name, const char * value)
{
(this->header)[this->nheader++] = new(HttpHeader, name, value);
}
// vim: set ts=4 sw=4:

20
src/http/response/size_get.c

@ -1,22 +1,32 @@
#include <search.h>
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>
#include "http/response.h" #include "http/response.h"
#include "http/header.h" #include "http/header.h"
static size_t size;
static
inline
void
addHeaderSize(const void * node, const VISIT which, const int depth)
{
if (endorder == which || leaf == which) {
size += httpHeaderSizeGet(*(HttpHeader *)node) + 2;
}
}
size_t size_t
httpResponseSizeGet(HttpResponse response) httpResponseSizeGet(HttpResponse response)
{ {
int i;
size_t size = 0;
size = 0;
size += strlen(response->version) + 1; size += strlen(response->version) + 1;
size += 4; // for status size += 4; // for status
size += strlen(response->reason) + 2; size += strlen(response->reason) + 2;
for (i=0; i<response->nheader; i++) {
size += httpHeaderSizeGet(response->header[i]) + 2;
}
twalk(response->header, addHeaderSize);
size += 2; size += 2;
size += response->nbody; size += response->nbody;

29
src/http/response/to_string.c

@ -1,16 +1,29 @@
#include <search.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include "http/response.h" #include "http/response.h"
#include "http/header.h" #include "http/header.h"
size_t
httpResponseToString(HttpResponse response, char * string)
static char * string;
void
addHeaderString(const void * node, const VISIT which, const int depth)
{
if (endorder == which || leaf == which) {
string += httpHeaderToString(*(HttpHeader *)node, string);
*string++ = '\r';
*string++ = '\n';
}
}
char *
httpResponseToString(HttpResponse response, char * _string)
{ {
int i;
size_t size = httpResponseSizeGet(response);
char status[4]; char status[4];
string = _string;
snprintf(status, 4, "%d", response->status); snprintf(status, 4, "%d", response->status);
strcpy(string, response->version); strcpy(string, response->version);
@ -29,18 +42,14 @@ httpResponseToString(HttpResponse response, char * string)
*string++ = '\r'; *string++ = '\r';
*string++ = '\n'; *string++ = '\n';
for (i=0; i<response->nheader; i++) {
string += httpHeaderToString(response->header[i], string);
*string++ = '\r';
*string++ = '\n';
}
twalk(response->header, addHeaderString);
*string++ = '\r'; *string++ = '\r';
*string++ = '\n'; *string++ = '\n';
memcpy(string, response->body, response->nbody); memcpy(string, response->body, response->nbody);
return size;
return string;
} }
// vim: set ts=4 sw=4: // vim: set ts=4 sw=4:

14
src/server/run.c

@ -116,17 +116,15 @@ serverRun(Server this)
if (httpRequestHasKeepAlive(queue->requests[j])) { if (httpRequestHasKeepAlive(queue->requests[j])) {
(this->conns)[fd].keep_alive = 1; (this->conns)[fd].keep_alive = 1;
httpResponseHeaderSet(
response,
"Connection",
"Keep-Alive");
httpHeaderAdd(
&(response->header),
new(HttpHeader, "Connection", "Keep-Alive"));
} }
else { else {
(this->conns)[fd].keep_alive = 0; (this->conns)[fd].keep_alive = 0;
httpResponseHeaderSet(
response,
"Connection",
"Close");
httpHeaderAdd(
&(response->header),
new(HttpHeader, "Connection", "Close"));
} }
delete(&(queue->requests[j])); delete(&(queue->requests[j]));

Loading…
Cancel
Save