Browse Source

closes #11: first very crude session handling implementation, no persitence no memory cleanups, spread over to much files TODO: clean this

master
Georg Hopp 14 years ago
parent
commit
a0ec357e0a
  1. 2
      include/http/response.h
  2. 3
      include/http/worker.h
  3. 47
      include/session.h
  4. 5
      src/Makefile.am
  5. 63
      src/http/response/403.c
  6. 77
      src/http/response/login_form.c
  7. 34
      src/http/response/me.c
  8. 41
      src/http/worker.c
  9. 78
      src/http/worker/process.c
  10. 46
      src/session.c
  11. 36
      src/session/add.c
  12. 23
      src/session/delete.c
  13. 29
      src/session/get.c

2
include/http/response.h

@ -43,7 +43,9 @@ HttpResponse httpResponse304(
const char *, size_t,
const char *, size_t);
HttpResponse httpResponse404();
HttpResponse httpResponse403();
HttpResponse httpResponseMe();
HttpResponse httpResponseLoginForm();
HttpResponse httpResponseRandval(time_t, int);
HttpResponse httpResponseAsset(
const char *,

3
include/http/worker.h

@ -31,6 +31,7 @@
#include "http/parser.h"
#include "http/writer.h"
#include "cbuf.h"
#include "session.h"
#ifndef TRUE
@ -56,6 +57,8 @@ CLASS(HttpWorker) {
HttpParser parser;
HttpWriter writer;
Session session;
Session * sroot;
};
#endif // __HTTP_WORKER_H__

47
include/session.h

@ -0,0 +1,47 @@
/**
* \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 <http://www.gnu.org/licenses/>.
*/
#ifndef __SESSION_H__
#define __SESSION_H__
#include <time.h>
#include <sys/types.h>
#include "class.h"
#define SESSION_LIVETIME 30
CLASS(Session) {
unsigned long id;
time_t livetime;
char * username;
};
Session sessionAdd(const Session *, Session);
Session sessionGet(const Session *, const unsigned long id);
void sessionDelete(const Session *, const unsigned long id);
#endif // __SESSION_H__
// vim: set ts=4 sw=4:

5
src/Makefile.am

@ -26,6 +26,8 @@ REQ = http/request.c \
RESP = http/response.c \
http/response/304.c \
http/response/404.c \
http/response/403.c \
http/response/login_form.c \
http/response/asset.c \
http/response/me.c \
http/response/randval.c
@ -43,6 +45,7 @@ WORKER = http/worker.c \
http/worker/add_common_header.c
HEADER = http/header.c http/header/get.c http/header/add.c \
http/header/to_string.c
SESSION = session.c session/add.c session/get.c session/delete.c
UTILS = utils/hash.c \
utils/memory.c \
utils/http.c \
@ -57,6 +60,6 @@ bin_PROGRAMS = testserver
testserver_SOURCES = testserver.c \
$(IFACE) $(SOCKET) $(SERVER) $(LOGGER) $(MSG) $(REQ) \
$(WRITER) $(RESP) $(HEADER) $(PARSER) $(WORKER) $(CB) \
$(UTILS) $(MSGQ)
$(UTILS) $(MSGQ) $(SESSION)
testserver_CFLAGS = -Wall -I ../include/
testserver_LDFLAGS = -lrt

63
src/http/response/403.c

@ -0,0 +1,63 @@
/**
* \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 <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include "class.h"
#include "interface/class.h"
#include "http/response.h"
#include "http/message.h"
#include "http/header.h"
HttpResponse
httpResponse403()
{
HttpResponse response;
HttpMessage message;
char buffer[200];
size_t nbuf;
response = new(HttpResponse, "HTTP/1.1", 403, "Forbidden");
message = (HttpMessage)response;
message->type = HTTP_MESSAGE_BUFFERED;
message->nbody = 0;
message->body = NULL;
nbuf = sprintf(buffer, "%d", message->nbody);
httpHeaderAdd(&(message->header),
new(HttpHeader,
"Content-Length",
sizeof("Content-Length")-1,
buffer,
nbuf));
return response;
}
// vim: set ts=4 sw=4:

77
src/http/response/login_form.c

@ -0,0 +1,77 @@
/**
* \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 <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <sys/types.h>
#include "class.h"
#include "interface/class.h"
#include "http/response.h"
#include "http/message.h"
#include "http/header.h"
#define RESP_DATA "<form action=\"/me/\" method=\"POST\">" \
"<input name=\"username\" type=\"text\" />" \
"<input type=\"submit\">" \
"</form>"
HttpResponse
httpResponseLoginForm()
{
char buffer[200];
HttpResponse response;
HttpMessage message;
size_t nbuf;
response = new(HttpResponse, "HTTP/1.1", 200, "OK");
message = (HttpMessage)response;
httpHeaderAdd(&(message->header),
new(HttpHeader,
"Content-Type",
sizeof("Content-Type")-1,
"text/html",
sizeof("text/html")-1));
message->type = HTTP_MESSAGE_BUFFERED;
message->nbody = sizeof(RESP_DATA)-1;
message->body = malloc(message->nbody);
memcpy(message->body, RESP_DATA, message->nbody);
nbuf = sprintf(buffer, "%d", message->nbody);
httpHeaderAdd(&(message->header),
new(HttpHeader,
"Content-Length",
sizeof("Content-Length")-1,
buffer,
nbuf));
return response;
}
// vim: set ts=4 sw=4:

34
src/http/response/me.c

@ -60,15 +60,31 @@
"$(document).ready(function() {" \
"var intervalId;" \
"var vnext = 0;" \
"var clickclose = function() {" \
"clearInterval(intervalId);" \
"vnext = 0;" \
"$(\"#randval\").addClass(\"hide\");" \
"};" \
"var counter = function() {" \
"if (0 >= vnext) {" \
"$.getJSON(\"/randval/\", function(data) {" \
"$.getJSON(\"/randval/\", function(data, xhr) {" \
"var date = new Date(data.ctime * 1000);" \
"$(\"#ctime\").empty().append(date.toString());" \
"vnext = data.vnext;" \
"$(\"#value\").empty().append(data.value);" \
"$(\"#vnext\").empty().append(vnext);" \
"$(\"#randval\").on(\"click\", clickclose);" \
"}).error(function(event, request, settings) {" \
"clearInterval(intervalId);" \
"$.get(\"/login/\", function(data) {" \
"$(\"#randval\")" \
".off(\"click\", clickclose)" \
".empty().append(data);" \
"});" \
"});" \
"if ($(\"#randval\").hasClass(\"hide\")) {" \
"$(\"#randval\").removeClass(\"hide\");" \
"}" \
"} else {" \
"vnext--;" \
"$(\"#vnext\").empty().append(vnext);" \
@ -83,12 +99,6 @@
"});" \
"$(\"a\").click(function() {" \
"intervalId = setInterval(counter, 1000);" \
"$(\"#randval\").removeClass(\"hide\");" \
"});" \
"$(\"#randval\").click(function() {" \
"clearInterval(intervalId);" \
"vnext = 0;" \
"$(\"#randval\").addClass(\"hide\");" \
"});" \
"});" \
"</script>" \
@ -103,6 +113,7 @@
"</div>" \
"<div id=\"main\">" \
"<h1>Testpage</h1>" \
"Welcome %s<br />" \
"<img src=\"/image/\" />" \
"<br /><a href=\"#\">Link</a>" \
"</div>" \
@ -111,7 +122,7 @@
"</html>"
HttpResponse
httpResponseMe()
httpResponseMe(char * uname)
{
char buffer[200];
HttpResponse response;
@ -141,9 +152,10 @@ httpResponseMe()
sizeof("profession=\"coder\"")-1));
message->type = HTTP_MESSAGE_BUFFERED;
message->nbody = sizeof(RESP_DATA)-1;
message->body = malloc(sizeof(RESP_DATA)-1);
memcpy(message->body, RESP_DATA, sizeof(RESP_DATA)-1);
message->nbody = sizeof(RESP_DATA)-1-2+strlen(uname); //!< the two are the %s
message->body = malloc(message->nbody+1);
sprintf(message->body, RESP_DATA, uname);
//memcpy(message->body, RESP_DATA, sizeof(RESP_DATA)-1);
nbuf = sprintf(buffer, "%d", message->nbody);

41
src/http/worker.c

@ -1,8 +1,32 @@
#include <stdlib.h>
/**
* \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 <http://www.gnu.org/licenses/>.
*/
#define _GNU_SOURCE
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <search.h>
#include "class.h"
#include "http/worker.h"
@ -37,9 +61,19 @@ httpWorkerCtor(void * _this, va_list * params)
this->parser = new(HttpParser, this->pbuf);
this->writer = new(HttpWriter, this->wbuf);
this->sroot = &(this->session);
return 0;
}
static
inline
void
tDelete(void * node)
{
delete(node);
}
static
void
httpWorkerDtor(void * _this)
@ -51,8 +85,11 @@ httpWorkerDtor(void * _this)
delete(this->parser);
delete(this->writer);
if (NULL != this->pbuf) {
delete(this->pbuf); //!< cloned workers have NULL, so delete won't do anything
delete(this->wbuf); //!< cloned workers have NULL, so delete won't do anything
tdestroy(*(this->sroot), tDelete);
}
}
static
@ -66,6 +103,8 @@ httpWorkerClone(void * _this, void * _base)
this->parser = new(HttpParser, base->pbuf);
this->writer = new(HttpWriter, base->wbuf);
this->sroot = &(base->session);
}
ssize_t httpWorkerProcess(void *, int);

