A task management system. At least this was the initial idea. Basically this it the base code for the taskrambler framework.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

300 lines
7.6 KiB

/**
* \file
*
* \author Georg Hopp
*
* \copyright
* Copyright © 2013 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 <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include "class.h"
#include "application/application.h"
#include "application/adapter/http.h"
#include "hash.h"
#include "http/worker.h"
#include "http/header.h"
#include "http/response.h"
#include "auth/credential.h"
#include "user.h"
#include "utils/memory.h"
#define NO_SESSION_SID NULL
#define SESS_HEADER "{\"id\":\"%s\",\"timeout\":%d,\"timeleft\":%ld}"
static
inline
char *
getSessionId(Hash cookies)
{
HashValue sidstr = hashGet(cookies, CSTRA("sid"));
if (NULL != sidstr) {
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, Session session)
{
HashValue username;
HashValue password;
Credential credential;
username = hashGet(
worker->current_request->post,
CSTRA("username"));
password = hashGet(
worker->current_request->post,
CSTRA("password"));
if (NULL == username || NULL == password) {
worker->current_response =
new(HttpResponse, "HTTP/1.1", 403, "Forbidden");
return;
}
credential = new(Credential,
CRED_PASSWORD,
(char *)(username->value), username->nvalue,
(char *)(password->value), password->nvalue);
if (! applicationLogin(application, credential, session)) {
worker->current_response =
new(HttpResponse, "HTTP/1.1", 403, "Forbidden");
} else {
worker->current_response =
(HttpMessage)httpResponseUser(session->user);
}
delete(credential);
}
static
void
signupAdapter(Application application, HttpWorker worker, Session session)
{
HashValue email;
HashValue password;
HashValue pwrepeat;
HashValue firstname;
HashValue surname;
Credential credential;
User user;
email = hashGet(
worker->current_request->post,
CSTRA("email"));
password = hashGet(
worker->current_request->post,
CSTRA("password"));
pwrepeat = hashGet(
worker->current_request->post,
CSTRA("pwrepeat"));
firstname = hashGet(
worker->current_request->post,
CSTRA("firstname"));
surname = hashGet(
worker->current_request->post,
CSTRA("surname"));
if (
NULL == email ||
NULL == password ||
NULL == pwrepeat ||
NULL == firstname ||
NULL == surname) {
// maybe this is not a 500...have to check repsonse codes.
worker->current_response = (HttpMessage)httpResponse500();
return;
}
if (password->nvalue != pwrepeat->nvalue ||
0 != memcmp(password->value, pwrepeat->value, password->nvalue)) {
// maybe this is not a 500...have to check repsonse codes.
worker->current_response = (HttpMessage)httpResponse500();
return;
}
credential = new(Credential,
CRED_PASSWORD,
(char *)(email->value), email->nvalue,
(char *)(password->value), password->nvalue);
user = new(User,
(char *)(email->value), email->nvalue,
(char *)(firstname->value), firstname->nvalue,
(char *)(surname->value), surname->nvalue);
if (! applicationSignup(application, credential, user, session)) {
worker->current_response = (HttpMessage)httpResponse500();
} else {
loginAdapter(application, worker, session);
}
delete(credential);
delete(user);
}
void
applicationAdapterHttpUpdate(void * _this, void * subject)
{
ApplicationAdapterHttp this = _this;
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, session);
return;
}
if (0 == strcmp("/signup/", worker->current_request->path)) {
signupAdapter(this->application, worker, session);
return;
}
}
if (0 == strcmp("GET", worker->current_request->method)) {
if (0 == strcmp("/user/get/", worker->current_request->path)) {
worker->current_response =
(HttpMessage)httpResponseUser(session->user);
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 (NULL != session->user) {
worker->current_response =
(HttpMessage)httpResponseRandval(
this->application->val->timestamp,
this->application->val->value);
} else {
worker->current_response = (HttpMessage)httpResponse403();
}
}
}
}
// vim: set ts=4 sw=4: