Browse Source

implemented an application class as well as an http adapter for it and use it to start application logic by http requests as well as creating a fitting repsonse. Not perfect, but a start. This code is not finish and will not work...in fact it won't even compile i think. refs #24

release0.1.5
Georg Hopp 12 years ago
parent
commit
36612df0da
  1. 36
      include/application/adapter/http.h
  2. 49
      include/application/application.h
  3. 18
      include/http/worker.h
  4. 6
      include/interface/observer.h
  5. 63
      src/application/adapter/http/http.c
  6. 161
      src/application/adapter/http/update.c
  7. 54
      src/application/application.c
  8. 64
      src/http/worker.c
  9. 20
      src/http/worker/add_common_header.c
  10. 7
      src/http/worker/get_asset.c
  11. 148
      src/http/worker/process.c
  12. 4
      src/interface/observer.c
  13. 10
      src/taskrambler.c

36
include/application/adapter/http.h

@ -0,0 +1,36 @@
/**
* \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/>.
*/
#ifndef __APPLICATION_ADAPTER_HTTP_H__
#define __APPLICATION_ADAPTER_HTTP_H__
#include "class.h"
#include "application.h"
CLASS(ApplicationAdapterHttp) {
Application application;
};
#endif // __APPLICATION_ADAPTER_HTTP_H__
// vim: set ts=4 sw=4:

49
include/application/application.h

@ -0,0 +1,49 @@
/**
* \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/>.
*/
#ifndef __APPLICATION_H__
#define __APPLICATION_H__
#include "class.h"
#include "auth/credential.h"
struct randval {
time_t timestamp;
int value;
}
CLASS(Application) {
Hash active_sessions;
void * auth;
struct randval * val;
};
// this should return a user account....now it only return success or failure.
int applicationLogin(Application, Credential);
unsigned long applicationSessionStart(Application);
void applicationSessionStop(Application, unsigned long);
Session applicationSessionGet(Application, unsigned long);
#endif // __HTTP_HEADER_H__
// vim: set ts=4 sw=4:

18
include/http/worker.h

@ -34,28 +34,24 @@
#include "cbuf.h"
#include "session.h"
#include "http/request.h"
#include "http/response.h"
#include "commons.h"
struct randval {
time_t timestamp;
int value;
};
CLASS(HttpWorker) {
char * id;
struct randval * val;
Cbuf pbuf;
Hash asset_pool;
void * application_adapter;
HttpRequest current_request;
HttpMessage current_response;
HttpParser parser;
HttpWriter writer;
Session session;
Session * sroot;
void * auth;
};
#endif // __HTTP_WORKER_H__

6
include/interface/observer.h

@ -24,16 +24,16 @@
#ifndef __OBSERVER_H__
#define __OBSERVER_H__
typedef void (* fptr_observerNotify)(void *, void*);
typedef void (* fptr_observerUpdate)(void *, void*);
extern const struct interface i_Observer;
struct i_Observer {
const struct interface * const _;
fptr_observerNotify notify;
fptr_observerUpdate update;
};
extern void observerNotify(void *, void *);
extern void observerUpdate(void *, void *);
#endif // __OBSERVER_H__

63
src/application/adapter/http/http.c

@ -0,0 +1,63 @@
/**
* \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/>.
*/
#define _GNU_SOURCE
#include <stdarg.h>
#include "class.h"
#include "application/application.h"
#include "application/adapter/http.h"
#include "utils/memory.h"
#include "interface/observer.h"
static
int
applicationAdapterHttpCtor(void * _this, va_list * params)
{
ApplicationAdapterHttp this = _this;
this->application = va_arg(*params, Application);
return 0;
}
static
void
applicationAdapterHttpDtor(void * _this)
{
}
void applicationAdapterHttpUpdate(ApplicationAdapterHttp, void *);
INIT_IFACE(Class, applicationAdapterHttpCtor, applicationAdapterHttpDtor);
INIT_IFACE(Observer, applicationAdapterHttpUpdate);
CREATE_CLASS(
ApplicationAdapterHttp,
NULL,
IFACE(Class),
IFACE(Observer));
// vim: set ts=4 sw=4:

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

