From a1350d7591c7a62046df6146727944ed16e78030 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Wed, 23 Oct 2013 00:11:16 +0100 Subject: [PATCH] added a generic router. This is a REST router that maps urls to specific functions which it tries to find via dlsym. That way the only thing to do to get a new REST functionality is to add a function that fits into the namesheme. All existing functionality is moved accordingly --- assets/js/init.js | 14 +- configure.ac | 1 + include/application/adapter/http.h | 2 + include/http/request.h | 17 +- include/router.h | 59 +++++ src/Makefile.am | 11 +- src/application/Makefile.am | 9 +- src/application/adapter/http/http.c | 2 + src/application/adapter/http/update.c | 245 +----------------- .../controller/authenticate/create.c | 75 ++++++ .../controller/authenticate/delete.c | 44 ++++ src/application/controller/currentuser/read.c | 58 +++++ src/application/controller/randval/read.c | 63 +++++ src/application/controller/sessinfo/read.c | 59 +++++ src/application/controller/user/create.c | 98 +++++++ src/application/controller/version/read.c | 49 ++++ src/http/Makefile.am | 2 +- src/http/request.c | 12 + .../{has_valid_method.c => get_method_id.c} | 15 +- src/router/Makefile.am | 11 + src/router/route.c | 181 +++++++++++++ src/router/router.c | 66 +++++ src/taskrambler.c | 5 +- 23 files changed, 841 insertions(+), 257 deletions(-) create mode 100644 include/router.h create mode 100644 src/application/controller/authenticate/create.c create mode 100644 src/application/controller/authenticate/delete.c create mode 100644 src/application/controller/currentuser/read.c create mode 100644 src/application/controller/randval/read.c create mode 100644 src/application/controller/sessinfo/read.c create mode 100644 src/application/controller/user/create.c create mode 100644 src/application/controller/version/read.c rename src/http/request/{has_valid_method.c => get_method_id.c} (88%) create mode 100644 src/router/Makefile.am create mode 100644 src/router/route.c create mode 100644 src/router/router.c diff --git a/assets/js/init.js b/assets/js/init.js index 41bfe47..b072d9f 100644 --- a/assets/js/init.js +++ b/assets/js/init.js @@ -46,21 +46,27 @@ $(document).ready(function() { ); $.getJSON("/sessinfo/", $.proxy(sess.loadJSON, sess)); - $.getJSON("/user/get/", $.proxy(sess.loadUserJSON, sess)); + $.getJSON("/currentuser/", $.proxy(sess.loadUserJSON, sess)); $(window).focus(function() { $.getJSON("/sessinfo/", $.proxy(sess.loadJSON, sess)); }); $("div#menu ul li.logout").click(function() { - $.getJSON("/logout/", $.proxy(sess.loadUserJSON, sess)); + $.ajax({ + dataType: "json", + url: "/authenticate/", + type: 'DELETE', + success: $.proxy(sess.loadUserJSON, sess) + }); + //$.getJSON("/authenticate/", $.proxy(sess.loadUserJSON, sess)); $.getJSON("/sessinfo/", $.proxy(sess.loadJSON, sess)); }); $("#login").load("/_login.html", function (){ $("#login form").submit(function(event) { event.preventDefault(); - $.post("/login/", + $.post("/authenticate/", $("#login form").serialize(), $.proxy(sess.loadUserJSON, sess)); $("#login").addClass("hide"); @@ -71,7 +77,7 @@ $(document).ready(function() { $("#signup").load("/_signup.html", function (){ $("#signup form").submit(function(event) { event.preventDefault(); - $.post("/signup/", + $.post("/user/", $("#signup form").serialize(), $.proxy(sess.loadUserJSON, sess)); $("#signup").addClass("hide"); diff --git a/configure.ac b/configure.ac index d3687b9..0cee415 100644 --- a/configure.ac +++ b/configure.ac @@ -97,6 +97,7 @@ AC_CONFIG_FILES([Makefile src/storage/Makefile src/user/Makefile src/config/Makefile + src/router/Makefile docs/Makefile config/Makefile tests/Makefile]) diff --git a/include/application/adapter/http.h b/include/application/adapter/http.h index 2708080..956a06e 100644 --- a/include/application/adapter/http.h +++ b/include/application/adapter/http.h @@ -24,11 +24,13 @@ #define __APPLICATION_ADAPTER_HTTP_H__ #include "class.h" +#include "router.h" #include "application/application.h" CLASS(ApplicationAdapterHttp) { Application application; + Router router; }; #endif // __APPLICATION_ADAPTER_HTTP_H__ diff --git a/include/http/request.h b/include/http/request.h index 45eac76..8455495 100644 --- a/include/http/request.h +++ b/include/http/request.h @@ -30,7 +30,18 @@ #define N_HTTP_METHOD 8 -char * http_method[N_HTTP_METHOD]; +extern char * http_method[N_HTTP_METHOD]; + +typedef enum e_HttpMethod { + HTTP_OPTIONS = 0, + HTTP_GET, + HTTP_HEAD, + HTTP_POST, + HTTP_PUT, + HTTP_DELETE, + HTTP_TRACE, + HTTP_CONNECT +} HttpMethod; CLASS(HttpRequest) { EXTENDS(HttpMessage); @@ -39,12 +50,14 @@ CLASS(HttpRequest) { char * uri; char * path; + HttpMethod method_id; + Hash get; Hash post; Hash cookies; }; -int httpRequestHasValidMethod(HttpRequest); +HttpMethod httpRequestGetMethodId(HttpRequest); #endif // __HTTP_REQUEST_H__ diff --git a/include/router.h b/include/router.h new file mode 100644 index 0000000..644af94 --- /dev/null +++ b/include/router.h @@ -0,0 +1,59 @@ +/** + * \file + * A generic REST router that is able to map a URL to a specific + * function. It uses dlsym to get the address of the function to + * be called. + * The functions need to have a common interface for sure....This will + * work out while I am working on this. + * After a function is found it's address will be stored in a hash + * so that further lookups might be faster. + * By it's nature I think this is part of the HttpApplicationAdapter. + * + * \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 . + */ + +#ifndef __ROUTER_H__ +#define __ROUTER_H__ + +#include + +#include "class.h" +#include "hash.h" +#include "session.h" +#include "http/request.h" +#include "http/response.h" +#include "application/application.h" + +typedef char * (* fptr_routable)(Application, Session, Hash); + +CLASS(Router) { + Hash functions; + Application application; + + void * handle; + char * prefix; + size_t nprefix; + +}; + +HttpResponse routerRoute(Router, HttpRequest, Session); + +#endif // __ROUTER_H__ + +// vim: set ts=4 sw=4: diff --git a/src/Makefile.am b/src/Makefile.am index bc1f50e..1159b5e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -27,13 +27,14 @@ TRHTTPSERVER = http/libhttp.la \ TR = ./application/.libs/libapplication.a \ ./user/.libs/libuser.a \ - ./storage/.libs/libstorage.a \ ./auth/.libs/libauth.a \ + ./storage/.libs/libstorage.a \ ./session/.libs/libsession.a \ - ./config/.libs/libconfig.a + ./config/.libs/libconfig.a \ + ./router/.libs/librouter.a TRLIBS = -ltrutils -ltrhttpserver -ltrbase -USEDLIBS = -lrt -lssl -lldap -lgdbm -luuid +USEDLIBS = -lrt -lssl -lldap -lgdbm -luuid -ldl AM_CFLAGS += -I../include/ @@ -55,7 +56,9 @@ libtrhttpserver_la_LIBADD = $(TRHTTPSERVER) taskrambler_SOURCES = taskrambler.c $(IFACE) $(UTILS) taskrambler_CFLAGS = $(AM_CFLAGS) taskrambler_LDADD = $(TRLIBS) $(TR) $(USEDLIBS) +taskrambler_LDFLAGS = -Wl,--export-dynamic \ + -Wl,--whole-archive,./application/.libs/libapplication.a,--no-whole-archive SUBDIRS = asset auth cbuf class hash queue http \ logger server session socket stream tree application \ - storage user config + storage user config router diff --git a/src/application/Makefile.am b/src/application/Makefile.am index af6f02c..09cb56f 100644 --- a/src/application/Makefile.am +++ b/src/application/Makefile.am @@ -11,10 +11,17 @@ APPLICATION = application.c \ session_cleanup.c ADAPTERHTTP = adapter/http/http.c \ adapter/http/update.c +CONTROLLER = controller/authenticate/create.c \ + controller/authenticate/delete.c \ + controller/currentuser/read.c \ + controller/randval/read.c \ + controller/sessinfo/read.c \ + controller/user/create.c \ + controller/version/read.c AM_CFLAGS += -I../../include/ noinst_LTLIBRARIES = libapplication.la -libapplication_la_SOURCES = $(APPLICATION) $(ADAPTERHTTP) +libapplication_la_SOURCES = $(APPLICATION) $(ADAPTERHTTP) $(CONTROLLER) libapplication_la_CFLAGS = $(AM_CFLAGS) diff --git a/src/application/adapter/http/http.c b/src/application/adapter/http/http.c index 3dfdda3..ef6ddf4 100644 --- a/src/application/adapter/http/http.c +++ b/src/application/adapter/http/http.c @@ -25,6 +25,7 @@ #include #include "class.h" +#include "router.h" #include "application/application.h" #include "application/adapter/http.h" @@ -38,6 +39,7 @@ applicationAdapterHttpCtor(void * _this, va_list * params) ApplicationAdapterHttp this = _this; this->application = va_arg(*params, Application); + this->router = va_arg(*params, Router); return 0; } diff --git a/src/application/adapter/http/update.c b/src/application/adapter/http/update.c index bb23915..4d2bc0d 100644 --- a/src/application/adapter/http/update.c +++ b/src/application/adapter/http/update.c @@ -22,32 +22,19 @@ #define _GNU_SOURCE -#include #include -#include #include -#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" - +#include "http/message.h" +#include "router.h" #define NO_SESSION_SID NULL -#define RANDVAL_JSON "{\"ctime\":%ld,\"vnext\":%ld,\"value\":\"%02d\"}" -#define SESSION_JSON "{\"id\":\"%s\",\"timeout\":%d,\"timeleft\":%ld}" -#define USER_JSON \ - "{\"email\":\"%s\",\"firstname\":\"%s\",\"surname\":\"%s\"}" -#define VERSION_JSON "{\"version\":\"%s\"}" - static inline char * @@ -62,170 +49,6 @@ getSessionId(Hash cookies) return NO_SESSION_SID; } -HttpMessage -responseVersion(const char * version) -{ - char buffer[200]; - size_t nbuf; - - nbuf = sprintf(buffer, VERSION_JSON, version? version : ""); - return (HttpMessage)httpResponseJson(buffer, nbuf); -} - -HttpMessage -responseRandval(struct randval * val) -{ - char buffer[200]; - size_t nbuf; - time_t remaining; - - remaining = 10 - (time(NULL) - val->timestamp); - - nbuf = sprintf( - buffer, - RANDVAL_JSON, - val->timestamp, - remaining, - val->value); - - return (HttpMessage)httpResponseJson(buffer, nbuf); -} - -HttpMessage -responseSession(Session session) -{ - char buffer[200]; - size_t nbuf; - - nbuf = sprintf(buffer, SESSION_JSON, - (NULL != session)? session->id : "", - (NULL != session)? SESSION_LIVETIME : 0, - (NULL != session)? session->livetime - time(NULL) : 0); - - return (HttpMessage)httpResponseJson(buffer, nbuf); -} - -HttpMessage -responseUser(User user) -{ - char buffer[200]; - size_t nbuf; - - nbuf = sprintf(buffer, USER_JSON, - (NULL != user)? user->email : "", - (NULL != user)? user->firstname : "", - (NULL != user)? user->surname : ""); - - return (HttpMessage)httpResponseJson(buffer, nbuf); -} - -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) { - username = hashGet( - worker->current_request->post, - CSTRA("email")); - } - - if (NULL == username || NULL == password) { - worker->current_response = (HttpMessage)httpResponse403(); - return; - } - - credential = new(Credential, - CRED_PASSWORD, - (char *)(username->value), username->nvalue, - (char *)(password->value), password->nvalue); - - if (! applicationLogin(application, credential, session)) { - worker->current_response = (HttpMessage)httpResponse403(); - } else { - worker->current_response = responseUser(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) { @@ -253,66 +76,10 @@ applicationAdapterHttpUpdate(void * _this, void * subject) 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("/version/", worker->current_request->path)) { - worker->current_response = - responseVersion(this->application->version); - return; - } - - if (0 == strcmp("/user/get/", worker->current_request->path)) { - worker->current_response = responseUser(session->user); - return; - } - - if (0 == strcmp("/logout/", worker->current_request->path)) { - applicationLogout(this->application, session); - - worker->current_response = responseUser(session->user); - return; - } - - if (0 == strcmp("/sessinfo/", worker->current_request->path)) { - worker->current_response = responseSession(session); - return; - } - - if (0 == strcmp("/randval/", worker->current_request->path)) { - if (NULL != session->user) { - worker->current_response = - responseRandval(this->application->val); - return; - } else { - worker->current_response = (HttpMessage)httpResponse403(); - } - } - } - - // if (0 < session->livetime - now) { - // nbuf = sprintf(buf, SESSION_JSON, - // session->id, - // SESSION_LIVETIME, - // session->livetime - now); - - // queuePut( - // worker->additional_headers, - // new(HttpHeader, CSTRA("X-TaskramblerSession"), buf, nbuf)); - - // } else { - // nbuf = sprintf(buf, "sid=%s;Path=/;Max-Age=-3600", session->id); - // } + worker->current_response = (HttpMessage)routerRoute( + this->router, + worker->current_request, + session); } // vim: set ts=4 sw=4: diff --git a/src/application/controller/authenticate/create.c b/src/application/controller/authenticate/create.c new file mode 100644 index 0000000..3f09f70 --- /dev/null +++ b/src/application/controller/authenticate/create.c @@ -0,0 +1,75 @@ +/** + * \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 . + */ + +#define _GNU_SOURCE + +#include "class.h" +#include "application/application.h" +#include "session.h" +#include "hash.h" +#include "auth/credential.h" +#include "user.h" + +#include "utils/memory.h" + +char * controllerCurrentuserRead(Application, Session, Hash); + +char * +controllerAuthenticateCreate( + Application application, + Session session, + Hash args) +{ + HashValue username; + HashValue password; + Credential credential; + + char * response_data; + + username = hashGet(args, CSTRA("username")); + password = hashGet(args, CSTRA("password")); + + if (NULL == username) { + username = hashGet(args, CSTRA("email")); + } + + if (NULL == username || NULL == password) { + return NULL; + } + + credential = new(Credential, + CRED_PASSWORD, + (char *)(username->value), username->nvalue, + (char *)(password->value), password->nvalue); + + if (! applicationLogin(application, credential, session)) { + response_data = NULL; + } else { + response_data = controllerCurrentuserRead(application, session, NULL); + } + + delete(credential); + + return response_data; +} + +// vim: set ts=4 sw=4: diff --git a/src/application/controller/authenticate/delete.c b/src/application/controller/authenticate/delete.c new file mode 100644 index 0000000..85e15ed --- /dev/null +++ b/src/application/controller/authenticate/delete.c @@ -0,0 +1,44 @@ +/** + * \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 . + */ + +#define _GNU_SOURCE + +#include "class.h" +#include "application/application.h" +#include "session.h" +#include "hash.h" + +#include "utils/memory.h" + +char * controllerCurrentuserRead(Application, Session, Hash); + +char * +controllerAuthenticateDelete( + Application application, + Session session, + Hash args) +{ + applicationLogout(application, session); + return controllerCurrentuserRead(application, session, NULL); +} + +// vim: set ts=4 sw=4: diff --git a/src/application/controller/currentuser/read.c b/src/application/controller/currentuser/read.c new file mode 100644 index 0000000..90e676f --- /dev/null +++ b/src/application/controller/currentuser/read.c @@ -0,0 +1,58 @@ +/** + * \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 . + */ + +#define _GNU_SOURCE + +#include +#include + +#include "class.h" +#include "application/application.h" +#include "session.h" +#include "hash.h" + +#include "utils/memory.h" + + +#define USER_JSON \ + "{\"email\":\"%s\",\"firstname\":\"%s\",\"surname\":\"%s\"}" + +char * +controllerCurrentuserRead(Application app, Session sess, Hash args) +{ + char * buffer; + size_t nbuffer; + + nbuffer = snprintf(NULL, 0, USER_JSON, + (NULL != sess->user)? sess->user->email : "", + (NULL != sess->user)? sess->user->firstname : "", + (NULL != sess->user)? sess->user->surname : ""); + buffer = memMalloc(nbuffer); + nbuffer = sprintf(buffer, USER_JSON, + (NULL != sess->user)? sess->user->email : "", + (NULL != sess->user)? sess->user->firstname : "", + (NULL != sess->user)? sess->user->surname : ""); + + return buffer; +} + +// vim: set ts=4 sw=4: diff --git a/src/application/controller/randval/read.c b/src/application/controller/randval/read.c new file mode 100644 index 0000000..3c6dab7 --- /dev/null +++ b/src/application/controller/randval/read.c @@ -0,0 +1,63 @@ +/** + * \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 . + */ + +#define _GNU_SOURCE + +#include +#include + +#include "application/application.h" +#include "session.h" +#include "hash.h" + +#include "utils/memory.h" + +#define RANDVAL_JSON "{\"ctime\":%ld,\"vnext\":%ld,\"value\":\"%02d\"}" + +char * +controllerRandvalRead(Application app, Session sess, Hash args) +{ + char * buffer; + size_t nbuffer; + time_t remaining; + + remaining = 10 - (time(NULL) - app->val->timestamp); + + nbuffer = snprintf( + NULL, + 0, + RANDVAL_JSON, + app->val->timestamp, + remaining, + app->val->value); + buffer = memMalloc(nbuffer); + sprintf( + buffer, + RANDVAL_JSON, + app->val->timestamp, + remaining, + app->val->value); + + return buffer; +} + +// vim: set ts=4 sw=4: diff --git a/src/application/controller/sessinfo/read.c b/src/application/controller/sessinfo/read.c new file mode 100644 index 0000000..02b9df0 --- /dev/null +++ b/src/application/controller/sessinfo/read.c @@ -0,0 +1,59 @@ +/** + * \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 . + */ + +#define _GNU_SOURCE + +#include +#include + +#include "application/application.h" +#include "session.h" +#include "hash.h" + +#include "utils/memory.h" + +#define SESSION_JSON "{\"id\":\"%s\",\"timeout\":%d,\"timeleft\":%ld}" + + +char * +controllerSessinfoRead( + Application application, + Session session, + Hash args) +{ + char * buffer; + size_t nbuffer; + + nbuffer = snprintf(NULL, 0, SESSION_JSON, + (NULL != session)? session->id : "", + (NULL != session)? SESSION_LIVETIME : 0, + (NULL != session)? session->livetime - time(NULL) : 0); + buffer = memMalloc(nbuffer); + sprintf(buffer, SESSION_JSON, + (NULL != session)? session->id : "", + (NULL != session)? SESSION_LIVETIME : 0, + (NULL != session)? session->livetime - time(NULL) : 0); + + return buffer; +} + +// vim: set ts=4 sw=4: diff --git a/src/application/controller/user/create.c b/src/application/controller/user/create.c new file mode 100644 index 0000000..81bcf41 --- /dev/null +++ b/src/application/controller/user/create.c @@ -0,0 +1,98 @@ +/** + * \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 . + */ + +#define _GNU_SOURCE + +#include "application/application.h" +#include "session.h" +#include "hash.h" +#include "auth/credential.h" +#include "user.h" + +#include "utils/memory.h" + +char * controllerCurrentuserRead(Application, Session, Hash); + +char * +controllerUserCreate( + Application application, + Session session, + Hash args) +{ + HashValue email; + HashValue password; + HashValue pwrepeat; + HashValue firstname; + HashValue surname; + + Credential credential; + User user; + + char * response_data; + + email = hashGet(args, CSTRA("email")); + password = hashGet(args, CSTRA("password")); + pwrepeat = hashGet(args, CSTRA("pwrepeat")); + firstname = hashGet(args, CSTRA("firstname")); + surname = hashGet(args, CSTRA("surname")); + + if ( + NULL == email || + NULL == password || + NULL == pwrepeat || + NULL == firstname || + NULL == surname) + { + return NULL; + } + + if ( + password->nvalue != pwrepeat->nvalue || + 0 != memcmp(password->value, pwrepeat->value, password->nvalue)) + { + return NULL; + } + + 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)) { + response_data = NULL; + } else { + applicationLogin(application, credential, session); + response_data = controllerCurrentuserRead(application, session, NULL); + } + + delete(credential); + delete(user); + + return response_data; +} + +// vim: set ts=4 sw=4: diff --git a/src/application/controller/version/read.c b/src/application/controller/version/read.c new file mode 100644 index 0000000..ed2d6c9 --- /dev/null +++ b/src/application/controller/version/read.c @@ -0,0 +1,49 @@ +/** + * \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 . + */ + +#define _GNU_SOURCE + +#include +#include + +#include "application/application.h" +#include "hash.h" +#include "session.h" + +#include "utils/memory.h" + +#define VERSION_JSON "{\"version\":\"%s\"}" + +char * +controllerVersionRead(Application app, Session sess, Hash args) +{ + char * buffer; + size_t nbuffer; + + nbuffer = snprintf(NULL, 0, VERSION_JSON, app->version? app->version : ""); + buffer = memMalloc(nbuffer); + sprintf(buffer, VERSION_JSON, app->version? app->version : ""); + + return buffer; +} + +// vim: set ts=4 sw=4: diff --git a/src/http/Makefile.am b/src/http/Makefile.am index 8cc182d..b682010 100644 --- a/src/http/Makefile.am +++ b/src/http/Makefile.am @@ -8,7 +8,7 @@ MSG = message.c \ message/get_version.c \ message/has_valid_version.c REQ = request.c \ - request/has_valid_method.c + request/get_method_id.c RESP = response.c \ response/304.c \ response/404.c \ diff --git a/src/http/request.c b/src/http/request.c index 3054632..b97f999 100644 --- a/src/http/request.c +++ b/src/http/request.c @@ -56,6 +56,18 @@ httpRequestCtor(void * _this, va_list * params) this->uri[ulen] = 0; memcpy(this->uri, uri, ulen); + this->method_id = httpRequestGetMethodId(this); + + if (-1 == this->method_id) { + MEM_FREE(this->uri); + MEM_FREE(this->method); + MEM_FREE(this->path); /** \todo looks like path is not used at all */ + + PARENTCALL(_this, Class, dtor); + + return -1; + } + this->get = new(Hash); this->post = new(Hash); this->cookies = new(Hash); diff --git a/src/http/request/has_valid_method.c b/src/http/request/get_method_id.c similarity index 88% rename from src/http/request/has_valid_method.c rename to src/http/request/get_method_id.c index c44dcc3..1e15d92 100644 --- a/src/http/request/has_valid_method.c +++ b/src/http/request/get_method_id.c @@ -32,22 +32,27 @@ char * http_method[N_HTTP_METHOD] = { "PUT", "DELETE", "TRACE", - "CONNECT"}; + "CONNECT" +}; -int -httpRequestHasValidMethod(HttpRequest this) +HttpMethod +httpRequestGetMethodId(HttpRequest this) { int i; if (NULL == this->method) - return 0; + return -1; for (i=0; imethod)) break; } - return (i != N_HTTP_METHOD); + if (i >= N_HTTP_METHOD) { + return -1; + } + + return (i); } // vim: set ts=4 sw=4: diff --git a/src/router/Makefile.am b/src/router/Makefile.am new file mode 100644 index 0000000..4854fbd --- /dev/null +++ b/src/router/Makefile.am @@ -0,0 +1,11 @@ +ACLOCAL_AMFLAGS = -I m4 +AUTOMAKE_OPTIONS = subdir-objects + +ROUTER = router.c route.c + +AM_CFLAGS += -I../../include/ + +noinst_LTLIBRARIES = librouter.la + +librouter_la_SOURCES = $(ROUTER) +librouter_la_CFLAGS = $(AM_CFLAGS) diff --git a/src/router/route.c b/src/router/route.c new file mode 100644 index 0000000..5a6e2c0 --- /dev/null +++ b/src/router/route.c @@ -0,0 +1,181 @@ +/** + * \file + * This is the generic application router.... + * Here RBAC can take place as every resource is always requested + * via an HTTP request. + * + * \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 . + */ + +// for strchr and others. +#include + +// for size_t +#include + +// for dlopen, dlsym +#include + +// for toupper +#include + +#include "router.h" +#include "hash.h" +#include "session.h" +#include "http/request.h" +#include "http/response.h" +#include "application/application.h" + +#include "utils/memory.h" +#include "commons.h" + + +#define COMMAND_LEN 128 + + +HttpResponse +routerRoute( + Router this, + HttpRequest request, + Session sess) +{ + char functionName[COMMAND_LEN + this->nprefix * 10]; + Hash args = NULL; + fptr_routable function; + + char * tmp; + char * command; + size_t ncommand; + char * response_data; + HttpResponse response; + + if ('/' != request->uri[0]) { + /* + * we only support absolute paths within our + * application + */ + return NULL; + } + + command = &(request->uri[1]); + command[0] = toupper(command[0]); + + /* + * find end of command + */ + tmp = strchr(command, '/'); + if (NULL == tmp) { + ncommand = strlen(command); + } else { + ncommand = tmp - command; + } + + memcpy(functionName, this->prefix, this->nprefix); + memcpy(&(functionName[this->nprefix]), + command, MIN(COMMAND_LEN, ncommand)); + + /** + * \todo + * now get all arguments if we have some + */ + + /* + * following the crud pattern we map the first part + * of the uri and the request method to according + * function names. + */ + switch (request->method_id) { + case HTTP_GET: + args = new(Hash); + strcpy(&(functionName[this->nprefix + ncommand]), "Read"); + break; + + case HTTP_POST: + args = request->post; + strcpy(&(functionName[this->nprefix + ncommand]), "Create"); + break; + + case HTTP_PUT: + strcpy(&(functionName[this->nprefix + ncommand]), "Update"); + break; + + case HTTP_DELETE: + strcpy(&(functionName[this->nprefix + ncommand]), "Delete"); + break; + + default: + /* other methods are not subject of REST */ + return NULL; + } + + /* + * \todo for the moment I don't cache the found symbol... + * I don't even check if there was an error...the only thing + * I do is checking a NULL symbol and in that case don't + * handle the request here. + */ + dlerror(); + function = dlsym(this->handle, functionName); + + /** + * \todo somewhere here or above access control have to take place + */ + + if (NULL == function) { + /** + * nothing there to handle the request ... so leave it to the + * caller... + */ + char * error; + + if (NULL != (error = dlerror())) { + /** + * \todo add logging...maybe. + */ + } + + return NULL; + } + + /* + * function has to allocate the memory for reponse_date by using + * memMalloc. + */ + response_data = function(this->application, sess, args); + + switch (request->method_id) { + case HTTP_GET: + delete(args); + break; + + case HTTP_POST: + case HTTP_PUT: + case HTTP_DELETE: + default: + /* other methods are not subject of REST */ + break; + } + + response = httpResponseJson(response_data, strlen(response_data)); + MEM_FREE(response_data); + + return response; +} + +// vim: set ts=4 sw=4: diff --git a/src/router/router.c b/src/router/router.c new file mode 100644 index 0000000..8305c87 --- /dev/null +++ b/src/router/router.c @@ -0,0 +1,66 @@ +/** + * \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 . + */ + +#include + +// for dlopen, dlsym +#include + +#include "class.h" +#include "router.h" +#include "hash.h" +#include "application/application.h" + +#define PREFIX "controller" + +static +int +routerCtor(void * _this, va_list * params) +{ + Router this = _this; + + this->application = va_arg(*params, Application); + this->functions = new(Hash); + this->handle = dlopen(NULL, RTLD_LAZY); + this->prefix = PREFIX; + this->nprefix = sizeof(PREFIX) - 1; + + if (NULL == this->handle) { + return -1; + } + + return 0; +} + +static +void +routerDtor(void * _this) { + Router this = _this; + + delete(this->functions); + dlclose(this->handle); +} + +INIT_IFACE(Class, routerCtor, routerDtor, NULL); +CREATE_CLASS(Router, NULL, IFACE(Class)); + +// vim: set ts=4 sw=4: diff --git a/src/taskrambler.c b/src/taskrambler.c index 7f588d9..1565916 100644 --- a/src/taskrambler.c +++ b/src/taskrambler.c @@ -165,6 +165,7 @@ main() AuthLdap authLdap; AuthStorage authStorage; Application application; + Router router; ApplicationAdapterHttp adapterHttp; HttpWorker worker; Server server; @@ -210,7 +211,8 @@ main() authLdap, authStorage); - adapterHttp = new(ApplicationAdapterHttp, application); + router = new(Router, application); + adapterHttp = new(ApplicationAdapterHttp, application, router); worker = new(HttpWorker, "taskrambler"); subjectAttach(worker, adapterHttp); @@ -267,6 +269,7 @@ main() delete(server); delete(worker); delete(adapterHttp); + delete(router); delete(application); delete(authStorage); delete(passwords);