78
src/http/worker/process.c

@ -21,6 +21,9 @@
*/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "class.h"
#include "interface/class.h"
@ -31,6 +34,7 @@
#include "http/response.h"
#include "http/message/queue.h"
#include "http/parser.h"
#include "session.h"
HttpMessage httpWorkerGetAsset(HttpRequest, const char *, const char *, size_t);
void httpWorkerAddCommonHeader(HttpMessage, HttpMessage);
@ -49,19 +53,91 @@ httpWorkerProcess(HttpWorker this, int fd)
HttpMessageQueue respq = this->writer->queue;
for (i=0; i<reqq->nmsgs; i++) {
HttpMessage rmessage = reqq->msgs[i];
HttpRequest request = (HttpRequest)(reqq->msgs[i]);
HttpMessage response = NULL;
HttpHeader cookie = httpHeaderGet(
&(rmessage->header),
"cookie",
sizeof("Cookie")-1);
if (NULL == this->session && NULL != cookie) {
int i;
for (i=0; i<cookie->cvalue; i++) {
char * sidstr = strstr(cookie->value[i], "sid");
if (NULL != sidstr) {
unsigned long sid;
sidstr = strchr(sidstr, '=')+1;
sid = strtoul(sidstr, NULL, 10);
this->session = sessionGet(this->sroot, sid);
break;
}
}
}
if (NULL != this->session) {
if (time(NULL) < this->session->livetime) {
this->session->livetime = time(NULL) + SESSION_LIVETIME;
} else {
sessionDelete(this->sroot, this->session->id);
delete(this->session);
}
}
if (0 == strcmp("POST", request->method)) {
if (0 == strcmp("/me/", request->uri)) {
char * delim = memchr(rmessage->body, '=', rmessage->nbody);
char * key = rmessage->body;
char * val;
size_t nkey, nval;
char buffer[200];
size_t nbuf;
nkey = delim - rmessage->body - 1;
*delim = 0;
val = delim + 1;
nval = rmessage->nbody - (val - rmessage->body);
this->session = sessionAdd(
this->sroot,
new(Session, val, nval));
nbuf = sprintf(buffer, "sid=%lu;Path=/", this->session->id);
response = (HttpMessage)httpResponseMe(this->session->username);
httpHeaderAdd(
&(response->header),
new(HttpHeader,
"Set-Cookie",
sizeof("Set-Cookie")-1,
buffer,
nbuf));
}
}
if (0 == strcmp("GET", request->method)) {
if (0 == strcmp("/login/", request->uri)) {
response = (HttpMessage)httpResponseLoginForm();
}
if (0 == strcmp("/me/", request->uri)) {
response = (HttpMessage)httpResponseMe();
char * uname = (NULL != this->session)? this->session->username : "";
response = (HttpMessage)httpResponseMe(uname);
}
if (0 == strcmp("/randval/", request->uri)) {
if (NULL != this->session) {
response = (HttpMessage)httpResponseRandval(
this->val->timestamp,
this->val->value);
} else {
response = (HttpMessage)httpResponse403();
}
}
if (0 == strcmp("/image/", request->uri)) {

46
src/session.c

@ -0,0 +1,46 @@
#include <time.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include "session.h"
#include "class.h"
#include "interface/class.h"
#include "utils/hash.h"
#include "utils/memory.h"
static
int
sessionCtor(void * _this, va_list * params)
{
Session this = _this;
char * uname = va_arg(* params, char *);
size_t nuname = va_arg(* params, size_t);
this->livetime = time(NULL) + SESSION_LIVETIME;
this->id = sdbm((unsigned char *)uname, nuname) & this->livetime;
this->username = malloc(nuname + 1);
this->username[nuname] = 0;
memcpy(this->username, uname, nuname);
return 0;
}
static
void
sessionDtor(void * _this)
{
Session this = _this;
FREE(this->username);
}
INIT_IFACE(Class, sessionCtor, sessionDtor, NULL);
CREATE_CLASS(Session, NULL, IFACE(Class));
// vim: set ts=4 sw=4:

36
src/session/add.c

@ -0,0 +1,36 @@
#include <search.h>
#include "session.h"
#include "interface/class.h"
static
inline
int
sessionAddComp(const void * _a, const void * _b)
{
Session a = (Session)_a;
Session b = (Session)_b;
return (a->id < b->id)? -1 : (a->id > b->id)? 1 : 0;
}
Session
sessionAdd(const Session * root, Session session)
{
Session * found = tsearch(session, (void**)root, sessionAddComp);
if (NULL == found) {
return NULL;
}
if (*found != session) {
/**
* \todo this should not happen, so do some logging here.
*/
delete(session);
}
return *found;
}
// vim: set ts=4 sw=4:

23
src/session/delete.c

@ -0,0 +1,23 @@
#include <search.h>
#include "session.h"
#include "interface/class.h"
static
inline
int
sessionDeleteComp(const void * _a, const void * _b)
{
unsigned long a = *(unsigned long *)_a;
Session b = (Session)_b;
return (a < b->id)? -1 : (a > b->id)? 1 : 0;
}
void
sessionDelete(const Session * root, const unsigned long id)
{
tdelete(&id, (void**)root, sessionDeleteComp);
}
// vim: set ts=4 sw=4:

29
src/session/get.c

@ -0,0 +1,29 @@
#include <search.h>
#include <time.h>
#include "session.h"
static
inline
int
sessionGetComp(const void * _a, const void * _b)
{
unsigned long a = *(unsigned long *)_a;
Session b = (Session)_b;
return (a < b->id)? -1 : (a > b->id)? 1 : 0;
}
Session
sessionGet(const Session * root, const unsigned long id)
{
Session * found = tfind(&id, (void**)root, sessionGetComp);
if (NULL == found) {
return NULL;
}
return *found;
}
// vim: set ts=4 sw=4:
Loading…
Cancel
Save