Commit a0ec357e0a1299a30285622b206e70477ec64ee4

Authored by Georg Hopp
1 parent 0c3d467b

closes #11: first very crude session handling implementation, no persitence no m…

…emory cleanups, spread over to much files TODO: clean this
... ... @@ -43,7 +43,9 @@ HttpResponse httpResponse304(
43 43 const char *, size_t,
44 44 const char *, size_t);
45 45 HttpResponse httpResponse404();
  46 +HttpResponse httpResponse403();
46 47 HttpResponse httpResponseMe();
  48 +HttpResponse httpResponseLoginForm();
47 49 HttpResponse httpResponseRandval(time_t, int);
48 50 HttpResponse httpResponseAsset(
49 51 const char *,
... ...
... ... @@ -31,6 +31,7 @@
31 31 #include "http/parser.h"
32 32 #include "http/writer.h"
33 33 #include "cbuf.h"
  34 +#include "session.h"
34 35
35 36
36 37 #ifndef TRUE
... ... @@ -56,6 +57,8 @@ CLASS(HttpWorker) {
56 57
57 58 HttpParser parser;
58 59 HttpWriter writer;
  60 + Session session;
  61 + Session * sroot;
59 62 };
60 63
61 64 #endif // __HTTP_WORKER_H__
... ...
  1 +/**
  2 + * \file
  3 + *
  4 + * \author Georg Hopp
  5 + *
  6 + * \copyright
  7 + * Copyright (C) 2012 Georg Hopp
  8 + *
  9 + * This program is free software: you can redistribute it and/or modify
  10 + * it under the terms of the GNU General Public License as published by
  11 + * the Free Software Foundation, either version 3 of the License, or
  12 + * (at your option) any later version.
  13 + *
  14 + * This program is distributed in the hope that it will be useful,
  15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17 + * GNU General Public License for more details.
  18 + *
  19 + * You should have received a copy of the GNU General Public License
  20 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21 + */
  22 +
  23 +#ifndef __SESSION_H__
  24 +#define __SESSION_H__
  25 +
  26 +#include <time.h>
  27 +#include <sys/types.h>
  28 +
  29 +#include "class.h"
  30 +
  31 +#define SESSION_LIVETIME 30
  32 +
  33 +
  34 +CLASS(Session) {
  35 + unsigned long id;
  36 + time_t livetime;
  37 +
  38 + char * username;
  39 +};
  40 +
  41 +Session sessionAdd(const Session *, Session);
  42 +Session sessionGet(const Session *, const unsigned long id);
  43 +void sessionDelete(const Session *, const unsigned long id);
  44 +
  45 +#endif // __SESSION_H__
  46 +
  47 +// vim: set ts=4 sw=4:
... ...
... ... @@ -26,6 +26,8 @@ REQ = http/request.c \
26 26 RESP = http/response.c \
27 27 http/response/304.c \
28 28 http/response/404.c \
  29 + http/response/403.c \
  30 + http/response/login_form.c \
29 31 http/response/asset.c \
30 32 http/response/me.c \
31 33 http/response/randval.c
... ... @@ -43,6 +45,7 @@ WORKER = http/worker.c \
43 45 http/worker/add_common_header.c
44 46 HEADER = http/header.c http/header/get.c http/header/add.c \
45 47 http/header/to_string.c
  48 +SESSION = session.c session/add.c session/get.c session/delete.c
46 49 UTILS = utils/hash.c \
47 50 utils/memory.c \
48 51 utils/http.c \
... ... @@ -57,6 +60,6 @@ bin_PROGRAMS = testserver
57 60 testserver_SOURCES = testserver.c \
58 61 $(IFACE) $(SOCKET) $(SERVER) $(LOGGER) $(MSG) $(REQ) \
59 62 $(WRITER) $(RESP) $(HEADER) $(PARSER) $(WORKER) $(CB) \
60   - $(UTILS) $(MSGQ)
  63 + $(UTILS) $(MSGQ) $(SESSION)
61 64 testserver_CFLAGS = -Wall -I ../include/
62 65 testserver_LDFLAGS = -lrt
... ...
  1 +/**
  2 + * \file
  3 + *
  4 + * \author Georg Hopp
  5 + *
  6 + * \copyright
  7 + * Copyright (C) 2012 Georg Hopp
  8 + *
  9 + * This program is free software: you can redistribute it and/or modify
  10 + * it under the terms of the GNU General Public License as published by
  11 + * the Free Software Foundation, either version 3 of the License, or
  12 + * (at your option) any later version.
  13 + *
  14 + * This program is distributed in the hope that it will be useful,
  15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17 + * GNU General Public License for more details.
  18 + *
  19 + * You should have received a copy of the GNU General Public License
  20 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21 + */
  22 +
  23 +#include <stdlib.h>
  24 +#include <string.h>
  25 +#include <stdio.h>
  26 +#include <sys/types.h>
  27 +
  28 +#include "class.h"
  29 +#include "interface/class.h"
  30 +
  31 +#include "http/response.h"
  32 +#include "http/message.h"
  33 +#include "http/header.h"
  34 +
  35 +
  36 +HttpResponse
  37 +httpResponse403()
  38 +{
  39 + HttpResponse response;
  40 + HttpMessage message;
  41 + char buffer[200];
  42 + size_t nbuf;
  43 +
  44 + response = new(HttpResponse, "HTTP/1.1", 403, "Forbidden");
  45 + message = (HttpMessage)response;
  46 +
  47 + message->type = HTTP_MESSAGE_BUFFERED;
  48 + message->nbody = 0;
  49 + message->body = NULL;
  50 +
  51 + nbuf = sprintf(buffer, "%d", message->nbody);
  52 +
  53 + httpHeaderAdd(&(message->header),
  54 + new(HttpHeader,
  55 + "Content-Length",
  56 + sizeof("Content-Length")-1,
  57 + buffer,
  58 + nbuf));
  59 +
  60 + return response;
  61 +}
  62 +
  63 +// vim: set ts=4 sw=4:
... ...
  1 +/**
  2 + * \file
  3 + *
  4 + * \author Georg Hopp
  5 + *
  6 + * \copyright
  7 + * Copyright (C) 2012 Georg Hopp
  8 + *
  9 + * This program is free software: you can redistribute it and/or modify
  10 + * it under the terms of the GNU General Public License as published by
  11 + * the Free Software Foundation, either version 3 of the License, or
  12 + * (at your option) any later version.
  13 + *
  14 + * This program is distributed in the hope that it will be useful,
  15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17 + * GNU General Public License for more details.
  18 + *
  19 + * You should have received a copy of the GNU General Public License
  20 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21 + */
  22 +
  23 +#include <stdlib.h>
  24 +#include <string.h>
  25 +#include <stdio.h>
  26 +#include <time.h>
  27 +#include <sys/types.h>
  28 +
  29 +#include "class.h"
  30 +#include "interface/class.h"
  31 +
  32 +#include "http/response.h"
  33 +#include "http/message.h"
  34 +#include "http/header.h"
  35 +
  36 +#define RESP_DATA "<form action=\"/me/\" method=\"POST\">" \
  37 + "<input name=\"username\" type=\"text\" />" \
  38 + "<input type=\"submit\">" \
  39 +"</form>"
  40 +
  41 +HttpResponse
  42 +httpResponseLoginForm()
  43 +{
  44 + char buffer[200];
  45 + HttpResponse response;
  46 + HttpMessage message;
  47 + size_t nbuf;
  48 +
  49 + response = new(HttpResponse, "HTTP/1.1", 200, "OK");
  50 + message = (HttpMessage)response;
  51 +
  52 + httpHeaderAdd(&(message->header),
  53 + new(HttpHeader,
  54 + "Content-Type",
  55 + sizeof("Content-Type")-1,
  56 + "text/html",
  57 + sizeof("text/html")-1));
  58 +
  59 + message->type = HTTP_MESSAGE_BUFFERED;
  60 +
  61 + message->nbody = sizeof(RESP_DATA)-1;
  62 + message->body = malloc(message->nbody);
  63 + memcpy(message->body, RESP_DATA, message->nbody);
  64 +
  65 + nbuf = sprintf(buffer, "%d", message->nbody);
  66 +
  67 + httpHeaderAdd(&(message->header),
  68 + new(HttpHeader,
  69 + "Content-Length",
  70 + sizeof("Content-Length")-1,
  71 + buffer,
  72 + nbuf));
  73 +
  74 + return response;
  75 +}
  76 +
  77 +// vim: set ts=4 sw=4:
... ...
... ... @@ -60,15 +60,31 @@
60 60 "$(document).ready(function() {" \
61 61 "var intervalId;" \
62 62 "var vnext = 0;" \
  63 + "var clickclose = function() {" \
  64 + "clearInterval(intervalId);" \
  65 + "vnext = 0;" \
  66 + "$(\"#randval\").addClass(\"hide\");" \
  67 + "};" \
63 68 "var counter = function() {" \
64 69 "if (0 >= vnext) {" \
65   - "$.getJSON(\"/randval/\", function(data) {" \
  70 + "$.getJSON(\"/randval/\", function(data, xhr) {" \
66 71 "var date = new Date(data.ctime * 1000);" \
67 72 "$(\"#ctime\").empty().append(date.toString());" \
68 73 "vnext = data.vnext;" \
69 74 "$(\"#value\").empty().append(data.value);" \
70 75 "$(\"#vnext\").empty().append(vnext);" \
  76 + "$(\"#randval\").on(\"click\", clickclose);" \
  77 + "}).error(function(event, request, settings) {" \
  78 + "clearInterval(intervalId);" \
  79 + "$.get(\"/login/\", function(data) {" \
  80 + "$(\"#randval\")" \
  81 + ".off(\"click\", clickclose)" \
  82 + ".empty().append(data);" \
  83 + "});" \
71 84 "});" \
  85 + "if ($(\"#randval\").hasClass(\"hide\")) {" \
  86 + "$(\"#randval\").removeClass(\"hide\");" \
  87 + "}" \
72 88 "} else {" \
73 89 "vnext--;" \
74 90 "$(\"#vnext\").empty().append(vnext);" \
... ... @@ -83,12 +99,6 @@
83 99 "});" \
84 100 "$(\"a\").click(function() {" \
85 101 "intervalId = setInterval(counter, 1000);" \
86   - "$(\"#randval\").removeClass(\"hide\");" \
87   - "});" \
88   - "$(\"#randval\").click(function() {" \
89   - "clearInterval(intervalId);" \
90   - "vnext = 0;" \
91   - "$(\"#randval\").addClass(\"hide\");" \
92 102 "});" \
93 103 "});" \
94 104 "</script>" \
... ... @@ -103,6 +113,7 @@
103 113 "</div>" \
104 114 "<div id=\"main\">" \
105 115 "<h1>Testpage</h1>" \
  116 + "Welcome %s<br />" \
106 117 "<img src=\"/image/\" />" \
107 118 "<br /><a href=\"#\">Link</a>" \
108 119 "</div>" \
... ... @@ -111,7 +122,7 @@
111 122 "</html>"
112 123
113 124 HttpResponse
114   -httpResponseMe()
  125 +httpResponseMe(char * uname)
115 126 {
116 127 char buffer[200];
117 128 HttpResponse response;
... ... @@ -141,9 +152,10 @@ httpResponseMe()
141 152 sizeof("profession=\"coder\"")-1));
142 153
143 154 message->type = HTTP_MESSAGE_BUFFERED;
144   - message->nbody = sizeof(RESP_DATA)-1;
145   - message->body = malloc(sizeof(RESP_DATA)-1);
146   - memcpy(message->body, RESP_DATA, sizeof(RESP_DATA)-1);
  155 + message->nbody = sizeof(RESP_DATA)-1-2+strlen(uname); //!< the two are the %s
  156 + message->body = malloc(message->nbody+1);
  157 + sprintf(message->body, RESP_DATA, uname);
  158 + //memcpy(message->body, RESP_DATA, sizeof(RESP_DATA)-1);
