Browse Source

make sessions start on any request and clean them when they have timed out.

release0.1.5
Georg Hopp 12 years ago
parent
commit
76d164b80c
  1. 31
      include/application/application.h
  2. 3
      include/http/worker.h
  3. 9
      include/session.h
  4. 2
      src/Makefile.am
  5. 160
      src/application/adapter/http/update.c
  6. 25
      src/application/application.c
  7. 33
      src/application/login.c
  8. 5
      src/application/session_get.c
  9. 12
      src/application/session_start.c
  10. 6
      src/application/session_stop.c
  11. 20
      src/application/session_update.c
  12. 3
      src/http/Makefile.am
  13. 7
      src/http/response/session.c
  14. 7
      src/http/worker.c
  15. 47
      src/http/worker/add_computed_header.c
  16. 2
      src/http/worker/process.c
  17. 20
      src/session/session.c
  18. 15
      src/taskrambler.c
  19. 18
      src/uuid.c

31
include/application/application.h

@ -27,8 +27,11 @@
#include "class.h"
#include "session.h"
#include "hash.h"
#include "queue.h"
#include "auth/credential.h"
#include "storage.h"
#include "session.h"
struct randval {
time_t timestamp;
@ -36,18 +39,24 @@ struct randval {
};
CLASS(Application) {
Hash active_sessions;
void * auth;
struct randval * val;
// should be a list and not a queue but currently queue is
// the closest I have.
Queue active_sessions;
void ** auth;
size_t nauth;
struct randval * val;
Storage users;
};
// this should return a user account....now it only return success or failure.
int applicationLogin(Application, Credential);
unsigned long applicationSessionStart(Application, const char *, size_t);
void applicationSessionStop(Application, unsigned long);
void applicationSessionUpdate(
Application, unsigned long, const char *, size_t);
Session applicationSessionGet(Application, unsigned long);
int applicationLogin(Application, Credential, Session);
Session applicationSessionStart(Application);
Session applicationSessionGet(Application, const char *);
void applicationSessionStop(Application, const char *);
void applicationSessionUpdate(
Application, const char *, const char *, size_t);
#endif // __HTTP_HEADER_H__

3
include/http/worker.h

@ -36,6 +36,7 @@
#include "http/request.h"
#include "http/response.h"
#include "queue.h"
#include "commons.h"
@ -50,6 +51,8 @@ CLASS(HttpWorker) {
HttpRequest current_request;
HttpMessage current_response;
Queue additional_headers;
HttpParser parser;
HttpWriter writer;
};

9
include/session.h

@ -25,17 +25,20 @@
#include <time.h>
#include <sys/types.h>
#include <user.h>
#include "class.h"
#define SESSION_LIVETIME 30
// livetime of a session in seconds
#define SESSION_LIVETIME 300 // 5 minutes
CLASS(Session) {
unsigned long id;
char id[37];
unsigned long hash;
time_t livetime;
char * username;
User user;
};
#endif // __SESSION_H__

2
src/Makefile.am

@ -34,7 +34,7 @@ bin_PROGRAMS = taskrambler
taskrambler_SOURCES = taskrambler.c $(IFACE) $(UTILS)
taskrambler_CFLAGS = $(CFLAGS) -Wall -DPWD=\"$(PWD)\" -I ../include/# $(COVERAGE_CFLAGS)
taskrambler_LDADD = $(LIBS) -lrt -lssl -lldap -lgdbm
taskrambler_LDADD = $(LIBS) -lrt -lssl -lldap -lgdbm -luuid
#taskrambler_LDFLAGS = $(COVERAGE_LDFLAGS)
SUBDIRS = asset auth cbuf class hash queue http \

160
src/application/adapter/http/update.c

@ -39,26 +39,92 @@
#include "utils/memory.h"
#define NO_SESSION_SID 0
#define NO_SESSION_SID NULL
#define SESS_HEADER "{\"id\":\"%s\",\"timeout\":%d,\"timeleft\":%ld}"
static
inline
unsigned long
char *
getSessionId(Hash cookies)
{
HashValue sidstr = hashGet(cookies, CSTRA("sid"));
if (NULL != sidstr) {
return strtoul((char*)(sidstr->value), NULL, 10);
return (char*)sidstr->value;
}
return NO_SESSION_SID;
}
static
Session
getSession(Queue sess_queue, const char * sid)
{
Session sess = NULL;
time_t now = time(NULL);
/**
* session start or update
*
* @TODO
* I need to walk through the whole hash at this point to find
* expired sessions and remove them....this is not good and
* probably I need another(faster) way to identify expired
* sessions....
*
* @TODO
* Build a way to cleanup the hash by a filter...currently
* there is nothing I could use for this.
* Well this is practically impossible in reasonable time
* because every time I remove one element the tree has to
* be rebalanced....
*
* I have to store all nodes in a different structure that
* gives me the possibility to find fast expired objects.
* These can then be removed from both structures....
*
* Anyway this is the pure horror...because I have to compute
* the condition for every stored session....and I really have to
* do this...else the tree would grow and grow all the time...
*
* I think the best I can do at this point is, at least for the moment,
* to store the sessions in a list and not in a stack.
* Each request will than have to walk through that list,
* remove expired sessions and pick out its own....
* this is O(n), but currently I gave no better idea at all.
*/
while (NULL != sess_queue->next) {
Session session = (Session)sess_queue->next->msg;
if (now >= session->livetime) {
Queue to_delete = sess_queue->next;
sess_queue->next = sess_queue->next->next;
delete(session);
delete(to_delete);
continue;
}
if (NULL != sid && 0 == memcmp(session->id, sid, 36)) {
session->livetime = time(NULL) + SESSION_LIVETIME;
sess = session;
}
sess_queue = sess_queue->next;
}
if (NULL == sess) {
sess = new(Session);
queuePut(sess_queue, sess);
}
return sess;
}
static
void
loginAdapter(Application application, HttpWorker worker, unsigned long sid)
loginAdapter(Application application, HttpWorker worker, Session session)
{
HashValue username;
HashValue password;
@ -82,34 +148,7 @@ loginAdapter(Application application, HttpWorker worker, unsigned long sid)
(char *)(username->value), username->nvalue,
(char *)(password->value), password->nvalue);
if (applicationLogin(application, credential)) {
char buffer[200];
size_t nbuf;
if (NO_SESSION_SID == sid
|| NULL == applicationSessionGet(application, sid)) {
sid = applicationSessionStart(
application,
(char *)(username->value),
username->nvalue);
} else {
applicationSessionUpdate(
application,
sid,
username->value,
username->nvalue);
}
nbuf = sprintf(buffer, "sid=%lu;Path=/", sid);
worker->current_response =
(HttpMessage)httpResponseSession(
applicationSessionGet(application, sid));
hashAdd(
worker->current_response->header,
new(HttpHeader, CSTRA("Set-Cookie"), buffer, nbuf));
} else {
if (! applicationLogin(application, credential, session)) {
worker->current_response =
new(HttpResponse, "HTTP/1.1", 403, "Forbidden");
}
@ -117,53 +156,42 @@ loginAdapter(Application application, HttpWorker worker, unsigned long sid)
delete(credential);
}
void
applicationAdapterHttpUpdate(void * _this, void * subject)
{
ApplicationAdapterHttp this = _this;
HttpWorker worker = (HttpWorker)subject;
unsigned long sid = getSessionId(worker->current_request->cookies);
Session session = applicationSessionGet(this->application, sid);
if (NULL != session) {
if (time(NULL) < session->livetime) {
session->livetime = time(NULL) + SESSION_LIVETIME;
} else {
applicationSessionStop(this->application, sid);
}
}
HttpWorker worker = (HttpWorker)subject;
char * sid;
Session session;
char buf[200];
size_t nbuf;
sid = getSessionId(worker->current_request->cookies);
session = getSession(this->application->active_sessions, sid);
nbuf = sprintf(buf, SESS_HEADER,
session->id,
SESSION_LIVETIME,
session->livetime - time(NULL));
queuePut(
worker->additional_headers,
new(HttpHeader, CSTRA("X-TaskramblerSession"), buf, nbuf));
nbuf = sprintf(buf, "sid=%s;Path=/", session->id);
queuePut(
worker->additional_headers,
new(HttpHeader, CSTRA("Set-Cookie"), buf, nbuf));
if (0 == strcmp("POST", worker->current_request->method)) {
if (0 == strcmp("/login/", worker->current_request->path)) {
loginAdapter(this->application, worker, sid);
loginAdapter(this->application, worker, session);
return;
}
}
if (0 == strcmp("GET", worker->current_request->method)) {
if (0 == strcmp("/sessinfo/", worker->current_request->path)) {
worker->current_response =
(HttpMessage)httpResponseSession(
applicationSessionGet(this->application, sid));
return;
}
if (0 == strcmp("/sess/", worker->current_request->path)) {
if (NO_SESSION_SID == sid
|| NULL == applicationSessionGet(this->application, sid)) {
sid = applicationSessionStart(this->application, NULL, 0);
}
worker->current_response =
(HttpMessage)httpResponseSession(
applicationSessionGet(this->application, sid));
return;
}
if (0 == strcmp("/randval/", worker->current_request->path)) {
if (NO_SESSION_SID != sid) {
if (NO_SESSION_SID != session->id) {
worker->current_response =
(HttpMessage)httpResponseRandval(
this->application->val->timestamp,

25
src/application/application.c

@ -25,8 +25,9 @@
#include <stdarg.h>
#include "class.h"
#include "hash.h"
#include "queue.h"
#include "application/application.h"
#include "storage.h"
#include "utils/memory.h"
@ -35,11 +36,20 @@ int
applicationCtor(void * _this, va_list * params)
{
Application this = _this;
size_t i;
this->val = va_arg(*params, struct randval *);
this->auth = va_arg(*params, void *);
this->val = va_arg(*params, struct randval *);
this->active_sessions = new(Hash);
// initialize authenticators to use.
this->nauth = va_arg(*params, size_t);
this->auth = memMalloc(this->nauth * sizeof(void*));
for (i=0; i<this->nauth; i++) {
this->auth[i] = va_arg(*params, void *);
}
this->active_sessions = new(Queue);
this->users = new(Storage, "./run/users.db");
return 0;
}
@ -49,8 +59,15 @@ void
applicationDtor(void * _this)
{
Application this = _this;
size_t i;
delete(this->active_sessions);
for (i=0; i<this->nauth; i++) {
delete(this->auth[i]);
}
MEM_FREE(this->auth);
}

33
src/application/login.c

@ -34,9 +34,38 @@
int
applicationLogin(Application this, Credential credential)
applicationLogin(
Application this,
Credential credential,
Session session)
{
return authenticate(this->auth, credential);
size_t i;
for (i=0; i<this->nauth; i++) {
if (authenticate(this->auth, credential)) {
session->user = new(User, NULL);
switch (credential->type) {
case CRED_PASSWORD:
session->user->email = CRED_PWD(credential).user;
session->user->nemail = &CRED_PWD(credential).nuser;
if (NULL == userLoad(session->user, this->users)) {
session->user->email = NULL;
session->user->nemail = NULL;
}
break;
default:
break;
}
return 1;
}
}
return 0;
}
// vim: set ts=4 sw=4:

5
src/application/session_get.c

@ -33,9 +33,10 @@
Session
applicationSessionGet(Application this, unsigned long sid)
applicationSessionGet(Application this, const char * sid)
{
return hashGetByVal(this->active_sessions, sid);
// return hashGet(this->active_sessions, sid, 36);
return NULL;
}
// vim: set ts=4 sw=4:

12
src/application/session_start.c

@ -26,20 +26,20 @@
#include "class.h"
#include "session.h"
#include "hash.h"
#include "queue.h"
#include "application/application.h"
#include "utils/memory.h"
unsigned long
applicationSessionStart(Application this, const char * name, size_t nname)
Session
applicationSessionStart(Application this)
{
Session session = new(Session, name, nname);
Session session = new(Session);
hashAdd(this->active_sessions, session);
queuePut(this->active_sessions, session);
return session->id;
return session;
}
// vim: set ts=4 sw=4:

6
src/application/session_stop.c

@ -33,10 +33,10 @@
void
applicationSessionStop(Application this, unsigned long sid)
applicationSessionStop(Application this, const char * sid)
{
Session session = hashDeleteByVal(this->active_sessions, sid);
delete(session);
//Session session = hashDelete(this->active_sessions, sid, 36);
//delete(session);
}
// vim: set ts=4 sw=4:

20
src/application/session_update.c

@ -36,19 +36,19 @@
void
applicationSessionUpdate(
Application this,
unsigned long sid,
const char * sid,
const char * name,
size_t nname)
{
Session session = hashGetByVal(this->active_sessions, sid);
if (NULL != session) {
MEM_FREE(session->username);
session->username = memMalloc(nname + 1);
session->username[nname] = 0;
memcpy(session->username, name, nname);
}
// Session session = hashGet(this->active_sessions, sid, 36);
//
// if (NULL != session) {
// MEM_FREE(session->username);
//
// session->username = memMalloc(nname + 1);
// session->username[nname] = 0;
// memcpy(session->username, name, nname);
// }
}
// vim: set ts=4 sw=4:

3
src/http/Makefile.am

@ -31,7 +31,8 @@ WORKER = worker.c \
worker/process.c \
worker/answer.c \
worker/get_asset.c \
worker/add_common_header.c
worker/add_common_header.c \
worker/add_computed_header.c
HEADER = header.c \
header/to_string.c

7
src/http/response/session.c

@ -36,7 +36,7 @@
#include "utils/memory.h"
#include "hash.h"
#define RESP_DATA "{\"id\":\"%lu\",\"timeout\":%d,\"timeleft\":%ld,\"username\":\"%s\"}"
#define RESP_DATA "{\"id\":\"%s\",\"timeout\":%d,\"timeleft\":%ld}"
HttpResponse
httpResponseSession(Session session)
@ -53,10 +53,9 @@ httpResponseSession(Session session)
new(HttpHeader, CSTRA("Content-Type"), CSTRA("application/json")));
nbuf = sprintf(buffer, RESP_DATA,
(NULL != session)? session->id : 0,
(NULL != session)? session->id : "",
(NULL != session)? SESSION_LIVETIME : 0,
(NULL != session)? session->livetime - time(NULL) : 0,
(NULL != session)? session->username : "");
(NULL != session)? session->livetime - time(NULL) : 0);
message->nbody = nbuf;
message->body = memMalloc(nbuf);

7
src/http/worker.c

@ -33,6 +33,7 @@
#include "class.h"
#include "stream.h"
#include "hash.h"
#include "queue.h"
#include "http/worker.h"
#include "http/parser.h"
#include "http/writer.h"
@ -57,6 +58,8 @@ httpWorkerCtor(void * _this, va_list * params)
sprintf(cbuf_id, "%s_%s", "parser", id);
this->pbuf = new(Cbuf, cbuf_id, PARSER_MAX_BUF);
this->additional_headers = new(Queue);
this->parser = new(HttpParser, this->pbuf);
this->writer = new(HttpWriter);
@ -71,6 +74,8 @@ httpWorkerDtor(void * _this)
MEM_FREE(this->id);
delete(this->additional_headers);
delete(this->parser);
delete(this->writer);
@ -90,6 +95,8 @@ httpWorkerClone(void * _this, void * _base)
this->asset_pool = base->asset_pool;
this->application_adapter = base->application_adapter;
this->additional_headers = new(Queue);
this->parser = new(HttpParser, base->pbuf);
/*
* I am pretty sure that it is not neccessary to have a

47
src/http/worker/add_computed_header.c

@ -0,0 +1,47 @@
/**
* \file
*
* \author Georg Hopp
*
* \copyright
* Copyright © 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 <sys/types.h>
#include "class.h"
#include "http/message.h"
#include "http/header.h"
#include "http/worker.h"
#include "queue.h"
#include "utils/memory.h"
void
httpWorkerAddComputedHeader(HttpWorker this)
{
HttpHeader header = (HttpHeader)queueGet(this->additional_headers);
while(NULL != header) {
hashAdd(this->current_response->header, header);
header = (HttpHeader)queueGet(this->additional_headers);
}
}
// vim: set ts=4 sw=4:

2
src/http/worker/process.c

@ -50,6 +50,7 @@
HttpMessage httpWorkerGetAsset(HttpWorker, const char *);
void httpWorkerAddCommonHeader(HttpWorker);
void httpWorkerAddComputedHeader(HttpWorker);
ssize_t
@ -117,6 +118,7 @@ httpWorkerProcess(HttpWorker this, Stream st)
}
httpWorkerAddCommonHeader(this);
httpWorkerAddComputedHeader(this);
delete(this->current_request);
queuePut(this->writer->queue, this->current_response);
this->current_response = NULL;

20
src/session/session.c

@ -26,6 +26,7 @@
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <uuid/uuid.h>
#include "session.h"
#include "hash.h"
@ -40,15 +41,13 @@ int
sessionCtor(void * _this, va_list * params)
{
Session this = _this;
char * uname = va_arg(* params, char *);
size_t nuname = va_arg(* params, size_t);
uuid_t uuid;
this->livetime = time(NULL) + SESSION_LIVETIME;
this->id = sdbm((unsigned char *)uname, nuname) ^ this->livetime;
uuid_generate(uuid);
uuid_unparse(uuid, this->id);
this->username = memMalloc(nuname + 1);
this->username[nuname] = 0;
memcpy(this->username, uname, nuname);
this->hash = sdbm((unsigned char *)this->id, 36);
return 0;
}
@ -57,18 +56,15 @@ static
void
sessionDtor(void * _this)
{
Session this = _this;
MEM_FREE(this->username);
}
static
unsigned long
sessionGetId(void * _this)
sessionGetHash(void * _this)
{
Session this = _this;
return this->id;
return this->hash;
}
static
@ -78,7 +74,7 @@ sessionHandleDouble(void * _this, void * _doub)
}
INIT_IFACE(Class, sessionCtor, sessionDtor, NULL);
INIT_IFACE(Hashable, sessionGetId, sessionHandleDouble);
INIT_IFACE(Hashable, sessionGetHash, sessionHandleDouble);
CREATE_CLASS(Session, NULL, IFACE(Class), IFACE(Hashable));
// vim: set ts=4 sw=4:

15
src/taskrambler.c

@ -55,6 +55,9 @@
//#define DEFAULT_SECS 1
#define DEFAULT_USECS 0
#define LDAP_BASE "ou=user,dc=yabrog,dc=weird-web-workers,dc=org"
void nullhandler() {}
void daemonize(void);
@ -137,7 +140,7 @@ main()
default:
{
AuthLdap auth;
AuthLdap ldap;
Application application;
ApplicationAdapterHttp adapterHttp;
HttpWorker worker;
@ -150,11 +153,12 @@ main()
close(shm);
logger = new(LoggerSyslog, LOGGER_DEBUG);
auth = new(AuthLdap,
"ldap://hosted/",
CSTRA("ou=user,dc=yabrog,dc=weird-web-workers,dc=org"));
worker = new(HttpWorker, "testserver");
application = new(Application, value, auth);
ldap = new(
AuthLdap, "ldap://hosted/", CSTRA(LDAP_BASE));
application = new(Application, value, 1, ldap);
adapterHttp = new(ApplicationAdapterHttp, application);
subjectAttach(worker, adapterHttp);
@ -206,7 +210,6 @@ main()
delete(worker);
delete(adapterHttp);
delete(application);
delete(auth);
delete(logger);
clearMimeTypes();

18
src/uuid.c

@ -0,0 +1,18 @@
#include <uuid/uuid.h>
#include <stdio.h>
int
main(int argc, char * argv[])
{
uuid_t uuid;
char uuid_str[37];
uuid_generate(uuid);
uuid_unparse(uuid, uuid_str);
printf("%s\n", uuid_str);
return 0;
}
// vim: set ts=4 sw=4:
Loading…
Cancel
Save