@ -0,0 +1,161 @@
/**
* \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/>.
*/
#define _GNU_SOURCE
#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 "utils/memory.h"
#define NO_SESSION_SID 0
static
inline
unsigned long
getSessionId(Hash cookies)
{
HashValue sidstr = hashGet(cookies, CSTRA("sid"));
if (NULL != sidstr) {
return strtoul((char*)(sidstr->value), NULL, 10);
}
return NO_SESSION_SID;
}
static
void
loginAdapter(Application application, HttpWorker worker)
{
HashValue username;
HashValue passeord;
Credential credential;
username = hashGet(
worker->current_reqeust->post,
CSTRA("username"));
password = hashGet(
worker->current_reqeust->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)) {
char buffer[200];
size_t nbuf;
if (NO_SESSION_SID == sid) {
sid = applicationSessionStart(application);
} else {
applicationSessionUpdate(
application,
sid,
username->value,
username->nvalue);
}
nbuf = sprintf(buffer, "sid=%lu;Path=/", sid);
worker->current_response =
(HttpMessage)httpResponseSession(
applicationSessionGet(sid));
hashAdd(
worker->current_response->header,
new(HttpHeader. CSTRA("Set-Cookie"), buffer, nbuf));
} else {
worker->current_response =
new(HttpResponse, "HTTP/1.1", 403, "Forbidden");
}
delete(credential)
}
void
applicationAdapterHttpUpdate(ApplicationAdapterHttp this, void * subject)
{
HttpWorker worker = (HttpWorker)subject;
unsigned long sid = getSessionId(worker->current_request->cookies);
if (0 == strcmp("POST", worker->current_request->method)) {
if (0 == strcmp("/login/", worker->current_request->path)) {
loginAdapter(this->application, worker);
return;
}
}
if (0 == strcmp("GET", worker->current_request->method)) {
if (0 == strcmp("/sessinfo/", worker->current_request->path)) {
worker->current_response =
(HttpMessage)httpResponseSession(
applicationSessionGet(sid));
return;
}
if (0 == strcmp("/sess/", worker->current_request->path)) {
if (NO_SESSION_SID == sid) {
sid = applicationSessionStart(application);
}
worker->current_response =
(HttpMessage)httpResponseSession(
applicationSessionGet(sid));
return;
}
if (0 == strcmp("/randval/", worker->current_request->path)) {
if (NO_SESSION_SID != sid) {
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:

54
src/application/application.c

@ -0,0 +1,54 @@
/**
* \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/>.
*/
#define _GNU_SOURCE
#include <stdarg.h>
#include "class.h"
#include "application/application.h"
#include "utils/memory.h"
static
int
applicationCtor(void * _this, va_list * params)
{
Application this = _this;
this->val = va_arg(*params, struct randval *);
this->auth = va_arg(* params, void *);
return 0;
}
static
void
applicationDtor(void * _this)
{
}
INIT_IFACE(Class, applicationCtor, applicationDtor);
CREATE_CLASS(Application, NULL, IFACE(Class));
// vim: set ts=4 sw=4:

64
src/http/worker.c

@ -38,6 +38,8 @@
#include "http/writer.h"
#include "utils/memory.h"
#include "interface/subject.h"
#include "interface/observer.h"
static
int
@ -50,8 +52,6 @@ httpWorkerCtor(void * _this, va_list * params)
this->id = memMalloc(strlen(id) + 1);
strcpy(this->id, id);
this->val = va_arg(*params, struct randval *);
this->asset_pool = new(Hash);
sprintf(cbuf_id, "%s_%s", "parser", id);
@ -60,20 +60,9 @@ httpWorkerCtor(void * _this, va_list * params)
this->parser = new(HttpParser, this->pbuf);
this->writer = new(HttpWriter);
this->sroot = &(this->session);
this->auth = va_arg(* params, void *);
return 0;
}
static
inline
void
tDelete(void * node)
{
delete(node);
}
static
void
httpWorkerDtor(void * _this)
@ -88,7 +77,6 @@ httpWorkerDtor(void * _this)
if (NULL != this->pbuf) {
delete(this->asset_pool);
delete(this->pbuf); //!< cloned workers have NULL, so delete won't do anything
tdestroy(*(this->sroot), tDelete);
}
}
@ -99,9 +87,8 @@ httpWorkerClone(void * _this, void * _base)
HttpWorker this = _this;
HttpWorker base = _base;
this->val = base->val;
this->asset_pool = base->asset_pool;
this->application_adapter = base->application_adapter;
this->parser = new(HttpParser, base->pbuf);
/*
@ -124,22 +111,59 @@ httpWorkerClone(void * _this, void * _base)
* it is.
*/
this->writer = new(HttpWriter);
this->sroot = &(base->session);
this->auth = base->auth;
}
ssize_t httpWorkerProcess(void *, Stream);
ssize_t httpWorkerWrite(void *, Stream);
static
void
httpWorkerDetach(void * _this, void * adapter)
{
HttpWorker this = (HttpWorker)_this;
if (NULL != this->application_adapter) {
delete(this->application_adapter);
}
}
static
void
httpWorkerAttach(void * _this, void * adapter)
{
HttpWorker this = (HttpWorker)_this;
/*
* right now only one adapter is allowed and the last
* added will be used....all others will be deleted in
* assumption that no other handle does exist anymore
* (because it was added as an adapter and thus is good
* for nothing else.)
*/
httpWorkerDetach(_this, adapter);
this->application_adapter = adapter;
}
static
void
httpWorkerNotify(void * _this)
{
HttpWorker this = (HttpWorker)_this;
observerUpdate(this->application_adapter, _this);
}
INIT_IFACE(Class, httpWorkerCtor, httpWorkerDtor, httpWorkerClone);
INIT_IFACE(StreamReader, httpWorkerProcess);
INIT_IFACE(StreamWriter, httpWorkerWrite);
INIT_IFACE(Subject, httpWorkerAttach, httpWorkerDetach, httpWorkerNotify);
CREATE_CLASS(
HttpWorker,
NULL,
IFACE(Class),
IFACE(StreamReader),
IFACE(StreamWriter));
IFACE(StreamWriter),
IFACE(Subject));
// vim: set ts=4 sw=4:

20
src/http/worker/add_common_header.c

@ -26,7 +26,7 @@
#include "http/message.h"
#include "http/header.h"
#include "http/response.h"
#include "http/worker.h"
#include "hash.h"
@ -35,35 +35,35 @@
void
httpWorkerAddCommonHeader(HttpMessage request, HttpMessage response)
httpWorkerAddCommonHeader(HttpWorker this)
{
char buffer[200];
size_t nbuf;
if (httpMessageHasKeepAlive(request)) {
hashAdd(response->header,
if (httpMessageHasKeepAlive((HttpMessage)this->current_request)) {
hashAdd(this->current_response->header,
new(HttpHeader, CSTRA("Connection"), CSTRA("Keep-Alive")));
}
else {
hashAdd(response->header,
hashAdd(this->current_response->header,
new(HttpHeader, CSTRA("Connection"), CSTRA("Close")));
}
hashAdd(response->header,
hashAdd(this->current_response->header,
new(HttpHeader, CSTRA("Server"), CSTRA("testserver")));
switch(((HttpResponse)response)->status) {
switch(((HttpResponse)this->current_response)->status) {
case 304:
break;
default:
nbuf = sprintf(buffer, "%d", response->nbody);
hashAdd(response->header,
nbuf = sprintf(buffer, "%d", this->current_response->nbody);
hashAdd(this->current_response->header,
new(HttpHeader, CSTRA("Content-Length"), buffer, nbuf));
}
nbuf = rfc1123GmtNow(buffer, sizeof(buffer));
hashAdd(response->header,
hashAdd(this->current_response->header,
new(HttpHeader, CSTRA("Date"), buffer, nbuf));
}

7
src/http/worker/get_asset.c

@ -32,10 +32,7 @@
#include "hash.h"
HttpMessage
httpWorkerGetAsset(
HttpWorker this,
HttpRequest request,
const char * fname)
httpWorkerGetAsset(HttpWorker this, const char * fname)
{
char * match;
size_t nmatch;
@ -45,7 +42,7 @@ httpWorkerGetAsset(
size_t nfname = strlen(fname);
header = hashGet(
((HttpMessage)request)->header,
((HttpMessage)this->current_request)->header,
CSTRA("If-None-Match"));
if (NULL == header) {

148
src/http/worker/process.c

@ -46,9 +46,8 @@
#include "commons.h"
HttpMessage httpWorkerGetAsset(HttpWorker, HttpRequest, const char *);
void httpWorkerAddCommonHeader(HttpMessage, HttpMessage);
char * httpWorkerGetMimeType(HttpWorker, const char * extension);
HttpMessage httpWorkerGetAsset(HttpWorker, const char *);
void httpWorkerAddCommonHeader(HttpWorker);
ssize_t
@ -62,123 +61,23 @@ httpWorkerProcess(HttpWorker this, Stream st)
if (0 < requests) {
while (! queueEmpty(this->parser->queue)) {
HttpRequest request = queueGet(this->parser->queue);
HttpMessage response = NULL;
this->current_request = queueGet(this->parser->queue);
this->current_response = NULL;
/**
* \todo store the cookie count in the request to make a simple
* check possible to prevent this lookup if no cookies exists
* at all
/*
* let our observers...application (or better their
* http adapter) try to create an answer.
*/
if (NULL == this->session) {
HashValue sidstr = hashGet(request->cookies, CSTRA("sid"));
if (NULL != sidstr) {
unsigned long sid;
sid = strtoul((char*)(sidstr->value), NULL, 10);
this->session = sessionGet(this->sroot, sid);
}
}
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);
}
}
subjectNotify(this);
if (0 == strcmp("POST", request->method)) {
if (0 == strcmp("/login/", request->path)) {
char buffer[200];
size_t nbuf;
HashValue username = hashGet(request->post, CSTRA("username"));
HashValue password = hashGet(request->post, CSTRA("password"));
/**
* \todo This is an application authorization not an HTTP
* authorization...anyway think about sending HTTP 401
* messages if authorization is required and think about
* sending the credentials via header as described in the
* HTTP protocol. Most likely this will lead to hacky thing
* with javascript as i am not sure how far this is implemented
* within browsers.
* Anyway, for now we simply ignore a failed login within the
* response except that no session is initialized. We send
* an empty 200 OK
if (0 == strcmp("POST", this->current_request->method)) {
/*
* we can't do post requests on our own...
*/
if (NULL == password || NULL == username) {
response = new(HttpResponse, "HTTP/1.1", 403, "Forbidden");
this->current_response = (HttpMessage)httpResponse500();
}
if (NULL == response) {
Credential cred = new(Credential,
CRED_PASSWORD,
(char*)(username->value), username->nvalue,
(char*)(password->value), password->nvalue);
if (!authenticate(this->auth, cred)) {
response = new(HttpResponse, "HTTP/1.1", 403, "Forbidden");
} else {
if (NULL == this->session) {
this->session = sessionAdd(
this->sroot,
new(Session,
username->value,
username->nvalue));
} else {
this->session->username = memMalloc(username->nvalue + 1);
this->session->username[username->nvalue] = 0;
memcpy(this->session->username,
username->value,
username->nvalue);
}
nbuf = sprintf(buffer,
"sid=%lu;Path=/",
this->session->id);
response = (HttpMessage)httpResponseSession(
this->session);
hashAdd(response->header,
new(HttpHeader,
CSTRA("Set-Cookie"),
buffer, nbuf));
}
delete(cred);
}
}
}
if (0 == strcmp("GET", request->method)) {
if (0 == strcmp("/sessinfo/", request->path)) {
response = (HttpMessage)httpResponseSession(this->session);
}
else if (0 == strcmp("/sess/", request->path)) {
if (NULL == this->session) {
this->session = sessionAdd(
this->sroot,
new(Session, NULL, 0));
}
response = (HttpMessage)httpResponseSession(this->session);
}
else if (0 == strcmp("/randval/", request->path)) {
if (NULL != this->session) {
response = (HttpMessage)httpResponseRandval(
this->val->timestamp,
this->val->value);
} else {
response = (HttpMessage)httpResponse403();
}
}
else {
if (0 == strcmp("GET", this->current_request->method)) {
char html_asset[2048] = "./assets/html";
char base_asset[2048] = "./assets";
char main_asset[] = "/main.html";
@ -187,10 +86,10 @@ httpWorkerProcess(HttpWorker this, Stream st)
char * asset;
char * mime_type;
if (0 == strcmp("/", request->path)) {
if (0 == strcmp("/", this->current_request->path)) {
asset = main_asset;
} else {
asset = request->path;
asset = this->current_request->path;
}
mime_type = strrchr(asset, '.');
@ -205,19 +104,18 @@ httpWorkerProcess(HttpWorker this, Stream st)
}
strcat(asset_path, asset);
response = httpWorkerGetAsset(this, request, asset_path);
}
this->current_response =
httpWorkerGetAsset(this, asset_path);
}
if (NULL == response) {
response = (HttpMessage)httpResponse404();
if (NULL == this->current_response) {
this->current_response = (HttpMessage)httpResponse404();
}
httpWorkerAddCommonHeader((HttpMessage)request, response);
delete(request);
queuePut(this->writer->queue, response);
response = NULL;
httpWorkerAddCommonHeader(this);
delete(this->current_request);
queuePut(this->writer->queue, this->current_response);
this->current_response = NULL;
}
}

4
src/interface/observer.c

@ -29,9 +29,9 @@ const struct interface i_Observer = {
};
void
observerNotify(void * observer, void * subject)
observerUpdate(void * observer, void * subject)
{
CALL(observer, Observer, notify, subject);
CALL(observer, Observer, update, subject);
}
// vim: set ts=4 sw=4:

10
src/taskrambler.c

@ -135,6 +135,8 @@ main()
default:
{
AuthLdap auth;
//Application application;
//ApplicationAdapterHttp adapterHttp;
HttpWorker worker;
Server server;
@ -146,9 +148,13 @@ main()
logger = new(LoggerSyslog, LOGGER_DEBUG);
auth = new(AuthLdap,
"ldap://localhost/",
"ldap://hosted/",
CSTRA("ou=user,dc=yabrog,dc=weird-web-workers,dc=org"));
worker = new(HttpWorker, "testserver", value, auth);
worker = new(HttpWorker, "testserver");
application = new(Application, value, auth);
adapterHttp = new(ApplicationAdapterHttp, application);
subjectAttach(worker, adapterHttp);
server = new(Server, logger, worker, 11212, SOMAXCONN);
if (NULL != server) {

Loading…
Cancel
Save