147 159
148 160 nbuf = sprintf(buffer, "%d", message->nbody);
149 161
... ...
1   -#include <stdlib.h>
  1 +/**
  2 + * \file
  3 + *
  4 + * \author Georg Hopp
  5 + *
  6 + * \copyright
  7 + * Copyright (C) 2012 Georg Hopp
  8 + *
  9 + * This program is free software: you can redistribute it and/or modify
  10 + * it under the terms of the GNU General Public License as published by
  11 + * the Free Software Foundation, either version 3 of the License, or
  12 + * (at your option) any later version.
  13 + *
  14 + * This program is distributed in the hope that it will be useful,
  15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17 + * GNU General Public License for more details.
  18 + *
  19 + * You should have received a copy of the GNU General Public License
  20 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21 + */
  22 +
  23 +#define _GNU_SOURCE
  24 +
2 25 #include <stdarg.h>
3 26 #include <stdlib.h>
4 27 #include <string.h>
5 28 #include <stdio.h>
  29 +#include <search.h>
6 30
7 31 #include "class.h"
8 32 #include "http/worker.h"
... ... @@ -37,10 +61,20 @@ httpWorkerCtor(void * _this, va_list * params)
37 61 this->parser = new(HttpParser, this->pbuf);
38 62 this->writer = new(HttpWriter, this->wbuf);
39 63
  64 + this->sroot = &(this->session);
  65 +
