From 59ccbf0207cf5acca3668f56cb5dc1f6da0de3c0 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Wed, 22 Feb 2012 08:48:43 +0100 Subject: [PATCH] closes #10: values for header ids are now stored in a char ** making multiple values for one id possible. Additionally added a jquery action that delivers the jquery java script and use it on the me action --- ChangeLog | 8 ++- include/http/header.h | 11 ++-- include/http/response.h | 1 + src/Makefile.am | 1 + src/http/header.c | 15 ++++-- src/http/header/add.c | 8 +-- src/http/header/get.c | 4 +- src/http/header/size_get.c | 7 ++- src/http/header/to_string.c | 17 +++++-- src/http/message/has_keep_alive.c | 11 ++-- src/http/message/header_size_get.c | 2 +- src/http/message/header_to_string.c | 2 - src/http/request/parser/get_body.c | 6 +-- src/http/response/jquery.c | 78 +++++++++++++++++++++++++++++ src/http/response/me.c | 25 +++++++-- src/http/worker/process.c | 13 +++++ src/testserver.c | 14 +++--- 17 files changed, 179 insertions(+), 44 deletions(-) create mode 100644 src/http/response/jquery.c diff --git a/ChangeLog b/ChangeLog index 6280440..91f9c5a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,10 +1,14 @@ +2012-02-22 08:48:43 +0100 Georg Hopp + + * closes #10: values for header ids are now stored in a char ** making multiple values for one id possible. Additionally added a jquery action that delivers the jquery java script and use it on the me action (HEAD, master) + 2012-02-21 13:01:38 +0100 Georg Hopp - * now when a constructor returns -1 the new call will in turn call the destructor effectively freeing all resources. ATTENTION: now the destructor has to be aware that it might be called with a not completely initialized object. To make this more ease there is the FREE makro with the corresponding ffree that does NULL pointer checking and the destructor checks for NULL pointer too. Additionally the handle_accept now handles _SC_OPEN_MAX - 10 connections. The 10 are reserved for internal usage. (HEAD, master) + * now when a constructor returns -1 the new call will in turn call the destructor effectively freeing all resources. ATTENTION: now the destructor has to be aware that it might be called with a not completely initialized object. To make this more ease there is the FREE makro with the corresponding ffree that does NULL pointer checking and the destructor checks for NULL pointer too. Additionally the handle_accept now handles _SC_OPEN_MAX - 10 connections. The 10 are reserved for internal usage. (origin/master, origin/HEAD) 2012-02-21 09:45:01 +0100 Georg Hopp - * now a child is spawned and writes random values in a shared memory segment. These values will be shown in the me action (origin/master, origin/HEAD) + * now a child is spawned and writes random values in a shared memory segment. These values will be shown in the me action 2012-02-20 21:36:55 +0100 Georg Hopp diff --git a/include/http/header.h b/include/http/header.h index e151338..db88fbc 100644 --- a/include/http/header.h +++ b/include/http/header.h @@ -30,15 +30,16 @@ CLASS(HttpHeader) { unsigned long hash; char * name; - char * value; + char ** value; + size_t nvalue; }; HttpHeader httpHeaderParse(char * line); // @INFO: destructive -void httpHeaderAdd(const HttpHeader *, HttpHeader); -char * httpHeaderGet(const HttpHeader *, const char *); -size_t httpHeaderSizeGet(HttpHeader); -size_t httpHeaderToString(HttpHeader, char *); +void httpHeaderAdd(const HttpHeader *, HttpHeader); +HttpHeader httpHeaderGet(const HttpHeader *, const char *); +size_t httpHeaderSizeGet(HttpHeader); +size_t httpHeaderToString(HttpHeader, char *); #endif // __HTTP_HEADER_H__ diff --git a/include/http/response.h b/include/http/response.h index bb31c34..da9e668 100644 --- a/include/http/response.h +++ b/include/http/response.h @@ -42,6 +42,7 @@ HttpResponse httpResponse304(int, const char *); HttpResponse httpResponse404(); HttpResponse httpResponseMe(int); HttpResponse httpResponseImage(int); +HttpResponse httpResponseJquery(int); #endif // __HTTP_RESPONSE_H__ diff --git a/src/Makefile.am b/src/Makefile.am index 9553921..bb164ee 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -24,6 +24,7 @@ RESP = http/response.c \ http/response/304.c \ http/response/404.c \ http/response/image.c \ + http/response/jquery.c \ http/response/me.c WORKER = http/worker.c http/worker/process.c http/worker/write.c WRITER = http/response/writer.c http/response/writer/write.c diff --git a/src/http/header.c b/src/http/header.c index df678d0..6b12a5d 100644 --- a/src/http/header.c +++ b/src/http/header.c @@ -29,6 +29,7 @@ #include "http/header.h" #include "utils/hash.h" +#include "utils/memory.h" static int @@ -45,8 +46,9 @@ ctor(void * _this, va_list * params) { this->hash = sdbm((unsigned char *)name); - this->value = malloc(strlen(value) + 1); - strcpy(this->value, value); + this->value = malloc(sizeof(char*) * (++this->nvalue)); + this->value[this->nvalue - 1] = malloc(strlen(value) + 1); + strcpy(this->value[this->nvalue - 1], value); return 0; } @@ -56,9 +58,14 @@ void dtor(void * _this) { HttpHeader this = _this; + size_t i; - free(this->name); - free(this->value); + FREE(&(this->name)); + + for (i=0; invalue; i++) { + FREE(&(this->value[i])); + } + FREE(&(this->value)); } INIT_IFACE(Class, ctor, dtor, NULL); diff --git a/src/http/header/add.c b/src/http/header/add.c index a257faa..5af6bbe 100644 --- a/src/http/header/add.c +++ b/src/http/header/add.c @@ -22,6 +22,8 @@ #include #include +#include +#include #include "class.h" #include "interface/class.h" @@ -44,9 +46,9 @@ httpHeaderAdd(const 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."); + (*found)->value = realloc((*found)->value, sizeof(char) * (++(*found)->nvalue)); + (*found)->value[(*found)->nvalue - 1] = malloc(strlen(header->value) + 1); + strcpy(((*found)->value)[(*found)->nvalue - 1], (header->value)[0]); delete(&header); } } diff --git a/src/http/header/get.c b/src/http/header/get.c index 49f1b00..1b37eb2 100644 --- a/src/http/header/get.c +++ b/src/http/header/get.c @@ -38,13 +38,13 @@ comp(const void * _a, const void * _b) return (a->hash < b->hash)? -1 : (a->hash > b->hash)? 1 : 0; } -char * +HttpHeader httpHeaderGet(const 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; + return (NULL != found)? *found : NULL; } // vim: set ts=4 sw=4: diff --git a/src/http/header/size_get.c b/src/http/header/size_get.c index f51aa2f..b270660 100644 --- a/src/http/header/size_get.c +++ b/src/http/header/size_get.c @@ -29,9 +29,12 @@ size_t httpHeaderSizeGet(HttpHeader header) { size_t size = 0; + int i; - size += strlen(header->name) + 2; - size += strlen(header->value); + for (i=0; invalue; i++) { + size += strlen(header->name) + 2; + size += strlen(header->value[i]) + 2; + } return size; } diff --git a/src/http/header/to_string.c b/src/http/header/to_string.c index cda833d..8b52596 100644 --- a/src/http/header/to_string.c +++ b/src/http/header/to_string.c @@ -29,14 +29,21 @@ size_t httpHeaderToString(HttpHeader header, char * string) { size_t size = httpHeaderSizeGet(header); + int i; - strcpy(string, header->name); - string += strlen(string); + for (i=0; invalue; i++) { + strcpy(string, header->name); + string += strlen(string); - *string++ = ':'; - *string++ = ' '; + *string++ = ':'; + *string++ = ' '; - strcpy(string, header->value); + strcpy(string, header->value[i]); + string += strlen(string); + + *string++ = '\r'; + *string++ = '\n'; + } return size; } diff --git a/src/http/message/has_keep_alive.c b/src/http/message/has_keep_alive.c index 748eb9e..638408b 100644 --- a/src/http/message/has_keep_alive.c +++ b/src/http/message/has_keep_alive.c @@ -31,8 +31,8 @@ char httpMessageHasKeepAlive(HttpMessage message) { - char * header; - char * header_ptr; + HttpHeader header; + char * con; header = httpHeaderGet(&(message->header), "connection"); @@ -40,11 +40,12 @@ httpMessageHasKeepAlive(HttpMessage message) return 0; } - for (header_ptr = header; 0 != *header_ptr; header_ptr++) { - *header_ptr = tolower(*header_ptr); + con = (header->value)[0]; + for (; 0 != *con; con++) { + *con = tolower(*con); } - if (0 == strcmp(header, "keep-alive")) { + if (0 == strcmp(con, "keep-alive")) { return 1; } diff --git a/src/http/message/header_size_get.c b/src/http/message/header_size_get.c index 1f98d43..b53ed7b 100644 --- a/src/http/message/header_size_get.c +++ b/src/http/message/header_size_get.c @@ -37,7 +37,7 @@ void addHeaderSize(const void * node, const VISIT which, const int depth) { if (endorder == which || leaf == which) { - size += httpHeaderSizeGet(*(HttpHeader *)node) + 2; + size += httpHeaderSizeGet(*(HttpHeader *)node); } } diff --git a/src/http/message/header_to_string.c b/src/http/message/header_to_string.c index aee3a83..ba223ab 100644 --- a/src/http/message/header_to_string.c +++ b/src/http/message/header_to_string.c @@ -35,8 +35,6 @@ addHeaderString(const void * node, const VISIT which, const int depth) { if (endorder == which || leaf == which) { string += httpHeaderToString(*(HttpHeader *)node, string); - *string++ = '\r'; - *string++ = '\n'; } } diff --git a/src/http/request/parser/get_body.c b/src/http/request/parser/get_body.c index 12f633f..f9004c9 100644 --- a/src/http/request/parser/get_body.c +++ b/src/http/request/parser/get_body.c @@ -43,17 +43,17 @@ httpRequestParserGetBody(HttpRequestParser this) size_t len; if (0 == message->nbody) { - char * nbody = httpHeaderGet( + HttpHeader clen = httpHeaderGet( &(message->header), "Content-Length"); - if (NULL == nbody) { + if (NULL == clen) { this->state = HTTP_REQUEST_DONE; return; } else { message->type = HTTP_MESSAGE_BUFFERED; - message->nbody = atoi(nbody); + message->nbody = atoi((clen->value)[0]); message->body = calloc(1, message->nbody); message->dbody = 0; } diff --git a/src/http/response/jquery.c b/src/http/response/jquery.c new file mode 100644 index 0000000..ba1d303 --- /dev/null +++ b/src/http/response/jquery.c @@ -0,0 +1,78 @@ +/** + * \file + * + * \author Georg Hopp + * + * \copyright + * Copyright (C) 2012 Georg Hopp + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +#include "class.h" +#include "interface/class.h" + +#include "http/response.h" +#include "http/message.h" +#include "http/header.h" + + +HttpResponse +httpResponseJquery(int handle) +{ + time_t t; + struct tm * tmp; + char buffer[200]; + struct stat st; + HttpResponse response; + HttpMessage message; + + fstat(handle, &st); + + response = new(HttpResponse, "HTTP/1.1", 200, "OK"); + message = (HttpMessage)response; + + httpHeaderAdd(&(message->header), + new(HttpHeader, "Content-Type", "text/javascript")); + httpHeaderAdd(&(message->header), + new(HttpHeader, "Server", "testserver")); + + message->type = HTTP_MESSAGE_PIPED; + message->handle = handle; + message->nbody = st.st_size; + + sprintf(buffer, "%d", message->nbody); + httpHeaderAdd(&(message->header), + new(HttpHeader, "Content-Length", buffer)); + + tmp = localtime(&(st.st_mtime)); + strftime(buffer, sizeof(buffer), "%s", tmp); + httpHeaderAdd(&(message->header), + new(HttpHeader, "ETag", buffer)); + + t = time(NULL); + tmp = localtime(&t); + strftime(buffer, sizeof(buffer), "%a, %d %b %Y %T %Z", tmp); + httpHeaderAdd(&(message->header), + new(HttpHeader, "Date", buffer)); + + return response; +} + +// vim: set ts=4 sw=4: diff --git a/src/http/response/me.c b/src/http/response/me.c index e91df81..809a143 100644 --- a/src/http/response/me.c +++ b/src/http/response/me.c @@ -35,9 +35,24 @@ #define RESP_DATA "\n" \ "\n" \ - "\n" \ - "200 - OK" \ - "