40 66 return 0;
41 67 }
42 68
43 69 static
  70 +inline
  71 +void
  72 +tDelete(void * node)
  73 +{
  74 + delete(node);
  75 +}
  76 +
  77 +static
44 78 void
45 79 httpWorkerDtor(void * _this)
46 80 {
... ... @@ -51,8 +85,11 @@ httpWorkerDtor(void * _this)
51 85 delete(this->parser);
52 86 delete(this->writer);
53 87
54   - delete(this->pbuf); //!< cloned workers have NULL, so delete won't do anything
55   - delete(this->wbuf); //!< cloned workers have NULL, so delete won't do anything
  88 + if (NULL != this->pbuf) {
  89 + delete(this->pbuf); //!< cloned workers have NULL, so delete won't do anything
  90 + delete(this->wbuf); //!< cloned workers have NULL, so delete won't do anything
  91 + tdestroy(*(this->sroot), tDelete);
  92 + }
56 93 }
57 94
58 95 static
... ... @@ -66,6 +103,8 @@ httpWorkerClone(void * _this, void * _base)
66 103
67 104 this->parser = new(HttpParser, base->pbuf);
68 105 this->writer = new(HttpWriter, base->wbuf);
  106 +
  107 + this->sroot = &(base->session);
69 108 }
70 109
71 110 ssize_t httpWorkerProcess(void *, int);
... ...
... ... @@ -21,6 +21,9 @@
21 21 */
22 22
23 23 #include <sys/types.h>
  24 +#include <stdio.h>
  25 +#include <stdlib.h>
  26 +#include <time.h>
24 27
25 28 #include "class.h"
26 29 #include "interface/class.h"
... ... @@ -31,6 +34,7 @@
31 34 #include "http/response.h"
32 35 #include "http/message/queue.h"
33 36 #include "http/parser.h"
  37 +#include "session.h"
34 38
35 39 HttpMessage httpWorkerGetAsset(HttpRequest, const char *, const char *, size_t);
36 40 void httpWorkerAddCommonHeader(HttpMessage, HttpMessage);
... ... @@ -49,19 +53,91 @@ httpWorkerProcess(HttpWorker this, int fd)
49 53 HttpMessageQueue respq = this->writer->queue;
50 54
51 55 for (i=0; i<reqq->nmsgs; i++) {
  56 + HttpMessage rmessage = reqq->msgs[i];
52 57 HttpRequest request = (HttpRequest)(reqq->msgs[i]);
53 58 HttpMessage response = NULL;
  59 + HttpHeader cookie = httpHeaderGet(
  60 + &(rmessage->header),
  61 + "cookie",
  62 + sizeof("Cookie")-1);
  63 +
  64 + if (NULL == this->session && NULL != cookie) {
  65 + int i;
  66 +
  67 + for (i=0; i<cookie->cvalue; i++) {
  68 + char * sidstr = strstr(cookie->value[i], "sid");
  69 +
  70 + if (NULL != sidstr) {
  71 + unsigned long sid;
  72 +
  73 + sidstr = strchr(sidstr, '=')+1;
  74 + sid = strtoul(sidstr, NULL, 10);
  75 +
  76 + this->session = sessionGet(this->sroot, sid);
  77 + break;
  78 + }
  79 + }
  80 + }
  81 +
  82 + if (NULL != this->session) {
  83 + if (time(NULL) < this->session->livetime) {
  84 + this->session->livetime = time(NULL) + SESSION_LIVETIME;
  85 + } else {
  86 + sessionDelete(this->sroot, this->session->id);
  87 + delete(this->session);
  88 + }
  89 + }
  90 +
  91 + if (0 == strcmp("POST", request->method)) {
  92 + if (0 == strcmp("/me/", request->uri)) {
  93 + char * delim = memchr(rmessage->body, '=', rmessage->nbody);
  94 + char * key = rmessage->body;
  95 + char * val;
  96 + size_t nkey, nval;
  97 + char buffer[200];
  98 + size_t nbuf;
  99 +
  100 + nkey = delim - rmessage->body - 1;
  101 + *delim = 0;
  102 + val = delim + 1;
  103 + nval = rmessage->nbody - (val - rmessage->body);
  104 +
  105 + this->session = sessionAdd(
  106 + this->sroot,
  107 + new(Session, val, nval));
  108 + nbuf = sprintf(buffer, "sid=%lu;Path=/", this->session->id);
  109 +
  110 + response = (HttpMessage)httpResponseMe(this->session->username);
  111 +
  112 + httpHeaderAdd(
  113 + &(response->header),
  114 + new(HttpHeader,
  115 + "Set-Cookie",
  116 + sizeof("Set-Cookie")-1,
  117 + buffer,
  118 + nbuf));
  119 + }
  120 + }
54 121
55 122 if (0 == strcmp("GET", request->method)) {
56 123
  124 + if (0 == strcmp("/login/", request->uri)) {
  125 + response = (HttpMessage)httpResponseLoginForm();
  126 + }
  127 +
57 128 if (0 == strcmp("/me/", request->uri)) {
58   - response = (HttpMessage)httpResponseMe();
  129 + char * uname = (NULL != this->session)? this->session->username : "";
  130 + response = (HttpMessage)httpResponseMe(uname);
59 131 }
60 132
61 133 if (0 == strcmp("/randval/", request->uri)) {
62   - response = (HttpMessage)httpResponseRandval(
63   - this->val->timestamp,
64   - this->val->value);
  134 + if (NULL != this->session) {
  135 + response = (HttpMessage)httpResponseRandval(
  136 + this->val->timestamp,
  137 + this->val->value);
  138 + } else {
  139 + response = (HttpMessage)httpResponse403();
  140 + }
65 141 }
66 142
67 143 if (0 == strcmp("/image/", request->uri)) {
... ...
  1 +#include <time.h>
  2 +#include <stdarg.h>
  3 +#include <stdlib.h>
  4 +#include <string.h>
  5 +#include <stdio.h>
  6 +#include <sys/types.h>
  7 +
  8 +#include "session.h"
  9 +#include "class.h"
  10 +#include "interface/class.h"
  11 +
  12 +#include "utils/hash.h"
  13 +#include "utils/memory.h"
  14 +
  15 +
  16 +static
  17 +int
  18 +sessionCtor(void * _this, va_list * params)
  19 +{
  20 + Session this = _this;
  21 + char * uname = va_arg(* params, char *);
  22 + size_t nuname = va_arg(* params, size_t);
  23 +
  24 + this->livetime = time(NULL) + SESSION_LIVETIME;
  25 + this->id = sdbm((unsigned char *)uname, nuname) & this->livetime;
  26 +
  27 + this->username = malloc(nuname + 1);
  28 + this->username[nuname] = 0;
  29 + memcpy(this->username, uname, nuname);
  30 +
  31 + return 0;
  32 +}
  33 +
  34 +static
  35 +void
  36 +sessionDtor(void * _this)
  37 +{
  38 + Session this = _this;
  39 +
  40 + FREE(this->username);
  41 +}
  42 +
  43 +INIT_IFACE(Class, sessionCtor, sessionDtor, NULL);
  44 +CREATE_CLASS(Session, NULL, IFACE(Class));
  45 +
  46 +// vim: set ts=4 sw=4:
... ...
  1 +#include <search.h>
  2 +
  3 +#include "session.h"
  4 +#include "interface/class.h"
  5 +
  6 +
  7 +static
  8 +inline
  9 +int
  10 +sessionAddComp(const void * _a, const void * _b)
  11 +{
  12 + Session a = (Session)_a;
  13 + Session b = (Session)_b;
  14 + return (a->id < b->id)? -1 : (a->id > b->id)? 1 : 0;
  15 +}
  16 +
  17 +Session
  18 +sessionAdd(const Session * root, Session session)
  19 +{
  20 + Session * found = tsearch(session, (void**)root, sessionAddComp);
  21 +
  22 + if (NULL == found) {
  23 + return NULL;
  24 + }
  25 +
  26 + if (*found != session) {
  27 + /**
  28 + * \todo this should not happen, so do some logging here.
  29 + */
  30 + delete(session);
  31 + }
  32 +
  33 + return *found;
  34 +}
  35 +
  36 +// vim: set ts=4 sw=4:
... ...
  1 +#include <search.h>
  2 +
  3 +#include "session.h"
  4 +#include "interface/class.h"
  5 +
  6 +
  7 +static
  8 +inline
  9 +int
  10 +sessionDeleteComp(const void * _a, const void * _b)
  11 +{
  12 + unsigned long a = *(unsigned long *)_a;
  13 + Session b = (Session)_b;
  14 + return (a < b->id)? -1 : (a > b->id)? 1 : 0;
  15 +}
  16 +
  17 +void
  18 +sessionDelete(const Session * root, const unsigned long id)
  19 +{
  20 + tdelete(&id, (void**)root, sessionDeleteComp);
  21 +}
  22 +
  23 +// vim: set ts=4 sw=4:
... ...
  1 +#include <search.h>
  2 +#include <time.h>
  3 +
  4 +#include "session.h"
  5 +
  6 +
  7 +static
  8 +inline
  9 +int
  10 +sessionGetComp(const void * _a, const void * _b)
  11 +{
  12 + unsigned long a = *(unsigned long *)_a;
  13 + Session b = (Session)_b;
  14 + return (a < b->id)? -1 : (a > b->id)? 1 : 0;
  15 +}
  16 +
  17 +Session
  18 +sessionGet(const Session * root, const unsigned long id)
  19 +{
  20 + Session * found = tfind(&id, (void**)root, sessionGetComp);
  21 +
  22 + if (NULL == found) {
  23 + return NULL;
  24 + }
  25 +
  26 + return *found;
  27 +}
  28 +
  29 +// vim: set ts=4 sw=4:
... ...
Please register or login to post a comment