200 - OK


%02d" \ + "" \ + "" \ + "200 - OK" \ + "" \ + "" \ + "" \ + "" \ + "

Testpage

" \ + "" \ + "
%02d" \ + "
Link" \ + "" \ "" @@ -55,6 +70,10 @@ httpResponseMe(int value) new(HttpHeader, "Content-Type", "text/html")); httpHeaderAdd(&(message->header), new(HttpHeader, "Server", "testserver")); + httpHeaderAdd(&(message->header), + new(HttpHeader, "Set-Cookie", "name=\"Georg Hopp\"")); + httpHeaderAdd(&(message->header), + new(HttpHeader, "Set-Cookie", "profession=\"coder\"")); message->type = HTTP_MESSAGE_BUFFERED; message->nbody = sizeof(RESP_DATA) - 1; diff --git a/src/http/worker/process.c b/src/http/worker/process.c index 6ba8a3a..2226cef 100644 --- a/src/http/worker/process.c +++ b/src/http/worker/process.c @@ -71,6 +71,19 @@ httpWorkerProcess(HttpWorker this, int fd) response = (HttpMessage)httpResponseImage(handle); } } + else if (0 == strcmp("GET", request->method) && + 0 == strcmp("/jquery/", request->uri)) { + int handle = open("./assets/jquery-1.7.1.min.js", O_RDONLY); + + if (NULL != httpHeaderGet( + &(((HttpMessage)request)->header), + "If-None-Match")) { + response = (HttpMessage)httpResponse304(handle, "text/javascript"); + } + else { + response = (HttpMessage)httpResponseJquery(handle); + } + } else { response = (HttpMessage)httpResponse404(); } diff --git a/src/testserver.c b/src/testserver.c index c32a9ae..c545ea0 100644 --- a/src/testserver.c +++ b/src/testserver.c @@ -42,10 +42,10 @@ #include "utils/signalHandling.h" -//#define DEFAULT_SECS 0 -//#define DEFAULT_USECS (1000000 / HZ) #define DEFAULT_SECS 1 -#define DEFAULT_USECS 0 +#define DEFAULT_USECS (1000000 / HZ * 2) +//#define DEFAULT_SECS 1 +//#define DEFAULT_USECS 0 void nullhandler() {} @@ -103,16 +103,16 @@ main() exit (1); } - interval.it_value.tv_sec = DEFAULT_SECS; - interval.it_value.tv_usec = DEFAULT_USECS; - interval.it_interval.tv_sec = DEFAULT_SECS; + interval.it_value.tv_sec = DEFAULT_SECS; + interval.it_value.tv_usec = DEFAULT_USECS; + interval.it_interval.tv_sec = DEFAULT_SECS; interval.it_interval.tv_usec = DEFAULT_USECS; setitimer(ITIMER_REAL, &interval, NULL); // child while(!doShutdown) { - *value = rand() % 10; + *value = rand() % 100; sigsuspend(&pause_mask); }