aqhome: more work on http server.
This commit is contained in:
@@ -38,7 +38,12 @@
|
||||
aqhomestorage_p.h
|
||||
aqhomestorage.h
|
||||
init.h
|
||||
http.h
|
||||
init_http.h
|
||||
fini.h
|
||||
loop.h
|
||||
loop_http.h
|
||||
u_login.h
|
||||
u_rooms.h
|
||||
aqhomehttp.h
|
||||
aqhomehttp_p.h
|
||||
</headers>
|
||||
@@ -48,7 +53,12 @@
|
||||
|
||||
aqhomestorage.c
|
||||
init.c
|
||||
http.c
|
||||
init_http.c
|
||||
fini.c
|
||||
loop.c
|
||||
loop_http.c
|
||||
u_login.c
|
||||
u_rooms.c
|
||||
main.c
|
||||
aqhomehttp.c
|
||||
</sources>
|
||||
|
||||
@@ -32,10 +32,6 @@ GWEN_INHERIT(AQH_SERVICE, AQHOME_HTTP)
|
||||
*/
|
||||
|
||||
static void GWENHYWFAR_CB _freeData(void *bp, void *p);
|
||||
static int _handleUrl(AQH_SERVICE *sv, AQH_HTTP_REQUEST *rq);
|
||||
static int _handleUrl_login(AQH_SERVICE *sv, AQH_HTTP_REQUEST *rq);
|
||||
static GWEN_MSG *_createResponseMsg(AQH_SERVICE *sv, int code, const char *text, const char *protocol, const char *page);
|
||||
static void _writeDefaultResponseHeaderToBuffer(AQH_SERVICE *sv, int contentLength, GWEN_BUFFER *buf);
|
||||
|
||||
|
||||
|
||||
@@ -51,7 +47,8 @@ void AqHomeHttpService_Extend(AQH_SERVICE *sv)
|
||||
GWEN_NEW_OBJECT(AQHOME_HTTP, xsv);
|
||||
GWEN_INHERIT_SETDATA(AQH_SERVICE, AQHOME_HTTP, sv, xsv, _freeData);
|
||||
|
||||
AQH_HttpService_SetHandleRequestFn(sv, _handleUrl);
|
||||
xsv->contentTree=AQH_HttpContent_new("root");
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -62,122 +59,15 @@ void _freeData(void *bp, void *p)
|
||||
|
||||
xsv=(AQHOME_HTTP*) p;
|
||||
|
||||
AQH_Storage_free(xsv->storage);
|
||||
xsv->storage=NULL;
|
||||
GWEN_MsgEndpoint_free(xsv->rootEndpoint);
|
||||
xsv->rootEndpoint=NULL;
|
||||
xsv->ipcdEndpoint=NULL;
|
||||
xsv->mqttEndpoint=NULL;
|
||||
xsv->httpdEndpoint=NULL;
|
||||
GWEN_DB_Group_free(xsv->dbArgs);
|
||||
xsv->dbArgs=NULL;
|
||||
free(xsv->pidFile);
|
||||
AQH_HttpContent_free(xsv->contentTree);
|
||||
xsv->contentTree=NULL;
|
||||
|
||||
GWEN_FREE_OBJECT(xsv);
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_DB_NODE *AqHomeHttpService_GetDbArgs(const AQH_SERVICE *sv)
|
||||
{
|
||||
if (sv) {
|
||||
AQHOME_HTTP *xsv;
|
||||
|
||||
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
|
||||
if (xsv)
|
||||
return xsv->dbArgs;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *AqHomeHttpService_GetPidFile(const AQH_SERVICE *sv)
|
||||
{
|
||||
if (sv) {
|
||||
AQHOME_HTTP *xsv;
|
||||
|
||||
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
|
||||
if (xsv)
|
||||
return xsv->pidFile;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeHttpService_SetPidFile(AQH_SERVICE *sv, const char *s)
|
||||
{
|
||||
if (sv) {
|
||||
AQHOME_HTTP *xsv;
|
||||
|
||||
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
|
||||
if (xsv) {
|
||||
free(xsv->pidFile);
|
||||
xsv->pidFile=s?strdup(s):NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
GWEN_MSG_ENDPOINT *AqHomeHttpService_GetRootEndpoint(const AQH_SERVICE *sv)
|
||||
{
|
||||
if (sv) {
|
||||
AQHOME_HTTP *xsv;
|
||||
|
||||
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
|
||||
if (xsv)
|
||||
return xsv->rootEndpoint;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_MSG_ENDPOINT *AqHomeHttpService_GetIpcdEndpoint(const AQH_SERVICE *sv)
|
||||
{
|
||||
if (sv) {
|
||||
AQHOME_HTTP *xsv;
|
||||
|
||||
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
|
||||
if (xsv)
|
||||
return xsv->ipcdEndpoint;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_MSG_ENDPOINT *AqHomeHttpService_GetMqttEndpoint(const AQH_SERVICE *sv)
|
||||
{
|
||||
if (sv) {
|
||||
AQHOME_HTTP *xsv;
|
||||
|
||||
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
|
||||
if (xsv)
|
||||
return xsv->mqttEndpoint;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_MSG_ENDPOINT *AqHomeHttpService_GetHttpdEndpoint(const AQH_SERVICE *sv)
|
||||
{
|
||||
if (sv) {
|
||||
AQHOME_HTTP *xsv;
|
||||
|
||||
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
|
||||
if (xsv)
|
||||
return xsv->httpdEndpoint;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_STORAGE *AqHomeHttpService_GetStorage(const AQH_SERVICE *sv)
|
||||
{
|
||||
if (sv) {
|
||||
@@ -192,72 +82,43 @@ AQH_STORAGE *AqHomeHttpService_GetStorage(const AQH_SERVICE *sv)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int _handleUrl(AQH_SERVICE *sv, AQH_HTTP_REQUEST *rq)
|
||||
void AqHomeHttpService_SetStorage(AQH_SERVICE *sv, AQH_STORAGE *sto)
|
||||
{
|
||||
if (sv) {
|
||||
AQHOME_HTTP *xsv;
|
||||
|
||||
const GWEN_URL *url;
|
||||
const char *sPath;
|
||||
|
||||
url=AQH_HttpRequest_GetUrl(rq);
|
||||
|
||||
sPath=GWEN_Url_GetPath(url);
|
||||
if (strcasecmp(sPath, "/login")==0)
|
||||
return _handleUrl_login(sv, rq);
|
||||
else {
|
||||
DBG_ERROR(NULL, "Invalid URL [%s]", sPath);
|
||||
return GWEN_ERROR_INVALID;
|
||||
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
|
||||
if (xsv)
|
||||
xsv->storage=sto;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _handleUrl_login(AQH_SERVICE *sv, AQH_HTTP_REQUEST *rq)
|
||||
AQH_HTTP_CONTENT *AqHomeHttpService_GetContentTree(const AQH_SERVICE *sv)
|
||||
{
|
||||
const char *protocol;
|
||||
const char *cmd;
|
||||
AQH_SESSION *session;
|
||||
GWEN_MSG *msgOut=NULL;
|
||||
if (sv) {
|
||||
AQHOME_HTTP *xsv;
|
||||
|
||||
protocol=AQH_HttpRequest_GetProtocol(rq);
|
||||
session=AQH_HttpRequest_GetSession(rq);
|
||||
cmd=AQH_HttpRequest_GetCommand(rq);
|
||||
if (cmd && strcasecmp(cmd, "GET")==0) {
|
||||
GWEN_BUFFER *pageBuf;
|
||||
const char *s;
|
||||
int rv;
|
||||
|
||||
pageBuf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
s=AQH_HttpService_GetSiteHeader(sv);
|
||||
if (s)
|
||||
GWEN_Buffer_AppendString(pageBuf, s);
|
||||
|
||||
rv=AQH_HttpService_AddFile(sv, session, "login.html", pageBuf);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error reading file \"login.html\"");
|
||||
GWEN_Buffer_free(pageBuf);
|
||||
msgOut=_createResponseMsg(sv, 500, "Internal Error", protocol, NULL);
|
||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
||||
return 0;
|
||||
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
|
||||
if (xsv)
|
||||
return xsv->contentTree;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s=AQH_HttpService_GetSiteFooter(sv);
|
||||
if (s)
|
||||
GWEN_Buffer_AppendString(pageBuf, s);
|
||||
|
||||
msgOut=_createResponseMsg(sv, 200, "OK", protocol, GWEN_Buffer_GetStart(pageBuf));
|
||||
GWEN_Buffer_free(pageBuf);
|
||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
||||
return 0;
|
||||
|
||||
void AqHomeHttpService_SetContentTree(AQH_SERVICE *sv, AQH_HTTP_CONTENT *c)
|
||||
{
|
||||
if (sv) {
|
||||
AQHOME_HTTP *xsv;
|
||||
|
||||
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
|
||||
if (xsv) {
|
||||
AQH_HttpContent_free(xsv->contentTree);
|
||||
xsv->contentTree=c;
|
||||
}
|
||||
else {
|
||||
msgOut=_createResponseMsg(sv, 501, "Not (yet) implemented", protocol, NULL);
|
||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,41 +127,5 @@ int _handleUrl_login(AQH_SERVICE *sv, AQH_HTTP_REQUEST *rq)
|
||||
|
||||
|
||||
|
||||
GWEN_MSG *_createResponseMsg(AQH_SERVICE *sv, int code, const char *text, const char *protocol, const char *page)
|
||||
{
|
||||
GWEN_BUFFER *buf;
|
||||
GWEN_MSG *msg;
|
||||
|
||||
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
AQH_HttpService_AddStatusLine(sv, code, text, protocol, buf);
|
||||
_writeDefaultResponseHeaderToBuffer(sv, (page && *page)?strlen(page):0, buf);
|
||||
if (page && *page)
|
||||
GWEN_Buffer_AppendString(buf, page);
|
||||
|
||||
msg=GWEN_Msg_fromBytes((const uint8_t*)GWEN_Buffer_GetStart(buf), GWEN_Buffer_GetUsedBytes(buf));
|
||||
GWEN_Buffer_free(buf);
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _writeDefaultResponseHeaderToBuffer(AQH_SERVICE *sv, int contentLength, GWEN_BUFFER *buf)
|
||||
{
|
||||
GWEN_DB_NODE *db;
|
||||
|
||||
db=GWEN_DB_Group_new("header");
|
||||
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Connection", "Keep-Alive");
|
||||
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Content-Type", "text/html; charset=utf-8");
|
||||
GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Content-Length", contentLength);
|
||||
|
||||
AQH_HttpService_AddHeader(sv, db, buf);
|
||||
GWEN_DB_Group_free(db);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -12,26 +12,42 @@
|
||||
|
||||
#include "aqhome/service/service.h"
|
||||
#include "aqhome/data/storage.h"
|
||||
#include "aqhome/http/content.h"
|
||||
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
|
||||
|
||||
#define AQHOME_HTTP_PERMS_LIST_ROOMS 0x00000001
|
||||
#define AQHOME_HTTP_PERMS_LIST_DEVICES 0x00000002
|
||||
#define AQHOME_HTTP_PERMS_LIST_VALUES 0x00000004
|
||||
#define AQHOME_HTTP_PERMS_LIST_TOPICS 0x00000008
|
||||
|
||||
#define AQHOME_HTTP_PERMS_ADD_ROOM 0x00000100
|
||||
#define AQHOME_HTTP_PERMS_ADD_DEVICE 0x00000200
|
||||
#define AQHOME_HTTP_PERMS_ADD_VALUE 0x00000400
|
||||
#define AQHOME_HTTP_PERMS_ADD_TOPIC 0x00000800
|
||||
|
||||
#define AQHOME_HTTP_PERMS_DEL_ROOM 0x00010000
|
||||
#define AQHOME_HTTP_PERMS_DEL_DEVICE 0x00020000
|
||||
#define AQHOME_HTTP_PERMS_DEL_VALUE 0x00040000
|
||||
#define AQHOME_HTTP_PERMS_DEL_TOPIC 0x00080000
|
||||
|
||||
#define AQHOME_HTTP_PERMS_EDIT_ROOM 0x01000000
|
||||
#define AQHOME_HTTP_PERMS_EDIT_DEVICE 0x02000000
|
||||
#define AQHOME_HTTP_PERMS_EDIT_VALUE 0x04000000
|
||||
#define AQHOME_HTTP_PERMS_EDIT_TOPIC 0x08000000
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void AqHomeHttpService_Extend(AQH_SERVICE *sv);
|
||||
|
||||
GWEN_MSG_ENDPOINT *AqHomeHttpService_GetRootEndpoint(const AQH_SERVICE *sv);
|
||||
GWEN_MSG_ENDPOINT *AqHomeHttpService_GetIpcdEndpoint(const AQH_SERVICE *sv);
|
||||
GWEN_MSG_ENDPOINT *AqHomeHttpService_GetMqttEndpoint(const AQH_SERVICE *sv);
|
||||
GWEN_MSG_ENDPOINT *AqHomeHttpService_GetHttpdEndpoint(const AQH_SERVICE *sv);
|
||||
|
||||
AQH_STORAGE *AqHomeHttpService_GetStorage(const AQH_SERVICE *sv);
|
||||
void AqHomeHttpService_SetStorage(AQH_SERVICE *sv, AQH_STORAGE *sto);
|
||||
|
||||
GWEN_DB_NODE *AqHomeHttpService_GetDbArgs(const AQH_SERVICE *sv);
|
||||
const char *AqHomeHttpService_GetPidFile(const AQH_SERVICE *sv);
|
||||
void AqHomeHttpService_SetPidFile(AQH_SERVICE *sv, const char *s);
|
||||
|
||||
|
||||
|
||||
|
||||
AQH_HTTP_CONTENT *AqHomeHttpService_GetContentTree(const AQH_SERVICE *sv);
|
||||
void AqHomeHttpService_SetContentTree(AQH_SERVICE *sv, AQH_HTTP_CONTENT *c);
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -15,17 +15,9 @@
|
||||
|
||||
typedef struct AQHOME_HTTP AQHOME_HTTP;
|
||||
struct AQHOME_HTTP {
|
||||
GWEN_MSG_ENDPOINT *rootEndpoint;
|
||||
AQH_STORAGE *storage; /* do not release */
|
||||
|
||||
GWEN_MSG_ENDPOINT *ipcdEndpoint;
|
||||
GWEN_MSG_ENDPOINT *mqttEndpoint;
|
||||
GWEN_MSG_ENDPOINT *httpdEndpoint;
|
||||
|
||||
AQH_STORAGE *storage;
|
||||
|
||||
GWEN_DB_NODE *dbArgs;
|
||||
|
||||
char *pidFile;
|
||||
AQH_HTTP_CONTENT *contentTree;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "aqhome/data/storage.h"
|
||||
#include "aqhome/service/session.h"
|
||||
#include "aqhome/http/httpservice.h"
|
||||
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
|
||||
|
||||
@@ -22,6 +22,11 @@
|
||||
#define AQHOME_STORAGE_DEFAULT_MQTT_KEEPALIVE 600
|
||||
#define AQHOME_STORAGE_DEFAULT_MQTT_PORT 1883
|
||||
|
||||
#define AQHOME_STORAGE_DEFAULT_CONFIGDIR "/var/lib/aqhomestorage/config"
|
||||
#define AQHOME_STORAGE_DEFAULT_HTTP_SOURCEDIR "/var/lib/aqhomestorage/html"
|
||||
|
||||
#define AQHOME_STORAGE_DEFAULT_STATEFILE "/var/lib/aqhomestorage/config/statefile"
|
||||
|
||||
#define AQHOME_STORAGE_SITEHEADER "site-header.html"
|
||||
#define AQHOME_STORAGE_SITEFOOTER "site-footer.html"
|
||||
|
||||
@@ -36,6 +41,7 @@ struct AQHOME_STORAGE {
|
||||
|
||||
GWEN_DB_NODE *dbArgs;
|
||||
|
||||
AQH_SERVICE *httpService;
|
||||
AQH_STORAGE *storage;
|
||||
|
||||
char *pidFile;
|
||||
|
||||
84
apps/aqhome-storage/fini.c
Normal file
84
apps/aqhome-storage/fini.c
Normal file
@@ -0,0 +1,84 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./fini.h"
|
||||
#include "./aqhomestorage_p.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/args.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint_tcpd.h>
|
||||
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _disconnectTree(GWEN_MSG_ENDPOINT *ep);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeStorage_Fini(AQHOME_STORAGE *aqh)
|
||||
{
|
||||
if (aqh) {
|
||||
if (aqh->rootEndpoint) {
|
||||
_disconnectTree(aqh->rootEndpoint);
|
||||
GWEN_MsgEndpoint_Disconnect(aqh->rootEndpoint);
|
||||
}
|
||||
GWEN_MsgEndpoint_free(aqh->rootEndpoint);
|
||||
aqh->rootEndpoint=NULL;
|
||||
aqh->ipcdEndpoint=NULL;
|
||||
aqh->httpdEndpoint=NULL;
|
||||
aqh->mqttEndpoint=NULL;
|
||||
|
||||
if (aqh->pidFile)
|
||||
remove(aqh->pidFile);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _disconnectTree(GWEN_MSG_ENDPOINT *ep)
|
||||
{
|
||||
GWEN_MSG_ENDPOINT *epChild;
|
||||
|
||||
epChild=GWEN_MsgEndpoint_Tree2_GetFirstChild(ep);
|
||||
while(epChild) {
|
||||
_disconnectTree(epChild);
|
||||
epChild=GWEN_MsgEndpoint_Tree2_GetNext(epChild);
|
||||
} /* while */
|
||||
|
||||
GWEN_MsgEndpoint_Disconnect(ep);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
23
apps/aqhome-storage/fini.h
Normal file
23
apps/aqhome-storage/fini.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_STORAGE_FINI_H
|
||||
#define AQHOME_STORAGE_FINI_H
|
||||
|
||||
|
||||
#include "./aqhomestorage.h"
|
||||
|
||||
|
||||
|
||||
void AqHomeStorage_Fini(AQHOME_STORAGE *aqh);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,19 +1,3 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<!-- copyright (c) 2023 by martin -->
|
||||
<meta name="generator" content="FTE 1.1" />
|
||||
<meta name="revised" content="martin,2023-07-23" />
|
||||
<meta name="keywords" content="" />
|
||||
<meta name="description" content="" />
|
||||
<meta name="author" content="martin" />
|
||||
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
|
||||
<title>AqHome Storage Service</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_STORAGE_HTTP_H
|
||||
#define AQHOME_STORAGE_HTTP_H
|
||||
|
||||
|
||||
#include "./aqhomestorage.h"
|
||||
|
||||
|
||||
|
||||
int AqHomeStorage_AddFile(AQHOME_STORAGE *aqh, AQH_SESSION *session, const char *fname, GWEN_BUFFER *buf);
|
||||
int AqHomeStorage_AddSiteHeader(AQHOME_STORAGE *aqh, AQH_SESSION *session, GWEN_BUFFER *buf);
|
||||
int AqHomeStorage_AddSiteFooter(AQHOME_STORAGE *aqh, AQH_SESSION *session, GWEN_BUFFER *buf);
|
||||
|
||||
void AqHomeStorage_AddStatusLine(AQHOME_STORAGE *aqh, int code, const char *msg, const char *proto, GWEN_BUFFER *buf);
|
||||
void AqHomeStorage_AddHeader(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbHeader, GWEN_BUFFER *buf);
|
||||
|
||||
int AqHomeStorage_ParsePostBody(AQHOME_STORAGE *aqh, const GWEN_MSG *msgReceived, GWEN_DB_NODE *dbBody);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -12,18 +12,24 @@
|
||||
|
||||
|
||||
#include "./init.h"
|
||||
#include "./init_http.h"
|
||||
#include "./aqhomestorage_p.h"
|
||||
#include "./aqhomehttp.h"
|
||||
|
||||
#include "aqhome/msg/endpoint_tty.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/mqtt/endpoint_mqttc.h"
|
||||
#include "aqhome/http/endpoint_http.h"
|
||||
#include "aqhome/http/httpservice_conf.h"
|
||||
#include "aqhome/http/httpservice_http.h"
|
||||
#include "aqhome/http/httpservice.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/args.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint_tcpd.h>
|
||||
#include <gwenhywfar/endpoint_msgio.h>
|
||||
#include <gwenhywfar/directory.h>
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
@@ -57,14 +63,14 @@
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static int _setupFolders(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs);
|
||||
|
||||
static int _setupStorage(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs);
|
||||
|
||||
static void _setupIpc(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs);
|
||||
static void _setupMqtt(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs);
|
||||
static void _setupHttp(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs);
|
||||
|
||||
static GWEN_MSG_ENDPOINT *_acceptIpcFn(GWEN_MSG_ENDPOINT *ep, GWEN_SOCKET *sk, const GWEN_INETADDRESS *addr, void *data);
|
||||
static GWEN_MSG_ENDPOINT *_acceptHttpFn(GWEN_MSG_ENDPOINT *ep, GWEN_SOCKET *sk, const GWEN_INETADDRESS *addr, void *data);
|
||||
|
||||
static int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs);
|
||||
static int _createPidFile(const char *pidFilename);
|
||||
@@ -100,27 +106,103 @@ int AqHomeStorage_Init(AQHOME_STORAGE *aqh, int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
// _setupStorage(aqh, dbArgs);
|
||||
rv=_setupFolders(aqh, dbArgs);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv=_setupStorage(aqh, dbArgs);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
_setupIpc(aqh, dbArgs);
|
||||
_setupMqtt(aqh, dbArgs);
|
||||
_setupHttp(aqh, dbArgs);
|
||||
rv=AqHomeStorage_SetupHttp(aqh, dbArgs);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _setupFolders(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs)
|
||||
{
|
||||
const char *s;
|
||||
GWEN_BUFFER *nameBuf;
|
||||
int pos;
|
||||
int rv;
|
||||
|
||||
s=GWEN_DB_GetCharValue(dbArgs, "cfgdir", 0, AQHOME_STORAGE_DEFAULT_CONFIGDIR);
|
||||
if (!(s && *s)) {
|
||||
DBG_ERROR(NULL, "Missing configuration folder");
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
nameBuf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
GWEN_Buffer_AppendString(nameBuf, s);
|
||||
pos=GWEN_Buffer_GetPos(nameBuf);
|
||||
rv=GWEN_Directory_GetPath(GWEN_Buffer_GetStart(nameBuf), GWEN_PATH_FLAGS_CHECKROOT);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error accessing configuration folder \"%s\"", GWEN_Buffer_GetStart(nameBuf));
|
||||
GWEN_Buffer_free(nameBuf);
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
GWEN_Buffer_Crop(nameBuf, 0, pos);
|
||||
|
||||
GWEN_Buffer_AppendString(nameBuf, GWEN_DIR_SEPARATOR_S "modules");
|
||||
rv=GWEN_Directory_GetPath(GWEN_Buffer_GetStart(nameBuf), GWEN_PATH_FLAGS_CHECKROOT);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error accessing modules folder \"%s\"", GWEN_Buffer_GetStart(nameBuf));
|
||||
GWEN_Buffer_free(nameBuf);
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
GWEN_Buffer_Crop(nameBuf, 0, pos);
|
||||
|
||||
GWEN_Buffer_AppendString(nameBuf, GWEN_DIR_SEPARATOR_S "users");
|
||||
rv=GWEN_Directory_GetPath(GWEN_Buffer_GetStart(nameBuf), GWEN_PATH_FLAGS_CHECKROOT);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error accessing configuration folder \"%s\"", GWEN_Buffer_GetStart(nameBuf));
|
||||
GWEN_Buffer_free(nameBuf);
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
GWEN_Buffer_free(nameBuf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int _setupStorage(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs)
|
||||
{
|
||||
AQH_STORAGE *sto;
|
||||
const char *stateFile;
|
||||
|
||||
stateFile=GWEN_DB_GetCharValue(dbArgs, "stateFile", 0, NULL);
|
||||
if (stateFile && *stateFile) {
|
||||
AQH_STORAGE *sto;
|
||||
int rv;
|
||||
|
||||
sto=AQH_Storage_new();
|
||||
AQH_Storage_SetStateFile(sto, stateFile);
|
||||
|
||||
rv=AQH_Storage_Init(sto);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
AQH_Storage_free(sto);
|
||||
return rv;
|
||||
}
|
||||
aqh->storage=sto;
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "No state file given");
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -178,27 +260,6 @@ void _setupMqtt(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs)
|
||||
|
||||
|
||||
|
||||
void _setupHttp(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs)
|
||||
{
|
||||
const char *tcpAddress;
|
||||
int tcpPort;
|
||||
|
||||
tcpAddress=GWEN_DB_GetCharValue(dbArgs, "httpAddress", 0, NULL);
|
||||
tcpPort=GWEN_DB_GetIntValue(dbArgs, "httpPort", 0, AQHOME_STORAGE_DEFAULT_HTTP_PORT);
|
||||
|
||||
if (tcpAddress && *tcpAddress && tcpPort) {
|
||||
GWEN_MSG_ENDPOINT *ep;
|
||||
|
||||
ep=GWEN_TcpdEndpoint_new(tcpAddress, tcpPort, NULL, 0);
|
||||
GWEN_TcpdEndpoint_SetAcceptFn(ep, _acceptHttpFn, aqh);
|
||||
|
||||
GWEN_MsgEndpoint_Tree2_AddChild(aqh->rootEndpoint, ep);
|
||||
aqh->httpdEndpoint=ep;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_MSG_ENDPOINT *_acceptIpcFn(GWEN_MSG_ENDPOINT *ep,
|
||||
GWEN_SOCKET *sk,
|
||||
const GWEN_INETADDRESS *addr,
|
||||
@@ -214,28 +275,6 @@ GWEN_MSG_ENDPOINT *_acceptIpcFn(GWEN_MSG_ENDPOINT *ep,
|
||||
|
||||
|
||||
|
||||
GWEN_MSG_ENDPOINT *_acceptHttpFn(GWEN_MSG_ENDPOINT *ep,
|
||||
GWEN_SOCKET *sk,
|
||||
const GWEN_INETADDRESS *addr,
|
||||
GWEN_UNUSED void *data)
|
||||
{
|
||||
GWEN_MSG_ENDPOINT *epIncoming;
|
||||
|
||||
/* AQHOME_STORAGE *aqh;
|
||||
*
|
||||
* aqh=(AQHOME_STORAGE*) data;
|
||||
*/
|
||||
|
||||
DBG_INFO(NULL, "Incoming HTTP connection");
|
||||
epIncoming=GWEN_MsgEndpoint_new("http", 0);
|
||||
GWEN_MsgEndpoint_SetSocket(epIncoming, sk);
|
||||
GWEN_MsgIoEndpoint_Extend(epIncoming);
|
||||
AQH_HttpEndpoint_Extend(epIncoming, AQH_ENDPOINT_HTTP_FLAGS_PASSIVE);
|
||||
return epIncoming;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _createPidFile(const char *pidFilename)
|
||||
{
|
||||
FILE *f;
|
||||
@@ -360,7 +399,7 @@ int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs)
|
||||
"httpAddress", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"ma", /* short option */
|
||||
"ha", /* short option */
|
||||
"httpaddress", /* long option */
|
||||
I18S("Specify the address to bind the http service to (disabled if missing)"),
|
||||
I18S("Specify the address to bind the http service to (disabled if missing)")
|
||||
@@ -371,11 +410,22 @@ int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs)
|
||||
"httpPort", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"mp", /* short option */
|
||||
"hp", /* short option */
|
||||
"httpport", /* long option */
|
||||
I18S("Specify the port to listen on for HTTP connections"),
|
||||
I18S("Specify the port to listen on for HTTP connections")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"sourcefolder", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
NULL, /* short option */
|
||||
"sourcefolder", /* long option */
|
||||
I18S("Folder where static HTML source files are stored"),
|
||||
I18S("Folder where static HTML source files are stored")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
|
||||
244
apps/aqhome-storage/init_http.c
Normal file
244
apps/aqhome-storage/init_http.c
Normal file
@@ -0,0 +1,244 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./init_http.h"
|
||||
#include "./aqhomestorage_p.h"
|
||||
#include "./aqhomehttp.h"
|
||||
#include "./u_login.h"
|
||||
#include "./u_rooms.h"
|
||||
|
||||
#include "aqhome/msg/endpoint_tty.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/mqtt/endpoint_mqttc.h"
|
||||
#include "aqhome/http/endpoint_http.h"
|
||||
#include "aqhome/http/httpservice_conf.h"
|
||||
#include "aqhome/http/httpservice_http.h"
|
||||
#include "aqhome/http/httpservice.h"
|
||||
#include "aqhome/http/content_files.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/args.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint_tcpd.h>
|
||||
#include <gwenhywfar/endpoint_msgio.h>
|
||||
#include <gwenhywfar/directory.h>
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
# include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//#define I18N(msg) msg
|
||||
#define I18S(msg) msg
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _setupEndpoint(AQHOME_STORAGE *aqh, const char *tcpAddress, int tcpPort);
|
||||
static int _setupHttpService(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs);
|
||||
static int _createContentRoot(AQHOME_STORAGE *aqh);
|
||||
static GWEN_MSG_ENDPOINT *_acceptHttpFn(GWEN_MSG_ENDPOINT *ep, GWEN_SOCKET *sk, const GWEN_INETADDRESS *addr, void *data);
|
||||
|
||||
static int _createUrlHandler_login(AQHOME_STORAGE *aqh);
|
||||
static int _createUrlHandler_rooms(AQHOME_STORAGE *aqh);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int AqHomeStorage_SetupHttp(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs)
|
||||
{
|
||||
const char *tcpAddress;
|
||||
int tcpPort;
|
||||
|
||||
tcpAddress=GWEN_DB_GetCharValue(dbArgs, "httpAddress", 0, NULL);
|
||||
tcpPort=GWEN_DB_GetIntValue(dbArgs, "httpPort", 0, AQHOME_STORAGE_DEFAULT_HTTP_PORT);
|
||||
|
||||
if (tcpAddress && *tcpAddress && tcpPort) {
|
||||
int rv;
|
||||
|
||||
_setupEndpoint(aqh, tcpAddress, tcpPort);
|
||||
rv=_setupHttpService(aqh, dbArgs);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv=_createContentRoot(aqh);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv=_createUrlHandler_login(aqh);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv=_createUrlHandler_rooms(aqh);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _setupEndpoint(AQHOME_STORAGE *aqh, const char *tcpAddress, int tcpPort)
|
||||
{
|
||||
GWEN_MSG_ENDPOINT *ep;
|
||||
|
||||
ep=GWEN_TcpdEndpoint_new(tcpAddress, tcpPort, NULL, 0);
|
||||
GWEN_TcpdEndpoint_SetAcceptFn(ep, _acceptHttpFn, aqh);
|
||||
|
||||
GWEN_MsgEndpoint_Tree2_AddChild(aqh->rootEndpoint, ep);
|
||||
aqh->httpdEndpoint=ep;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _setupHttpService(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs)
|
||||
{
|
||||
const char *configFolder;
|
||||
const char *sourceFolder;
|
||||
int rv;
|
||||
|
||||
configFolder=GWEN_DB_GetCharValue(dbArgs, "cfgdir", 0, AQHOME_STORAGE_DEFAULT_CONFIGDIR);
|
||||
sourceFolder=GWEN_DB_GetCharValue(dbArgs, "sourceFolder", 0, AQHOME_STORAGE_DEFAULT_HTTP_SOURCEDIR);
|
||||
aqh->httpService=AQH_HttpService_new(configFolder, sourceFolder);
|
||||
AqHomeHttpService_Extend(aqh->httpService);
|
||||
AqHomeHttpService_SetStorage(aqh->httpService, aqh->storage);
|
||||
rv=AQH_HttpService_LoadConfig(aqh->httpService);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error loading config for HTTP service (%d)", rv);
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_MSG_ENDPOINT *_acceptHttpFn(GWEN_MSG_ENDPOINT *ep,
|
||||
GWEN_SOCKET *sk,
|
||||
const GWEN_INETADDRESS *addr,
|
||||
GWEN_UNUSED void *data)
|
||||
{
|
||||
GWEN_MSG_ENDPOINT *epIncoming;
|
||||
|
||||
/* AQHOME_STORAGE *aqh;
|
||||
*
|
||||
* aqh=(AQHOME_STORAGE*) data;
|
||||
*/
|
||||
|
||||
DBG_INFO(NULL, "Incoming HTTP connection");
|
||||
epIncoming=GWEN_MsgEndpoint_new("http", 0);
|
||||
GWEN_MsgEndpoint_SetSocket(epIncoming, sk);
|
||||
GWEN_MsgIoEndpoint_Extend(epIncoming);
|
||||
AQH_HttpEndpoint_Extend(epIncoming, AQH_ENDPOINT_HTTP_FLAGS_PASSIVE);
|
||||
return epIncoming;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _createContentRoot(AQHOME_STORAGE *aqh)
|
||||
{
|
||||
const char *sourceFolder;
|
||||
GWEN_BUFFER *nbuf1;
|
||||
GWEN_BUFFER *nbuf2;
|
||||
AQH_HTTP_CONTENT *c;
|
||||
|
||||
sourceFolder=AQH_HttpService_GetSourceFolder(aqh->httpService);
|
||||
|
||||
nbuf1=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
nbuf2=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
|
||||
GWEN_Buffer_AppendString(nbuf1, sourceFolder);
|
||||
GWEN_Buffer_AppendString(nbuf1, GWEN_DIR_SEPARATOR_S AQHOME_STORAGE_SITEHEADER);
|
||||
|
||||
GWEN_Buffer_AppendString(nbuf2, sourceFolder);
|
||||
GWEN_Buffer_AppendString(nbuf2, GWEN_DIR_SEPARATOR_S AQHOME_STORAGE_SITEFOOTER);
|
||||
|
||||
c=AQH_HttpContentFiles_new("root", GWEN_Buffer_GetStart(nbuf1), GWEN_Buffer_GetStart(nbuf2));
|
||||
if (c==NULL) {
|
||||
DBG_INFO(NULL,
|
||||
"Unable to create content for root (header=[%s], footer=[%s])",
|
||||
GWEN_Buffer_GetStart(nbuf1), GWEN_Buffer_GetStart(nbuf2));
|
||||
GWEN_Buffer_free(nbuf2);
|
||||
GWEN_Buffer_free(nbuf1);
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
AqHomeHttpService_SetContentTree(aqh->httpService, c);
|
||||
|
||||
GWEN_Buffer_free(nbuf2);
|
||||
GWEN_Buffer_free(nbuf1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _createUrlHandler_login(AQHOME_STORAGE *aqh)
|
||||
{
|
||||
AQH_HTTP_URLHANDLER *uh;
|
||||
|
||||
uh=AQH_LoginHttpUrlHandler_new(aqh->httpService);
|
||||
AQH_HttpUrlHandler_SetContentProvider(uh, AqHomeHttpService_GetContentTree(aqh->httpService));
|
||||
AQH_HttpUrlHandler_AddUrlPattern(uh, "/login");
|
||||
AQH_HttpService_AddUrlHandler(aqh->httpService, uh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _createUrlHandler_rooms(AQHOME_STORAGE *aqh)
|
||||
{
|
||||
AQH_HTTP_URLHANDLER *uh;
|
||||
|
||||
uh=AQH_RoomsHttpUrlHandler_new(aqh->httpService);
|
||||
AQH_HttpUrlHandler_SetContentProvider(uh, AqHomeHttpService_GetContentTree(aqh->httpService));
|
||||
AQH_HttpUrlHandler_AddUrlPattern(uh, "/rooms/*");
|
||||
AQH_HttpService_AddUrlHandler(aqh->httpService, uh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
23
apps/aqhome-storage/init_http.h
Normal file
23
apps/aqhome-storage/init_http.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_STORAGE_INIT_HTTP_H
|
||||
#define AQHOME_STORAGE_INIT_HTTP_H
|
||||
|
||||
|
||||
#include "./aqhomestorage.h"
|
||||
|
||||
|
||||
|
||||
int AqHomeStorage_SetupHttp(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -11,38 +11,14 @@
|
||||
#endif
|
||||
|
||||
|
||||
#include "./http.h"
|
||||
#include "./loop.h"
|
||||
#include "./loop_http.h"
|
||||
#include "./aqhomestorage_p.h"
|
||||
|
||||
#include "aqhome/msg/endpoint_tty.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/mqtt/endpoint_mqttc.h"
|
||||
#include "aqhome/http/endpoint_http.h"
|
||||
#include "aqhome/http/httpservice_http.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
#include <gwenhywfar/args.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint_tcpd.h>
|
||||
#include <gwenhywfar/endpoint_msgio.h>
|
||||
#include <gwenhywfar/syncio.h>
|
||||
#include <gwenhywfar/url.h>
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
# include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
|
||||
|
||||
|
||||
@@ -51,9 +27,6 @@
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//#define I18N(msg) msg
|
||||
#define I18S(msg) msg
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
@@ -63,10 +36,21 @@
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeStorage_Loop(AQHOME_STORAGE *aqh, int timeoutInMsecs)
|
||||
{
|
||||
if (aqh) {
|
||||
GWEN_MsgEndpoint_ChildrenIoLoop(aqh->rootEndpoint, timeoutInMsecs);
|
||||
AqHomeStorage_ReadAndHandleHttpMessages(aqh);
|
||||
// AqHomeStorage_ReadAndHandleIpcMessages(aqh);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
24
apps/aqhome-storage/loop.h
Normal file
24
apps/aqhome-storage/loop.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_STORAGE_LOOP_H
|
||||
#define AQHOME_STORAGE_LOOP_H
|
||||
|
||||
|
||||
#include "./aqhomestorage.h"
|
||||
|
||||
|
||||
void AqHomeStorage_Loop(AQHOME_STORAGE *aqh, int timeoutInMsecs);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
117
apps/aqhome-storage/loop_http.c
Normal file
117
apps/aqhome-storage/loop_http.c
Normal file
@@ -0,0 +1,117 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./loop_http.h"
|
||||
#include "./aqhomestorage_p.h"
|
||||
|
||||
#include "aqhome/msg/endpoint_tty.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/mqtt/endpoint_mqttc.h"
|
||||
#include "aqhome/http/endpoint_http.h"
|
||||
#include "aqhome/http/httpservice_http.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint_tcpd.h>
|
||||
#include <gwenhywfar/endpoint_msgio.h>
|
||||
#include <gwenhywfar/syncio.h>
|
||||
#include <gwenhywfar/url.h>
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
# include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//#define I18N(msg) msg
|
||||
#define I18S(msg) msg
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _handleHttpEndpoint(AQHOME_STORAGE *aqh, GWEN_MSG_ENDPOINT *ep);
|
||||
static void _handleHttpMsg(AQHOME_STORAGE *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msgReceived);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeStorage_ReadAndHandleHttpMessages(AQHOME_STORAGE *aqh)
|
||||
{
|
||||
if (aqh->httpdEndpoint) {
|
||||
GWEN_MSG_ENDPOINT *ep;
|
||||
|
||||
ep=GWEN_MsgEndpoint_Tree2_GetFirstChild(aqh->httpdEndpoint);
|
||||
while(ep) {
|
||||
_handleHttpEndpoint(aqh, ep);
|
||||
ep=GWEN_MsgEndpoint_Tree2_GetNext(ep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleHttpEndpoint(AQHOME_STORAGE *aqh, GWEN_MSG_ENDPOINT *ep)
|
||||
{
|
||||
GWEN_MSG *msg;
|
||||
|
||||
while( (msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(ep)) ) {
|
||||
_handleHttpMsg(aqh, ep, msg);
|
||||
GWEN_Msg_free(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleHttpMsg(AQHOME_STORAGE *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msgReceived)
|
||||
{
|
||||
GWEN_MSG *msgResponse;
|
||||
|
||||
msgResponse=AQH_HttpService_HandleHttpRequest(aqh->httpService, ep, msgReceived);
|
||||
if (msgResponse) {
|
||||
DBG_INFO(NULL, "Sending response message");
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, msgResponse);
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No response for message");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
21
apps/aqhome-storage/loop_http.h
Normal file
21
apps/aqhome-storage/loop_http.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_STORAGE_HTTP_H
|
||||
#define AQHOME_STORAGE_HTTP_H
|
||||
|
||||
|
||||
#include "./aqhomestorage.h"
|
||||
|
||||
|
||||
void AqHomeStorage_ReadAndHandleHttpMessages(AQHOME_STORAGE *aqh);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,12 +1,189 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <aqhome/api.h>
|
||||
#include <aqhome/aqhome.h>
|
||||
|
||||
#include "./aqhomestorage.h"
|
||||
#include "./init.h"
|
||||
#include "./fini.h"
|
||||
#include "./loop.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/logger.h>
|
||||
#include <gwenhywfar/cgui.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
# include <signal.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
static int _setSignalHandlers(void);
|
||||
static int _setupSigAction(struct sigaction *sa, int sig);
|
||||
static void _signalHandler(int s);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* static vars
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
static struct sigaction saINT,saTERM, saHUP, saTSTP, saCONT;
|
||||
#endif
|
||||
|
||||
static int stopService=0;
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
return 1;
|
||||
int rv;
|
||||
AQHOME_STORAGE *aqh;
|
||||
GWEN_GUI *gui;
|
||||
|
||||
rv=GWEN_Init();
|
||||
if (rv) {
|
||||
fprintf(stderr, "ERROR: Unable to init Gwen.\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
GWEN_Logger_Open(0, "aqhome-storage", 0, GWEN_LoggerType_Console, GWEN_LoggerFacility_User);
|
||||
//GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Warning);
|
||||
GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Info);
|
||||
|
||||
rv=_setSignalHandlers();
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv=AQH_Init();
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return 2;
|
||||
}
|
||||
|
||||
gui=GWEN_Gui_CGui_new();
|
||||
GWEN_Gui_SetGui(gui);
|
||||
|
||||
aqh=AqHomeStorage_new();
|
||||
rv=AqHomeStorage_Init(aqh, argc, argv);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return 2;
|
||||
}
|
||||
|
||||
while(!stopService) {
|
||||
DBG_DEBUG(NULL, "Next loop");
|
||||
AqHomeStorage_Loop(aqh, 2000);
|
||||
}
|
||||
|
||||
AqHomeStorage_Fini(aqh);
|
||||
AqHomeStorage_free(aqh);
|
||||
|
||||
GWEN_Gui_SetGui(NULL);
|
||||
GWEN_Gui_free(gui);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _setSignalHandlers(void)
|
||||
{
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
int rv;
|
||||
|
||||
rv=_setupSigAction(&saINT, SIGINT);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
rv=_setupSigAction(&saTERM, SIGTERM);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
rv=_setupSigAction(&saHUP, SIGHUP);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
# ifdef SIGTSTP
|
||||
rv=_setupSigAction(&saTSTP, SIGTSTP);
|
||||
if (rv)
|
||||
return rv;
|
||||
# endif
|
||||
|
||||
# ifdef SIGCONT
|
||||
rv=_setupSigAction(&saCONT, SIGCONT);
|
||||
if (rv)
|
||||
return rv;
|
||||
# endif
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _setupSigAction(struct sigaction *sa, int sig)
|
||||
{
|
||||
sa->sa_handler=_signalHandler;
|
||||
sigemptyset(&sa->sa_mask);
|
||||
sa->sa_flags=0;
|
||||
if (sigaction(sig, sa, 0)) {
|
||||
DBG_ERROR(NULL, "Could not setup signal handler for signal %d", sig);
|
||||
return GWEN_ERROR_IO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _signalHandler(int s)
|
||||
{
|
||||
switch(s) {
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
case SIGHUP:
|
||||
DBG_WARN(0, "Received signal %d, stopping service in next loop.",s);
|
||||
stopService=1;
|
||||
break;
|
||||
default:
|
||||
DBG_WARN(0, "Unknown signal %d",s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
388
apps/aqhome-storage/u_login.c
Normal file
388
apps/aqhome-storage/u_login.c
Normal file
@@ -0,0 +1,388 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./u_login.h"
|
||||
#include "aqhome/http/httpservice.h"
|
||||
#include "aqhome/http/httpservice_http.h"
|
||||
#include "aqhome/http/httpservice_conf.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/args.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
#include <gwenhywfar/mdigest.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
#include <gwenhywfar/timestamp.h>
|
||||
|
||||
|
||||
|
||||
static int _handleUrl(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
|
||||
static int _handleGet(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
|
||||
static int _handlePost(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
|
||||
|
||||
static int _loginUser(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
|
||||
static int _verifyPass(AQH_USER *u, const char *userName, const char *password);
|
||||
static AQH_SESSION *_generateSessionForUser(AQH_SERVICE *sv, AQH_USER *u);
|
||||
static GWEN_BUFFER *_generateSessionUid(void);
|
||||
static void _headerSetCookie(GWEN_DB_NODE *db, uint32_t flags, const char *cookieName, const char *cookieValue);
|
||||
static GWEN_MSG *_createLoginResponseMsg(AQH_SERVICE *sv, const char *protocol, const char *sessionId, const char *newPage);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
AQH_HTTP_URLHANDLER *AQH_LoginHttpUrlHandler_new(AQH_SERVICE *sv)
|
||||
{
|
||||
AQH_HTTP_URLHANDLER *uh;
|
||||
|
||||
uh=AQH_HttpUrlHandler_new(sv);
|
||||
AQH_HttpUrlHandler_SetHandleFn(uh, _handleUrl);
|
||||
|
||||
return uh;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _handleUrl(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
|
||||
{
|
||||
const char *protocol;
|
||||
const char *cmd;
|
||||
GWEN_MSG *msgOut=NULL;
|
||||
|
||||
protocol=AQH_HttpRequest_GetProtocol(rq);
|
||||
cmd=AQH_HttpRequest_GetCommand(rq);
|
||||
if (cmd && *cmd) {
|
||||
int rv;
|
||||
|
||||
if (strcasecmp(cmd, "GET")==0) {
|
||||
rv=_handleGet(uh, rq);
|
||||
if (rv<0) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(cmd, "POST")==0) {
|
||||
rv=_handlePost(uh, rq);
|
||||
if (rv<0) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
else {
|
||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 405, "Method not allowed", protocol, NULL);
|
||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "No command in request");
|
||||
return GWEN_ERROR_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _handleGet(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
|
||||
{
|
||||
GWEN_BUFFER *pageBuf;
|
||||
int rv;
|
||||
GWEN_MSG *msgOut=NULL;
|
||||
const char *protocol;
|
||||
|
||||
protocol=AQH_HttpRequest_GetProtocol(rq);
|
||||
pageBuf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
rv=AQH_HttpUrlHandler_AddContentHeaders(uh, AQH_HTTP_CONTENT_MODE_DESKTOP, pageBuf);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error adding headers");
|
||||
GWEN_Buffer_free(pageBuf);
|
||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
|
||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rv=AQH_HttpService_AddFile(AQH_HttpUrlHandler_GetHttpService(uh), NULL, "login.html", pageBuf);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error reading file \"login.html\"");
|
||||
GWEN_Buffer_free(pageBuf);
|
||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
|
||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rv=AQH_HttpUrlHandler_AddContentFooters(uh, AQH_HTTP_CONTENT_MODE_DESKTOP, pageBuf);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error adding footers");
|
||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
|
||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
||||
GWEN_Buffer_free(pageBuf);
|
||||
return rv;
|
||||
}
|
||||
|
||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 200, "OK", protocol, GWEN_Buffer_GetStart(pageBuf));
|
||||
GWEN_Buffer_free(pageBuf);
|
||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _handlePost(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
|
||||
{
|
||||
GWEN_DB_NODE *db;
|
||||
int rv;
|
||||
|
||||
DBG_ERROR(NULL, "Login POST:");
|
||||
db=AQH_HttpRequest_GetDbPostBody(rq);
|
||||
GWEN_DB_Dump(db, 2);
|
||||
|
||||
rv=_loginUser(uh, rq);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _loginUser(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
|
||||
{
|
||||
AQH_SERVICE *sv;
|
||||
GWEN_MSG *msgOut=NULL;
|
||||
const char *protocol;
|
||||
GWEN_DB_NODE *db;
|
||||
const char *userName;
|
||||
const char *password;
|
||||
AQH_USER *u;
|
||||
AQH_SESSION *session;
|
||||
int i;
|
||||
int rv;
|
||||
|
||||
sv=AQH_HttpUrlHandler_GetHttpService(uh);
|
||||
db=AQH_HttpRequest_GetDbPostBody(rq);
|
||||
protocol=AQH_HttpRequest_GetProtocol(rq);
|
||||
|
||||
userName=GWEN_DB_GetCharValue(db, "username", 0, NULL);
|
||||
password=GWEN_DB_GetCharValue(db, "password", 0, NULL);
|
||||
if (!(userName && *userName && password && *password)) {
|
||||
msgOut=AQH_HttpService_CreateResponseMsg(sv, 401, "Unauthorized", protocol, NULL);
|
||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u=AQH_HttpService_GetUser(sv, userName);
|
||||
if (u==NULL) {
|
||||
DBG_INFO(NULL, "User \"%s\" not found", userName);
|
||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 401, "Unauthorized", protocol, NULL);
|
||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
||||
return 0;
|
||||
}
|
||||
|
||||
i=AQH_User_GetState(u);
|
||||
if (i==AQH_UserState_Suspended) {
|
||||
DBG_INFO(NULL, "User \"%s\" suspended", userName);
|
||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 401, "Unauthorized", protocol, NULL);
|
||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rv=_verifyPass(u, userName, password);
|
||||
if (rv<0) {
|
||||
if (rv==GWEN_ERROR_VERIFY)
|
||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 401, "Unauthorized", protocol, "error");
|
||||
else
|
||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
|
||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
||||
return 0;
|
||||
}
|
||||
|
||||
session=_generateSessionForUser(sv, u);
|
||||
if (session==NULL) {
|
||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
|
||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DBG_ERROR(NULL, "Session generated");
|
||||
AQH_User_SetTimestampLastLogin(u, AQH_Session_GetTimestampCreation(session));
|
||||
rv=AQH_HttpService_WriteUser(sv, u);
|
||||
if (rv<0) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
|
||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
||||
return 0;
|
||||
}
|
||||
|
||||
msgOut=_createLoginResponseMsg(sv, protocol, AQH_Session_GetUid(session), "/rooms/list");
|
||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _verifyPass(AQH_USER *u, const char *userName, const char *password)
|
||||
{
|
||||
GWEN_MDIGEST *md;
|
||||
int rv;
|
||||
const char *storedPasswordHash;
|
||||
char buffer[70];
|
||||
|
||||
storedPasswordHash=AQH_User_GetHashedPassword(u);
|
||||
if (!(storedPasswordHash && *storedPasswordHash)) {
|
||||
DBG_ERROR(NULL, "No password hash stored with user \"%s\"", userName);
|
||||
return GWEN_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
md=GWEN_MDigest_Sha256_new();
|
||||
rv=GWEN_MDigest_Begin(md);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error digesting given password [begin] (%d)", rv);
|
||||
GWEN_MDigest_free(md);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv=GWEN_MDigest_Update(md, (const uint8_t*) password, strlen(password));
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error digesting given password [update] (%d)", rv);
|
||||
GWEN_MDigest_free(md);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv=GWEN_MDigest_End(md);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error digesting given password [end] (%d)", rv);
|
||||
GWEN_MDigest_free(md);
|
||||
return rv;
|
||||
}
|
||||
|
||||
DBG_ERROR(NULL, "Digest needs %d bytes", (GWEN_MDigest_GetDigestSize(md)*2)+1);
|
||||
if (NULL==GWEN_Text_ToHex((const char*) GWEN_MDigest_GetDigestPtr(md), GWEN_MDigest_GetDigestSize(md), buffer, sizeof(buffer)-1)) {
|
||||
DBG_ERROR(NULL, "Buffer too small (need %d)", (GWEN_MDigest_GetDigestSize(md)*2)+1);
|
||||
GWEN_MDigest_free(md);
|
||||
return GWEN_ERROR_INTERNAL;
|
||||
}
|
||||
GWEN_MDigest_free(md);
|
||||
|
||||
if (strcasecmp(buffer, storedPasswordHash)!=0) {
|
||||
DBG_ERROR(NULL, "Bad password for user \"%s\"", userName);
|
||||
return GWEN_ERROR_VERIFY;
|
||||
}
|
||||
|
||||
DBG_ERROR(NULL, "Valid password for user \"%s\"", userName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_SESSION *_generateSessionForUser(AQH_SERVICE *sv, AQH_USER *u)
|
||||
{
|
||||
AQH_SESSION *session;
|
||||
GWEN_BUFFER *buf;
|
||||
GWEN_TIMESTAMP *ts;
|
||||
int rv;
|
||||
|
||||
buf=_generateSessionUid();
|
||||
if (buf==NULL) {
|
||||
DBG_INFO(NULL, "here");
|
||||
return NULL;
|
||||
}
|
||||
DBG_INFO(NULL, "New session id: [%s]", GWEN_Buffer_GetStart(buf));
|
||||
|
||||
session=AQH_Session_new();
|
||||
AQH_Session_SetUid(session, GWEN_Buffer_GetStart(buf));
|
||||
|
||||
ts=GWEN_Timestamp_NowInGmTime();
|
||||
AQH_Session_SetTimestampCreation(session, ts);
|
||||
GWEN_Timestamp_free(ts);
|
||||
|
||||
AQH_Session_SetUserAlias(session, AQH_User_GetAlias(u));
|
||||
AQH_Session_SetUser(session, u);
|
||||
|
||||
rv=AQH_HttpService_AddSession(sv, session);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "Error adding session \"%s\" (%d)", AQH_Session_GetUid(session), rv);
|
||||
AQH_Session_free(session);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_BUFFER *_generateSessionUid(void)
|
||||
{
|
||||
uint8_t binbuf[8];
|
||||
GWEN_BUFFER *buf;
|
||||
int rv;
|
||||
|
||||
rv=GWEN_SyncIo_Helper_PartiallyReadFile("/dev/urandom", binbuf, sizeof(binbuf));
|
||||
if (rv<sizeof(binbuf)) {
|
||||
DBG_ERROR(NULL, "Error reading from /dev/urandom: %d", rv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf=GWEN_Buffer_new(0, 20, 0, 1);
|
||||
rv=GWEN_Text_ToHexBuffer((const char*) binbuf, rv, buf, 0, 0, 0);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error converting random bytes to hex (%d)", rv);
|
||||
GWEN_Buffer_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_MSG *_createLoginResponseMsg(AQH_SERVICE *sv, const char *protocol, const char *sessionId, const char *newPage)
|
||||
{
|
||||
GWEN_BUFFER *buf;
|
||||
GWEN_MSG *msg;
|
||||
GWEN_DB_NODE *db;
|
||||
|
||||
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
AQH_HttpService_AddStatusLine(sv, 303, "OK, redirecting to content", protocol, buf);
|
||||
db=GWEN_DB_Group_new("header");
|
||||
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Connection", "Keep-Alive");
|
||||
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Content-Type", "text/html; charset=utf-8");
|
||||
_headerSetCookie(db, GWEN_DB_FLAGS_OVERWRITE_VARS, AQH_HTTP_REQUEST_SESSIONCOOKIE, sessionId);
|
||||
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Location", newPage);
|
||||
GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Content-Length", 0);
|
||||
AQH_HttpService_AddHeader(sv, db, buf);
|
||||
GWEN_DB_Group_free(db);
|
||||
|
||||
msg=GWEN_Msg_fromBytes((const uint8_t*)GWEN_Buffer_GetStart(buf), GWEN_Buffer_GetUsedBytes(buf));
|
||||
GWEN_Buffer_free(buf);
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _headerSetCookie(GWEN_DB_NODE *db, uint32_t flags, const char *cookieName, const char *cookieValue)
|
||||
{
|
||||
if (cookieName && cookieValue) {
|
||||
GWEN_BUFFER *dbuf;
|
||||
|
||||
dbuf=GWEN_Buffer_new(0, 32, 0, 1);
|
||||
GWEN_Buffer_AppendArgs(dbuf, "%s=%s", cookieName, cookieValue);
|
||||
GWEN_DB_SetCharValue(db, flags, "Set-Cookie", GWEN_Buffer_GetStart(dbuf));
|
||||
GWEN_Buffer_free(dbuf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
24
apps/aqhome-storage/u_login.h
Normal file
24
apps/aqhome-storage/u_login.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_STORAGE_U_LOGIN_H
|
||||
#define AQHOME_STORAGE_U_LOGIN_H
|
||||
|
||||
|
||||
#include "aqhome/http/urlhandler.h"
|
||||
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
|
||||
|
||||
AQH_HTTP_URLHANDLER *AQH_LoginHttpUrlHandler_new(AQH_SERVICE *sv);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
344
apps/aqhome-storage/u_rooms.c
Normal file
344
apps/aqhome-storage/u_rooms.c
Normal file
@@ -0,0 +1,344 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./u_rooms.h"
|
||||
#include "./aqhomehttp.h"
|
||||
#include "aqhome/http/httpservice.h"
|
||||
#include "aqhome/http/httpservice_http.h"
|
||||
#include "aqhome/http/httpservice_conf.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/args.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
#include <gwenhywfar/mdigest.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
#include <gwenhywfar/timestamp.h>
|
||||
|
||||
|
||||
|
||||
static int _handleUrl(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
|
||||
static int _handleGet(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
|
||||
static int _handlePost(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
|
||||
|
||||
static void _handleGetList(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_BUFFER *pageBuf);
|
||||
|
||||
static void _handleGetAdd(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_BUFFER *pageBuf);
|
||||
static int _handlePostAdd(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
|
||||
static int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_BUFFER *pageBuf);
|
||||
|
||||
|
||||
|
||||
|
||||
AQH_HTTP_URLHANDLER *AQH_RoomsHttpUrlHandler_new(AQH_SERVICE *sv)
|
||||
{
|
||||
AQH_HTTP_URLHANDLER *uh;
|
||||
|
||||
uh=AQH_HttpUrlHandler_new(sv);
|
||||
AQH_HttpUrlHandler_SetHandleFn(uh, _handleUrl);
|
||||
|
||||
return uh;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _handleUrl(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
|
||||
{
|
||||
const char *protocol;
|
||||
const char *cmd;
|
||||
GWEN_MSG *msgOut=NULL;
|
||||
|
||||
AQH_HttpService_SetupModuleAndPerms(AQH_HttpUrlHandler_GetHttpService(uh), rq, "aqhome");
|
||||
AQH_HttpRequest_SetupUrlPathMembers(rq);
|
||||
|
||||
protocol=AQH_HttpRequest_GetProtocol(rq);
|
||||
cmd=AQH_HttpRequest_GetCommand(rq);
|
||||
if (cmd && *cmd) {
|
||||
int rv;
|
||||
|
||||
if (strcasecmp(cmd, "GET")==0) {
|
||||
rv=_handleGet(uh, rq);
|
||||
if (rv<0) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(cmd, "POST")==0) {
|
||||
rv=_handlePost(uh, rq);
|
||||
if (rv<0) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
else {
|
||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 405, "Method not allowed", protocol, NULL);
|
||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "No command in request");
|
||||
return GWEN_ERROR_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _handleGet(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
|
||||
{
|
||||
GWEN_BUFFER *pageBuf;
|
||||
int rv;
|
||||
GWEN_MSG *msgOut=NULL;
|
||||
const char *protocol;
|
||||
const GWEN_STRINGLIST *sl;
|
||||
|
||||
protocol=AQH_HttpRequest_GetProtocol(rq);
|
||||
pageBuf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
rv=AQH_HttpUrlHandler_AddContentHeaders(uh, AQH_HTTP_CONTENT_MODE_DESKTOP, pageBuf);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error adding headers");
|
||||
GWEN_Buffer_free(pageBuf);
|
||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
|
||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* handle middle part (header - middle - footer) */
|
||||
sl=AQH_HttpRequest_GetUrlPathMembers(rq);
|
||||
if (sl) {
|
||||
const char *s;
|
||||
|
||||
s=GWEN_StringList_StringAt(sl, 1);
|
||||
if (!(s && *s))
|
||||
s="list";
|
||||
|
||||
if (strcasecmp(s, "list")==0)
|
||||
_handleGetList(uh, rq, pageBuf);
|
||||
else if (strcasecmp(s, "add")==0)
|
||||
_handleGetAdd(uh, rq, pageBuf);
|
||||
else {
|
||||
DBG_ERROR(NULL, "Invalid url (2nd member is [%s])", s);
|
||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
|
||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
||||
GWEN_Buffer_free(pageBuf);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
rv=AQH_HttpUrlHandler_AddContentFooters(uh, AQH_HTTP_CONTENT_MODE_DESKTOP, pageBuf);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error adding footers");
|
||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
|
||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
||||
GWEN_Buffer_free(pageBuf);
|
||||
return rv;
|
||||
}
|
||||
|
||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 200, "OK", protocol, GWEN_Buffer_GetStart(pageBuf));
|
||||
GWEN_Buffer_free(pageBuf);
|
||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _handlePost(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
|
||||
{
|
||||
GWEN_DB_NODE *db;
|
||||
const GWEN_STRINGLIST *sl;
|
||||
const char *protocol;
|
||||
GWEN_MSG *msgOut=NULL;
|
||||
int rv;
|
||||
|
||||
DBG_ERROR(NULL, "POST:");
|
||||
db=AQH_HttpRequest_GetDbPostBody(rq);
|
||||
GWEN_DB_Dump(db, 2);
|
||||
|
||||
protocol=AQH_HttpRequest_GetProtocol(rq);
|
||||
sl=AQH_HttpRequest_GetUrlPathMembers(rq);
|
||||
if (sl) {
|
||||
const char *s;
|
||||
|
||||
s=GWEN_StringList_StringAt(sl, 1);
|
||||
if (s && *s) {
|
||||
if (strcasecmp(s, "add")==0)
|
||||
rv=_handlePostAdd(uh, rq);
|
||||
else {
|
||||
DBG_ERROR(NULL, "Invalid url (2nd member is [%s])", s);
|
||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
|
||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
||||
return 0;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Invalid url (2nd member missing)");
|
||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
|
||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// TODO
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleGetList(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_BUFFER *pageBuf)
|
||||
{
|
||||
AQH_SERVICE *sv;
|
||||
uint32_t perms;
|
||||
|
||||
DBG_ERROR(NULL, "LIST");
|
||||
perms=AQH_HttpRequest_GetModulePerms(rq);
|
||||
if (perms & AQHOME_HTTP_PERMS_LIST_ROOMS) {
|
||||
AQH_STORAGE *sto;
|
||||
|
||||
sv=AQH_HttpUrlHandler_GetHttpService(uh);
|
||||
sto=AqHomeHttpService_GetStorage(sv);
|
||||
if (sto) {
|
||||
const AQH_ROOM_LIST *rl;
|
||||
|
||||
GWEN_Buffer_AppendString(pageBuf, "<h2>Rooms</h2>");
|
||||
GWEN_Buffer_AppendString(pageBuf, "<table>");
|
||||
GWEN_Buffer_AppendString(pageBuf, "<tr><th>Id</th><th>Name</th><th>Description</th></tr>");
|
||||
rl=AQH_Storage_GetRoomList(sto);
|
||||
if (rl) {
|
||||
const AQH_ROOM *r;
|
||||
|
||||
r=AQH_Room_List_First(rl);
|
||||
while(r) {
|
||||
long unsigned int id;
|
||||
const char *name;
|
||||
const char *descr;
|
||||
|
||||
id=(long unsigned int) AQH_Room_GetId(r);
|
||||
name=AQH_Room_GetName(r);
|
||||
descr=AQH_Room_GetDescription(r);
|
||||
GWEN_Buffer_AppendArgs(pageBuf, "<tr><td>%lu</td><td>%s</td><td>%s</td></tr>", id, name?name:"", descr?descr:"");
|
||||
|
||||
r=AQH_Room_List_Next(r);
|
||||
}
|
||||
}
|
||||
GWEN_Buffer_AppendString(pageBuf, "</table>");
|
||||
GWEN_Buffer_AppendString(pageBuf, "<a href=\"/rooms/add\">Add Room</a><br>");
|
||||
}
|
||||
else {
|
||||
GWEN_Buffer_AppendString(pageBuf, "<p>Internal error.</p>");
|
||||
}
|
||||
}
|
||||
else {
|
||||
GWEN_Buffer_AppendString(pageBuf, "<p>No permissions to see list of rooms.</p>");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleGetAdd(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_BUFFER *pageBuf)
|
||||
{
|
||||
uint32_t perms;
|
||||
|
||||
DBG_ERROR(NULL, "ADD");
|
||||
perms=AQH_HttpRequest_GetModulePerms(rq);
|
||||
if (perms & AQHOME_HTTP_PERMS_ADD_ROOM) {
|
||||
_writeAddPage(uh, rq, pageBuf);
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No permissions to add a room.");
|
||||
GWEN_Buffer_AppendString(pageBuf, "<p>No permissions to add a room.</p>");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_BUFFER *pageBuf)
|
||||
{
|
||||
int rv;
|
||||
int pos;
|
||||
|
||||
pos=GWEN_Buffer_GetPos(pageBuf);
|
||||
rv=AQH_HttpService_AddFile(AQH_HttpUrlHandler_GetHttpService(uh), NULL, "roomadd.html", pageBuf);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error reading file \"roomadd.html\"");
|
||||
GWEN_Buffer_Crop(pageBuf, 0, pos);
|
||||
GWEN_Buffer_AppendString(pageBuf, "<p>Internal error.</p>");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _handlePostAdd(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
|
||||
{
|
||||
const char *protocol;
|
||||
AQH_SERVICE *sv;
|
||||
uint32_t perms;
|
||||
GWEN_MSG *msgOut=NULL;
|
||||
|
||||
protocol=AQH_HttpRequest_GetProtocol(rq);
|
||||
sv=AQH_HttpUrlHandler_GetHttpService(uh);
|
||||
perms=AQH_HttpRequest_GetModulePerms(rq);
|
||||
if (perms & AQHOME_HTTP_PERMS_ADD_ROOM) {
|
||||
GWEN_DB_NODE *db;
|
||||
const char *roomName;
|
||||
const char *roomDescr;
|
||||
AQH_STORAGE *sto;
|
||||
|
||||
db=AQH_HttpRequest_GetDbPostBody(rq);
|
||||
|
||||
roomName=GWEN_DB_GetCharValue(db, "roomname", 0, NULL);
|
||||
roomDescr=GWEN_DB_GetCharValue(db, "descr", 0, NULL);
|
||||
|
||||
if (!(roomName && *roomName)) {
|
||||
msgOut=AQH_HttpUrlHandler_CreatePageMessage(uh, rq, "red", "Missing room name", 1, _writeAddPage);
|
||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sto=AqHomeHttpService_GetStorage(sv);
|
||||
if (sto) {
|
||||
AQH_ROOM *r;
|
||||
|
||||
r=AQH_Room_new();
|
||||
AQH_Room_SetName(r, roomName);
|
||||
if (roomDescr && *roomDescr)
|
||||
AQH_Room_SetDescription(r, roomDescr);
|
||||
if (AQH_Storage_GetRoomByName(sto, roomName)!=NULL) {
|
||||
msgOut=AQH_HttpUrlHandler_CreatePageMessage(uh, rq, "red", "Room already exists", 1, _writeAddPage);
|
||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
||||
return 0;
|
||||
}
|
||||
AQH_Storage_AddRoom(sto, r);
|
||||
msgOut=AQH_HttpService_CreateRedirectingResponseMsg(sv, protocol, "/rooms/list");
|
||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "No storage");
|
||||
msgOut=AQH_HttpService_CreateResponseMsg(sv, 500, "Internal error", protocol, NULL);
|
||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
msgOut=AQH_HttpService_CreateResponseMsg(sv, 403, "Forbidden", protocol, NULL);
|
||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
24
apps/aqhome-storage/u_rooms.h
Normal file
24
apps/aqhome-storage/u_rooms.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_STORAGE_U_ROOMS_H
|
||||
#define AQHOME_STORAGE_U_ROOMS_H
|
||||
|
||||
|
||||
#include "aqhome/http/urlhandler.h"
|
||||
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
|
||||
|
||||
AQH_HTTP_URLHANDLER *AQH_RoomsHttpUrlHandler_new(AQH_SERVICE *sv);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
15
aqhome-storage.sh
Executable file
15
aqhome-storage.sh
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
|
||||
export AQHOME_LOGLEVEL=info
|
||||
export LD_LIBRARY_PATH="0-build/aqhome/:$LD_LIBRARY_PATH"
|
||||
|
||||
# 0-build/apps/aqhome-storage/aqhome-storage $*
|
||||
|
||||
0-build/apps/aqhome-storage/aqhome-storage \
|
||||
--sourcefolder=apps/aqhome-storage/test/html \
|
||||
-D apps/aqhome-storage/test/config \
|
||||
--statefile=apps/aqhome-storage/test/config/state \
|
||||
-ma 192.168.117.192 -mp 1883 --mqttclientid=AQHOMESTORAGETEST \
|
||||
-ha 127.0.0.1 -hp 1884 \
|
||||
-p ./aqhome-storage.pid
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags></flags>
|
||||
<flags>with_getbymember</flags>
|
||||
</member>
|
||||
|
||||
<member name="description" type="char_ptr" maxlen="256">
|
||||
|
||||
@@ -82,6 +82,40 @@ void AQH_Storage_SetStateFile(AQH_STORAGE *sto, const char *s)
|
||||
|
||||
|
||||
|
||||
void AQH_Storage_AddRoom(AQH_STORAGE *sto, AQH_ROOM *r)
|
||||
{
|
||||
if (sto && r) {
|
||||
uint64_t id;
|
||||
|
||||
id=++(sto->lastRoomId);
|
||||
AQH_Room_SetId(r, id);
|
||||
AQH_Room_List_Add(r, sto->roomList);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_ROOM_LIST *AQH_Storage_GetRoomList(const AQH_STORAGE *sto)
|
||||
{
|
||||
return sto?sto->roomList:NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_ROOM *AQH_Storage_GetRoomById(const AQH_STORAGE *sto, uint64_t id)
|
||||
{
|
||||
return sto?AQH_Room_List_GetById(sto->roomList, id):NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_ROOM *AQH_Storage_GetRoomByName(const AQH_STORAGE *sto, const char *s)
|
||||
{
|
||||
return sto?AQH_Room_List_GetByName(sto->roomList, s):NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_Storage_AddDevice(AQH_STORAGE *sto, AQH_DEVICE *dev)
|
||||
{
|
||||
if (sto && dev) {
|
||||
|
||||
@@ -46,6 +46,11 @@ extern "C" {
|
||||
AQHOME_API AQH_STORAGE *AQH_Storage_new(void);
|
||||
AQHOME_API void AQH_Storage_free(AQH_STORAGE *sto);
|
||||
|
||||
AQHOME_API void AQH_Storage_AddRoom(AQH_STORAGE *sto, AQH_ROOM *r);
|
||||
AQHOME_API AQH_ROOM_LIST *AQH_Storage_GetRoomList(const AQH_STORAGE *sto);
|
||||
AQHOME_API AQH_ROOM *AQH_Storage_GetRoomById(const AQH_STORAGE *sto, uint64_t id);
|
||||
AQHOME_API AQH_ROOM *AQH_Storage_GetRoomByName(const AQH_STORAGE *sto, const char *s);
|
||||
|
||||
AQHOME_API void AQH_Storage_AddDevice(AQH_STORAGE *sto, AQH_DEVICE *dev);
|
||||
AQHOME_API AQH_DEVICE_LIST *AQH_Storage_GetDeviceList(const AQH_STORAGE *sto);
|
||||
AQHOME_API AQH_DEVICE *AQH_Storage_GetDeviceById(const AQH_STORAGE *sto, uint64_t id);
|
||||
|
||||
@@ -50,6 +50,9 @@
|
||||
httpservice_conf.h
|
||||
httpservice_http.h
|
||||
httprequest.h
|
||||
urlhandler.h
|
||||
content.h
|
||||
content_files.h
|
||||
</headers>
|
||||
|
||||
|
||||
@@ -57,6 +60,9 @@
|
||||
endpoint_http_p.h
|
||||
httpservice_p.h
|
||||
httprequest_p.h
|
||||
urlhandler_p.h
|
||||
content_p.h
|
||||
content_files_p.h
|
||||
</headers>
|
||||
|
||||
|
||||
@@ -68,6 +74,9 @@
|
||||
httpservice_conf.c
|
||||
httpservice_http.c
|
||||
httprequest.c
|
||||
urlhandler.c
|
||||
content.c
|
||||
content_files.c
|
||||
</sources>
|
||||
|
||||
|
||||
|
||||
112
aqhome/http/content.c
Normal file
112
aqhome/http/content.c
Normal file
@@ -0,0 +1,112 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "aqhome/http/content_p.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
|
||||
GWEN_INHERIT_FUNCTIONS(AQH_HTTP_CONTENT)
|
||||
GWEN_TREE2_FUNCTIONS(AQH_HTTP_CONTENT, AQH_HttpContent)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
AQH_HTTP_CONTENT *AQH_HttpContent_new(const char *name)
|
||||
{
|
||||
AQH_HTTP_CONTENT *cp;
|
||||
|
||||
GWEN_NEW_OBJECT(AQH_HTTP_CONTENT, cp);
|
||||
GWEN_INHERIT_INIT(AQH_HTTP_CONTENT, cp);
|
||||
GWEN_TREE2_INIT(AQH_HTTP_CONTENT, cp, AQH_HttpContent);
|
||||
|
||||
cp->name=name?strdup(name):NULL;
|
||||
|
||||
return cp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_HttpContent_free(AQH_HTTP_CONTENT *cp)
|
||||
{
|
||||
if (cp) {
|
||||
GWEN_TREE2_FINI(AQH_HTTP_CONTENT, cp, AQH_HttpContent);
|
||||
GWEN_INHERIT_FINI(AQH_HTTP_CONTENT, cp);
|
||||
GWEN_FREE_OBJECT(cp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *AQH_HttpContent_GetName(const AQH_HTTP_CONTENT *cp)
|
||||
{
|
||||
return cp?cp->name:NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AQH_HttpContent_AddOpeningContent(AQH_HTTP_CONTENT *cp, int mode, GWEN_BUFFER *buffer)
|
||||
{
|
||||
return (cp && cp->addOpeningContentFn)?(cp->addOpeningContentFn(cp, mode, buffer)):0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AQH_HttpContent_AddClosingContent(AQH_HTTP_CONTENT *cp, int mode, GWEN_BUFFER *buffer)
|
||||
{
|
||||
return (cp && cp->addClosingContentFn)?(cp->addClosingContentFn(cp, mode, buffer)):0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_HttpContent_SetAddOpeningContentFn(AQH_HTTP_CONTENT *cp, AQH_HTTP_CONTENT_ADD_OPENING_CONTENT_FN f)
|
||||
{
|
||||
if (cp)
|
||||
cp->addOpeningContentFn=f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_HttpContent_SetAddClosingContentFn(AQH_HTTP_CONTENT *cp, AQH_HTTP_CONTENT_ADD_CLOSING_CONTENT_FN f)
|
||||
{
|
||||
if (cp)
|
||||
cp->addClosingContentFn=f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_HTTP_CONTENT *AQH_HttpContent_Tree2_FindChildByName(AQH_HTTP_CONTENT *parent, const char *name)
|
||||
{
|
||||
if (parent) {
|
||||
AQH_HTTP_CONTENT *c;
|
||||
|
||||
c=AQH_HttpContent_Tree2_GetFirstChild(parent);
|
||||
while(c) {
|
||||
const char *s;
|
||||
|
||||
s=AQH_HttpContent_GetName(c);
|
||||
if (s && *s && strcasecmp(s, name)==0)
|
||||
return c;
|
||||
c=AQH_HttpContent_Tree2_GetNext(c);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
63
aqhome/http/content.h
Normal file
63
aqhome/http/content.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_HTTP_CONTENT_H
|
||||
#define AQHOME_HTTP_CONTENT_H
|
||||
|
||||
|
||||
#include <aqhome/api.h>
|
||||
|
||||
#include <gwenhywfar/buffer.h>
|
||||
#include <gwenhywfar/inherit.h>
|
||||
#include <gwenhywfar/tree2.h>
|
||||
|
||||
|
||||
#define AQH_HTTP_CONTENT_MODE_DESKTOP 0
|
||||
#define AQH_HTTP_CONTENT_MODE_MOBILE 1
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
typedef struct AQH_HTTP_CONTENT AQH_HTTP_CONTENT;
|
||||
GWEN_INHERIT_FUNCTION_LIB_DEFS(AQH_HTTP_CONTENT, AQHOME_API)
|
||||
GWEN_TREE2_FUNCTION_LIB_DEFS(AQH_HTTP_CONTENT, AQH_HttpContent, AQHOME_API)
|
||||
|
||||
|
||||
typedef int (*AQH_HTTP_CONTENT_ADD_OPENING_CONTENT_FN)(AQH_HTTP_CONTENT *cp, int mode, GWEN_BUFFER *buffer);
|
||||
typedef int (*AQH_HTTP_CONTENT_ADD_CLOSING_CONTENT_FN)(AQH_HTTP_CONTENT *cp, int mode, GWEN_BUFFER *buffer);
|
||||
|
||||
|
||||
AQHOME_API AQH_HTTP_CONTENT *AQH_HttpContent_new(const char *name);
|
||||
AQHOME_API void AQH_HttpContent_free(AQH_HTTP_CONTENT *cp);
|
||||
|
||||
AQHOME_API const char *AQH_HttpContent_GetName(const AQH_HTTP_CONTENT *cp);
|
||||
|
||||
|
||||
AQHOME_API int AQH_HttpContent_AddOpeningContent(AQH_HTTP_CONTENT *cp, int mode, GWEN_BUFFER *buffer);
|
||||
AQHOME_API int AQH_HttpContent_AddClosingContent(AQH_HTTP_CONTENT *cp, int mode, GWEN_BUFFER *buffer);
|
||||
|
||||
|
||||
AQHOME_API void AQH_HttpContent_SetAddOpeningContentFn(AQH_HTTP_CONTENT *cp, AQH_HTTP_CONTENT_ADD_OPENING_CONTENT_FN f);
|
||||
AQHOME_API void AQH_HttpContent_SetAddClosingContentFn(AQH_HTTP_CONTENT *cp, AQH_HTTP_CONTENT_ADD_CLOSING_CONTENT_FN f);
|
||||
|
||||
AQHOME_API AQH_HTTP_CONTENT *AQH_HttpContent_Tree2_FindChildByName(AQH_HTTP_CONTENT *parent, const char *name);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
140
aqhome/http/content_files.c
Normal file
140
aqhome/http/content_files.c
Normal file
@@ -0,0 +1,140 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "aqhome/http/content_files_p.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/syncio.h>
|
||||
|
||||
|
||||
|
||||
GWEN_INHERIT(AQH_HTTP_CONTENT, AQH_HTTP_CONTENT_FILES)
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _freeData(void *bp, void *p);
|
||||
static int _addOpeningContent(AQH_HTTP_CONTENT *cp, int mode, GWEN_BUFFER *buffer);
|
||||
static int _addClosingContent(AQH_HTTP_CONTENT *cp, int mode, GWEN_BUFFER *buffer);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
AQH_HTTP_CONTENT *AQH_HttpContentFiles_new(const char *name, const char *headerFilename, const char *footerFilename)
|
||||
{
|
||||
AQH_HTTP_CONTENT *cp;
|
||||
AQH_HTTP_CONTENT_FILES *xcp;
|
||||
|
||||
cp=AQH_HttpContent_new(name);
|
||||
GWEN_NEW_OBJECT(AQH_HTTP_CONTENT_FILES, xcp);
|
||||
GWEN_INHERIT_SETDATA(AQH_HTTP_CONTENT, AQH_HTTP_CONTENT_FILES, cp, xcp, _freeData);
|
||||
|
||||
xcp->headerFilename=(headerFilename && *headerFilename)?strdup(headerFilename):NULL;
|
||||
xcp->footerFilename=(footerFilename && *footerFilename)?strdup(footerFilename):NULL;
|
||||
|
||||
AQH_HttpContent_SetAddOpeningContentFn(cp, _addOpeningContent);
|
||||
AQH_HttpContent_SetAddClosingContentFn(cp, _addClosingContent);
|
||||
|
||||
return cp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _freeData(void *bp, void *p)
|
||||
{
|
||||
AQH_HTTP_CONTENT_FILES *xcp;
|
||||
|
||||
xcp=(AQH_HTTP_CONTENT_FILES*) p;
|
||||
|
||||
free(xcp->footerData);
|
||||
free(xcp->headerData);
|
||||
|
||||
free(xcp->footerFilename);
|
||||
free(xcp->headerFilename);
|
||||
GWEN_FREE_OBJECT(xcp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _addOpeningContent(AQH_HTTP_CONTENT *cp, int mode, GWEN_BUFFER *buffer)
|
||||
{
|
||||
if (cp) {
|
||||
AQH_HTTP_CONTENT_FILES *xcp;
|
||||
|
||||
xcp=GWEN_INHERIT_GETDATA(AQH_HTTP_CONTENT, AQH_HTTP_CONTENT_FILES, cp);
|
||||
if (xcp) {
|
||||
if (xcp->headerData==NULL) {
|
||||
if (xcp->headerFilename) {
|
||||
int rv;
|
||||
GWEN_BUFFER *fileBuffer;
|
||||
|
||||
fileBuffer=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
rv=GWEN_SyncIo_Helper_ReadFile(xcp->headerFilename, fileBuffer);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error reading header file \"%s\": %d", xcp->headerFilename, rv);
|
||||
GWEN_Buffer_free(fileBuffer);
|
||||
return rv;
|
||||
}
|
||||
xcp->headerData=strdup(GWEN_Buffer_GetStart(fileBuffer));
|
||||
GWEN_Buffer_free(fileBuffer);
|
||||
}
|
||||
}
|
||||
if (xcp->headerData)
|
||||
GWEN_Buffer_AppendString(buffer, xcp->headerData);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _addClosingContent(AQH_HTTP_CONTENT *cp, int mode, GWEN_BUFFER *buffer)
|
||||
{
|
||||
if (cp) {
|
||||
AQH_HTTP_CONTENT_FILES *xcp;
|
||||
|
||||
xcp=GWEN_INHERIT_GETDATA(AQH_HTTP_CONTENT, AQH_HTTP_CONTENT_FILES, cp);
|
||||
if (xcp) {
|
||||
if (xcp->footerData==NULL) {
|
||||
if (xcp->footerFilename) {
|
||||
int rv;
|
||||
GWEN_BUFFER *fileBuffer;
|
||||
|
||||
fileBuffer=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
rv=GWEN_SyncIo_Helper_ReadFile(xcp->footerFilename, fileBuffer);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error reading footer file \"%s\": %d", xcp->footerFilename, rv);
|
||||
GWEN_Buffer_free(fileBuffer);
|
||||
return rv;
|
||||
}
|
||||
xcp->footerData=strdup(GWEN_Buffer_GetStart(fileBuffer));
|
||||
GWEN_Buffer_free(fileBuffer);
|
||||
}
|
||||
if (xcp->footerData)
|
||||
GWEN_Buffer_AppendString(buffer, xcp->footerData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
34
aqhome/http/content_files.h
Normal file
34
aqhome/http/content_files.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_HTTP_CONTENT_FILES_H
|
||||
#define AQHOME_HTTP_CONTENT_FILES_H
|
||||
|
||||
|
||||
#include <aqhome/api.h>
|
||||
#include <aqhome/http/content.h>
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
AQHOME_API AQH_HTTP_CONTENT *AQH_HttpContentFiles_new(const char *name, const char *headerFilename, const char *footerFilename);
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
29
aqhome/http/content_files_p.h
Normal file
29
aqhome/http/content_files_p.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_HTTP_CONTENT_FILES_P_H
|
||||
#define AQHOME_HTTP_CONTENT_FILES_P_H
|
||||
|
||||
|
||||
#include "aqhome/http/content_files.h"
|
||||
|
||||
|
||||
|
||||
typedef struct AQH_HTTP_CONTENT_FILES AQH_HTTP_CONTENT_FILES;
|
||||
struct AQH_HTTP_CONTENT_FILES {
|
||||
char *headerFilename;
|
||||
char *footerFilename;
|
||||
|
||||
char *headerData;
|
||||
char *footerData;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
29
aqhome/http/content_p.h
Normal file
29
aqhome/http/content_p.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_HTTP_CONTENT_P_H
|
||||
#define AQHOME_HTTP_CONTENT_P_H
|
||||
|
||||
|
||||
#include "aqhome/http/content.h"
|
||||
|
||||
|
||||
struct AQH_HTTP_CONTENT {
|
||||
GWEN_INHERIT_ELEMENT(AQH_HTTP_CONTENT);
|
||||
GWEN_TREE2_ELEMENT(AQH_HTTP_CONTENT);
|
||||
|
||||
char *name;
|
||||
AQH_HTTP_CONTENT_ADD_OPENING_CONTENT_FN addOpeningContentFn;
|
||||
AQH_HTTP_CONTENT_ADD_CLOSING_CONTENT_FN addClosingContentFn;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -70,6 +70,7 @@ void AQH_HttpEndpoint_Extend(GWEN_MSG_ENDPOINT *ep, uint32_t flags)
|
||||
GWEN_NEW_OBJECT(AQH_ENDPOINT_HTTP, xep);
|
||||
GWEN_INHERIT_SETDATA(GWEN_MSG_ENDPOINT, AQH_ENDPOINT_HTTP, ep, xep, _freeData);
|
||||
xep->readMode=AQH_EndpointHttpd_ReadMode_Command;
|
||||
xep->flags=flags;
|
||||
|
||||
xep->addSocketsFn=GWEN_MsgEndpoint_SetAddSocketsFn(ep, _addSockets);
|
||||
xep->checkSocketsFn=GWEN_MsgEndpoint_SetCheckSocketsFn(ep, _checkSockets);
|
||||
@@ -325,7 +326,9 @@ int _distributeBufferInCommandMode(GWEN_MSG_ENDPOINT *ep, const uint8_t *bufferP
|
||||
_finishMessageAndStartNext(ep);
|
||||
return rv;
|
||||
}
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Command line complete, advancing to header read mode");
|
||||
DBG_INFO(AQH_LOGDOMAIN,
|
||||
"Command line complete, advancing to header read mode (start: %d)",
|
||||
GWEN_Buffer_GetPos(xep->currentReadBuffer));
|
||||
xep->readMode=AQH_EndpointHttpd_ReadMode_Headers;
|
||||
xep->currentHeaderPos=GWEN_Buffer_GetPos(xep->currentReadBuffer);
|
||||
}
|
||||
@@ -368,7 +371,7 @@ int _distributeBufferInHeaderMode(GWEN_MSG_ENDPOINT *ep, const uint8_t *bufferPt
|
||||
AQH_ENDPOINT_HTTP *xep;
|
||||
int lineLength;
|
||||
|
||||
/* line complete, TODO: parse status/command line */
|
||||
/* line complete, parse status/command line */
|
||||
rv=-rv;
|
||||
xep=GWEN_INHERIT_GETDATA(GWEN_MSG_ENDPOINT, AQH_ENDPOINT_HTTP, ep);
|
||||
|
||||
@@ -379,7 +382,7 @@ int _distributeBufferInHeaderMode(GWEN_MSG_ENDPOINT *ep, const uint8_t *bufferPt
|
||||
int contentLength;
|
||||
|
||||
/* Empty line received, TODO: parse header */
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Empty header line received, end of header reached.");
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Empty header line received, end of header reached (header pos: %d).", xep->currentHeaderPos);
|
||||
copyOfHeader=strdup(GWEN_Buffer_GetStart(xep->currentReadBuffer)+xep->currentHeaderPos);
|
||||
xep->dbCurrentReadHeader=GWEN_DB_Group_new("header");
|
||||
if (_parseHeader(copyOfHeader, xep->dbCurrentReadHeader)<0) {
|
||||
@@ -498,10 +501,14 @@ void _finishMessageAndStartNext(GWEN_MSG_ENDPOINT *ep)
|
||||
xep->dbCurrentReadCommand=NULL;
|
||||
xep->dbCurrentReadHeader=NULL;
|
||||
|
||||
if (xep->flags & AQH_ENDPOINT_HTTP_FLAGS_PASSIVE)
|
||||
if (xep->flags & AQH_ENDPOINT_HTTP_FLAGS_PASSIVE) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Passive connection");
|
||||
xep->readMode=AQH_EndpointHttpd_ReadMode_Command;
|
||||
else
|
||||
}
|
||||
else {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Active connection");
|
||||
xep->readMode=AQH_EndpointHttpd_ReadMode_Status;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -571,7 +578,7 @@ int _parseHeader(char *bufferPtr, GWEN_DB_NODE *db)
|
||||
p++;
|
||||
pVarEnd=p;
|
||||
if (*p!=':') {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "No separator after variable name in received header");
|
||||
DBG_INFO(AQH_LOGDOMAIN, "No separator after variable name in received header (var: [%s])", pVarBegin);
|
||||
return GWEN_ERROR_BAD_DATA;
|
||||
}
|
||||
*pVarEnd=0;
|
||||
|
||||
@@ -16,8 +16,7 @@
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
|
||||
|
||||
#define AQH_HTTP_REQUEST_SESSIONCOOKIE "sessionid"
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
GWEN_TREE2_FUNCTIONS(AQH_HTTP_REQUEST, AQH_HttpRequest);
|
||||
@@ -34,13 +33,13 @@ static int _inspectReceivedMessage(AQH_HTTP_REQUEST *rq, const GWEN_MSG *msg);
|
||||
static int _inspectMsgCommand(AQH_HTTP_REQUEST *rq, const GWEN_MSG *msg);
|
||||
static void _inspectMsgHeader(AQH_HTTP_REQUEST *rq, const GWEN_MSG *msg);
|
||||
static int _inspectMsgBody(AQH_HTTP_REQUEST *rq, const GWEN_MSG *msg);
|
||||
static void _setModuleNameFromUrl(AQH_HTTP_REQUEST *rq);
|
||||
static GWEN_DB_NODE *_extractCookies(GWEN_DB_NODE *dbHeader);
|
||||
static void _setCookieValue(GWEN_DB_NODE *dbCookies,
|
||||
const char *nameStart, int nameLen,
|
||||
const char *valueStart, int valueLen,
|
||||
uint32_t dbFlags);
|
||||
static int _parsePostBody(const char *s, int contentLength, GWEN_DB_NODE *dbBody);
|
||||
static int _unescapeUrlEncoded(const char *src, unsigned int srclen, char *buffer, unsigned int maxsize);
|
||||
|
||||
|
||||
|
||||
@@ -79,6 +78,7 @@ void AQH_HttpRequest_free(AQH_HTTP_REQUEST *rq)
|
||||
free(rq->moduleName);
|
||||
free(rq->responseText);
|
||||
GWEN_Msg_free(rq->responseMsg);
|
||||
GWEN_StringList_free(rq->urlPathMembers);
|
||||
GWEN_Url_free(rq->url);
|
||||
GWEN_DB_Group_free(rq->dbPostBody);
|
||||
|
||||
@@ -133,6 +133,30 @@ void AQH_HttpRequest_SetUrl(AQH_HTTP_REQUEST *rq, GWEN_URL *url)
|
||||
|
||||
|
||||
|
||||
const char *AQH_HttpRequest_GetUrlPath(const AQH_HTTP_REQUEST *rq)
|
||||
{
|
||||
return rq?(rq->urlPath):NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_STRINGLIST *AQH_HttpRequest_GetUrlPathMembers(const AQH_HTTP_REQUEST *rq)
|
||||
{
|
||||
return rq?(rq->urlPathMembers):NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_HttpRequest_SetUrlPathMembers(AQH_HTTP_REQUEST *rq, GWEN_STRINGLIST *sl)
|
||||
{
|
||||
if (rq) {
|
||||
GWEN_StringList_free(rq->urlPathMembers);
|
||||
rq->urlPathMembers=sl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_DB_NODE *AQH_HttpRequest_GetDbCommand(const AQH_HTTP_REQUEST *rq)
|
||||
{
|
||||
return rq?(rq->dbCommand):NULL;
|
||||
@@ -154,6 +178,13 @@ GWEN_DB_NODE *AQH_HttpRequest_GetDbCookies(const AQH_HTTP_REQUEST *rq)
|
||||
|
||||
|
||||
|
||||
GWEN_DB_NODE *AQH_HttpRequest_GetDbPostBody(const AQH_HTTP_REQUEST *rq)
|
||||
{
|
||||
return rq?(rq->dbPostBody):NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *AQH_HttpRequest_GetSessionId(const AQH_HTTP_REQUEST *rq)
|
||||
{
|
||||
return rq?(rq->sessionId):NULL;
|
||||
@@ -296,6 +327,27 @@ void AQH_HttpRequest_SetResponseMsg(AQH_HTTP_REQUEST *rq, GWEN_MSG *msg)
|
||||
|
||||
|
||||
|
||||
void AQH_HttpRequest_SetupUrlPathMembers(AQH_HTTP_REQUEST *rq)
|
||||
{
|
||||
const char *path;
|
||||
|
||||
path=AQH_HttpRequest_GetUrlPath(rq);
|
||||
if (path && *path) {
|
||||
GWEN_STRINGLIST *sl;
|
||||
|
||||
if (*path=='/') /* skip leading slash */
|
||||
path++;
|
||||
sl=GWEN_StringList_fromString(path, "/", 0);
|
||||
if (sl==NULL) {
|
||||
DBG_ERROR(NULL, "Empty url path member list");
|
||||
}
|
||||
else
|
||||
AQH_HttpRequest_SetUrlPathMembers(rq, sl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _inspectReceivedMessage(AQH_HTTP_REQUEST *rq, const GWEN_MSG *msg)
|
||||
{
|
||||
int rv;
|
||||
@@ -384,7 +436,12 @@ int _inspectMsgCommand(AQH_HTTP_REQUEST *rq, const GWEN_MSG *msg)
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
_setModuleNameFromUrl(rq);
|
||||
s=GWEN_Url_GetPath(rq->url);
|
||||
if (!(s && *s)) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Empty url in request, assuming \"/\"");
|
||||
s="/";
|
||||
}
|
||||
rq->urlPath=s;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -399,9 +456,11 @@ void _inspectMsgHeader(AQH_HTTP_REQUEST *rq, const GWEN_MSG *msg)
|
||||
const char *s;
|
||||
|
||||
s=GWEN_DB_GetCharValue(rq->dbCookies, AQH_HTTP_REQUEST_SESSIONCOOKIE, 0, NULL);
|
||||
if (s && *s)
|
||||
if (s && *s) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Sessionid: %s", s);
|
||||
AQH_HttpRequest_SetSessionId(rq, s);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -419,7 +478,7 @@ int _inspectMsgBody(AQH_HTTP_REQUEST *rq, const GWEN_MSG *msg)
|
||||
const char *s;
|
||||
|
||||
/* check whether we need to parse POST body */
|
||||
s=GWEN_DB_GetCharValue(rq->dbCommand, "content-type", 0, NULL);
|
||||
s=GWEN_DB_GetCharValue(rq->dbHeader, "content-type", 0, NULL);
|
||||
if (s && strcasecmp(s, "application/x-www-form-urlencoded")==0) {
|
||||
rq->dbPostBody=GWEN_DB_Group_new("post");
|
||||
rv=_parsePostBody((const char*) (rq->recvdBodyPtr), rq->recvdBodySize, rq->dbPostBody);
|
||||
@@ -519,34 +578,6 @@ void _setCookieValue(GWEN_DB_NODE *dbCookies, const char *nameStart, int nameLen
|
||||
|
||||
|
||||
|
||||
void _setModuleNameFromUrl(AQH_HTTP_REQUEST *rq)
|
||||
{
|
||||
if (rq->url) {
|
||||
const char *sPath;
|
||||
|
||||
sPath=GWEN_Url_GetPath(rq->url);
|
||||
if (sPath && *sPath) {
|
||||
if (*sPath=='/')
|
||||
sPath++;
|
||||
while(*sPath && *sPath<33)
|
||||
sPath++;
|
||||
if (*sPath) {
|
||||
const char *s;
|
||||
|
||||
s=sPath;
|
||||
while(*s && *s!='/')
|
||||
s++;
|
||||
if (s>sPath) {
|
||||
free(rq->moduleName);
|
||||
rq->moduleName=GWEN_Text_strndup(sPath, s-sPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _parsePostBody(const char *s, int contentLength, GWEN_DB_NODE *dbBody)
|
||||
{
|
||||
while(contentLength>0) {
|
||||
@@ -569,6 +600,7 @@ int _parsePostBody(const char *s, int contentLength, GWEN_DB_NODE *dbBody)
|
||||
int valueLen;
|
||||
|
||||
s++;
|
||||
contentLength--;
|
||||
while((contentLength>0) && (*s<33)) {
|
||||
s++;
|
||||
contentLength--;
|
||||
@@ -584,22 +616,111 @@ int _parsePostBody(const char *s, int contentLength, GWEN_DB_NODE *dbBody)
|
||||
char sNameBuf[32];
|
||||
char sValueBuf[64];
|
||||
|
||||
if (GWEN_Text_UnescapeN(sNameStart, nameLen, sNameBuf, sizeof(sNameBuf))!=NULL &&
|
||||
GWEN_Text_UnescapeN(sValueStart, valueLen, sValueBuf, sizeof(sValueBuf))!=NULL)
|
||||
if (_unescapeUrlEncoded(sNameStart, nameLen, sNameBuf, sizeof(sNameBuf))>=0 &&
|
||||
_unescapeUrlEncoded(sValueStart, valueLen, sValueBuf, sizeof(sValueBuf))>=0)
|
||||
GWEN_DB_SetCharValue(dbBody, 0, sNameBuf, sValueBuf);
|
||||
else {
|
||||
DBG_ERROR(NULL, "Either name or value invalid in body, aborting");
|
||||
return GWEN_ERROR_BAD_DATA;
|
||||
}
|
||||
}
|
||||
if ((contentLength>0) && (*s=='&'))
|
||||
if ((contentLength>0) && (*s=='&')) {
|
||||
contentLength--;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
} /* while */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _unescapeUrlEncoded(const char *src, unsigned int srclen, char *buffer, unsigned int maxsize)
|
||||
{
|
||||
unsigned int size;
|
||||
|
||||
size=0;
|
||||
|
||||
while (*src && srclen>0) {
|
||||
unsigned char x;
|
||||
|
||||
x=(unsigned char)*src;
|
||||
if (
|
||||
(x>='A' && x<='Z') ||
|
||||
(x>='a' && x<='z') ||
|
||||
(x>='0' && x<='9') ||
|
||||
x==' ' ||
|
||||
x=='.' ||
|
||||
x==',' ||
|
||||
x=='.' ||
|
||||
x=='*' ||
|
||||
x=='?' ||
|
||||
x=='+'
|
||||
) {
|
||||
if (size<(maxsize-1)) {
|
||||
buffer[size++]=(x=='+')?' ':x;
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(GWEN_LOGDOMAIN, "Buffer too small");
|
||||
return GWEN_ERROR_BUFFER_OVERFLOW;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (*src=='%') {
|
||||
unsigned char d1, d2;
|
||||
unsigned char c;
|
||||
|
||||
if (srclen<3) {
|
||||
DBG_ERROR(GWEN_LOGDOMAIN, "Incomplete escape sequence (EOLN met)");
|
||||
return GWEN_ERROR_BAD_DATA;
|
||||
}
|
||||
/* skip '%' */
|
||||
src++;
|
||||
if (!(*src) || !isxdigit((int)*src)) {
|
||||
DBG_ERROR(GWEN_LOGDOMAIN, "Incomplete escape sequence (no digits)");
|
||||
return GWEN_ERROR_BAD_DATA;
|
||||
}
|
||||
/* read first digit */
|
||||
d1=(unsigned char)(toupper(*src));
|
||||
|
||||
/* get second digit */
|
||||
src++;
|
||||
if (!(*src) || !isxdigit((int)*src)) {
|
||||
DBG_ERROR(GWEN_LOGDOMAIN, "Incomplete escape sequence (only 1 digit)");
|
||||
return GWEN_ERROR_BAD_DATA;
|
||||
}
|
||||
d2=(unsigned char)(toupper(*src));
|
||||
/* compute character */
|
||||
d1-='0';
|
||||
if (d1>9)
|
||||
d1-=7;
|
||||
c=(d1<<4)&0xf0;
|
||||
d2-='0';
|
||||
if (d2>9)
|
||||
d2-=7;
|
||||
c+=(d2&0xf);
|
||||
/* store character */
|
||||
if (size<(maxsize-1))
|
||||
buffer[size++]=(char)c;
|
||||
else {
|
||||
DBG_ERROR(GWEN_LOGDOMAIN, "Buffer too small");
|
||||
return GWEN_ERROR_BUFFER_OVERFLOW;
|
||||
}
|
||||
srclen-=2;
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(GWEN_LOGDOMAIN, "Found non-alphanum characters in escaped string (\"%s\")", src);
|
||||
return GWEN_ERROR_BAD_DATA;
|
||||
}
|
||||
}
|
||||
srclen--;
|
||||
src++;
|
||||
} /* while */
|
||||
|
||||
buffer[size]=0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include <gwenhywfar/url.h>
|
||||
|
||||
|
||||
#define AQH_HTTP_REQUEST_SESSIONCOOKIE "sessionid"
|
||||
|
||||
|
||||
typedef struct AQH_HTTP_REQUEST AQH_HTTP_REQUEST;
|
||||
GWEN_TREE2_FUNCTION_LIB_DEFS(AQH_HTTP_REQUEST, AQH_HttpRequest, AQHOME_API);
|
||||
@@ -37,9 +39,15 @@ AQHOME_API const char *AQH_HttpRequest_GetProtocol(const AQH_HTTP_REQUEST *rq);
|
||||
AQHOME_API GWEN_URL *AQH_HttpRequest_GetUrl(const AQH_HTTP_REQUEST *rq);
|
||||
AQHOME_API void AQH_HttpRequest_SetUrl(AQH_HTTP_REQUEST *rq, GWEN_URL *url);
|
||||
|
||||
AQHOME_API const char *AQH_HttpRequest_GetUrlPath(const AQH_HTTP_REQUEST *rq);
|
||||
|
||||
AQHOME_API GWEN_STRINGLIST *AQH_HttpRequest_GetUrlPathMembers(const AQH_HTTP_REQUEST *rq);
|
||||
AQHOME_API void AQH_HttpRequest_SetUrlPathMembers(AQH_HTTP_REQUEST *rq, GWEN_STRINGLIST *sl);
|
||||
|
||||
AQHOME_API GWEN_DB_NODE *AQH_HttpRequest_GetDbCommand(const AQH_HTTP_REQUEST *rq);
|
||||
AQHOME_API GWEN_DB_NODE *AQH_HttpRequest_GetDbHeader(const AQH_HTTP_REQUEST *rq);
|
||||
AQHOME_API GWEN_DB_NODE *AQH_HttpRequest_GetDbCookies(const AQH_HTTP_REQUEST *rq);
|
||||
AQHOME_API GWEN_DB_NODE *AQH_HttpRequest_GetDbPostBody(const AQH_HTTP_REQUEST *rq);
|
||||
|
||||
|
||||
AQHOME_API const char *AQH_HttpRequest_GetSessionId(const AQH_HTTP_REQUEST *rq);
|
||||
@@ -68,6 +76,7 @@ AQHOME_API GWEN_MSG *AQH_HttpRequest_GetResponseMsg(const AQH_HTTP_REQUEST *rq);
|
||||
AQHOME_API GWEN_MSG *AQH_HttpRequest_TakeResponseMsg(AQH_HTTP_REQUEST *rq);
|
||||
AQHOME_API void AQH_HttpRequest_SetResponseMsg(AQH_HTTP_REQUEST *rq, GWEN_MSG *msg);
|
||||
|
||||
AQHOME_API void AQH_HttpRequest_SetupUrlPathMembers(AQH_HTTP_REQUEST *rq);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -25,8 +25,11 @@ struct AQH_HTTP_REQUEST {
|
||||
|
||||
const char *command; /* don't free */
|
||||
const char *protocol; /* don't free */
|
||||
const char *urlPath; /* don't free */
|
||||
GWEN_URL *url;
|
||||
|
||||
GWEN_STRINGLIST *urlPathMembers;
|
||||
|
||||
GWEN_DB_NODE *dbCommand; /* don't free */
|
||||
GWEN_DB_NODE *dbHeader; /* don't free */
|
||||
GWEN_DB_NODE *dbCookies; /* don't free */
|
||||
|
||||
@@ -28,16 +28,34 @@ static void GWENHYWFAR_CB _freeData(void *bp, void *p);
|
||||
|
||||
|
||||
|
||||
void AQH_HttpService_Extend(AQH_SERVICE *sv)
|
||||
AQH_SERVICE *AQH_HttpService_new(const char *configFolder, const char *sourceFolder)
|
||||
{
|
||||
AQH_SERVICE *sv;
|
||||
|
||||
sv=AQH_Service_new();
|
||||
AQH_HttpService_Extend(sv, configFolder, sourceFolder);
|
||||
|
||||
return sv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_HttpService_Extend(AQH_SERVICE *sv, const char *configFolder, const char *sourceFolder)
|
||||
{
|
||||
AQH_HTTP_SERVICE *xsv;
|
||||
|
||||
GWEN_NEW_OBJECT(AQH_HTTP_SERVICE, xsv);
|
||||
GWEN_INHERIT_SETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv, xsv, _freeData);
|
||||
|
||||
AQH_HttpService_SetConfigFolder(sv, configFolder);
|
||||
AQH_HttpService_SetSourceFolder(sv, sourceFolder);
|
||||
|
||||
xsv->moduleMutex=GWEN_Mutex_new();
|
||||
xsv->userMutex=GWEN_Mutex_new();
|
||||
xsv->sessionMutex=GWEN_Mutex_new();
|
||||
|
||||
xsv->urlHandlerList=AQH_HttpUrlHandler_List_new(sv);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +66,8 @@ void _freeData(void *bp, void *p)
|
||||
|
||||
xsv=(AQH_HTTP_SERVICE*) p;
|
||||
|
||||
AQH_HttpUrlHandler_List_free(xsv->urlHandlerList);
|
||||
|
||||
GWEN_Mutex_free(xsv->moduleMutex);
|
||||
GWEN_Mutex_free(xsv->userMutex);
|
||||
GWEN_Mutex_free(xsv->sessionMutex);
|
||||
@@ -61,25 +81,6 @@ void _freeData(void *bp, void *p)
|
||||
|
||||
|
||||
|
||||
AQH_HTTP_SERVICE_HANDLEREQUEST_FN AQH_HttpService_SetHandleRequestFn(AQH_SERVICE *sv, AQH_HTTP_SERVICE_HANDLEREQUEST_FN fn)
|
||||
{
|
||||
if (sv) {
|
||||
AQH_HTTP_SERVICE *xsv;
|
||||
|
||||
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv);
|
||||
if (xsv) {
|
||||
AQH_HTTP_SERVICE_HANDLEREQUEST_FN oldFn;
|
||||
|
||||
oldFn=xsv->handleRequestFn;
|
||||
xsv->handleRequestFn=fn;
|
||||
return oldFn;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *AQH_HttpService_GetConfigFolder(const AQH_SERVICE *sv)
|
||||
{
|
||||
if (sv) {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "aqhome/service/service.h"
|
||||
|
||||
#include "aqhome/http/httprequest.h"
|
||||
#include "aqhome/http/urlhandler.h"
|
||||
|
||||
#include <gwenhywfar/msg.h>
|
||||
#include <gwenhywfar/db.h>
|
||||
@@ -23,10 +24,9 @@
|
||||
|
||||
|
||||
|
||||
typedef int (*AQH_HTTP_SERVICE_HANDLEREQUEST_FN)(AQH_SERVICE *sv, AQH_HTTP_REQUEST *request);
|
||||
|
||||
|
||||
AQHOME_API void AQH_HttpService_Extend(AQH_SERVICE *sv);
|
||||
AQHOME_API AQH_SERVICE *AQH_HttpService_new(const char *configFolder, const char *sourceFolder);
|
||||
AQHOME_API void AQH_HttpService_Extend(AQH_SERVICE *sv, const char *configFolder, const char *sourceFolder);
|
||||
|
||||
|
||||
AQHOME_API const char *AQH_HttpService_GetConfigFolder(const AQH_SERVICE *sv);
|
||||
@@ -51,9 +51,6 @@ AQHOME_API int AQH_HttpService_GetMaxSessionAgeInSecs(const AQH_SERVICE *sv);
|
||||
AQHOME_API void AQH_HttpService_SetMaxSessionAgeInSecs(AQH_SERVICE *sv, int i);
|
||||
|
||||
|
||||
AQHOME_API AQH_HTTP_SERVICE_HANDLEREQUEST_FN AQH_HttpService_SetHandleRequestFn(AQH_SERVICE *sv, AQH_HTTP_SERVICE_HANDLEREQUEST_FN fn);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ int AQH_HttpService_LoadConfig(AQH_SERVICE *sv)
|
||||
db=GWEN_DB_Group_new("service");
|
||||
|
||||
nameBuf=_getConfigFilePath(sv, AQH_HTTP_SERVICE_FILE_CONFIG);
|
||||
rv=GWEN_DB_ReadFile(db, GWEN_Buffer_GetStart(nameBuf), GWEN_DB_FLAGS_DEFAULT | GWEN_DB_FLAGS_LOCKFILE);
|
||||
rv=GWEN_DB_ReadFile(db, GWEN_Buffer_GetStart(nameBuf), GWEN_DB_FLAGS_DEFAULT);
|
||||
if (rv<0) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||
GWEN_Buffer_free(nameBuf);
|
||||
@@ -206,6 +206,42 @@ AQH_USER *AQH_HttpService_GetUser(AQH_SERVICE *sv, const char *alias)
|
||||
|
||||
|
||||
|
||||
int AQH_HttpService_WriteUser(const AQH_SERVICE *sv, const AQH_USER *user)
|
||||
{
|
||||
AQH_HTTP_SERVICE *xsv;
|
||||
int rv;
|
||||
|
||||
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv);
|
||||
if (xsv==NULL) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Not a AQH_HttpService object");
|
||||
return GWEN_ERROR_INVALID;
|
||||
}
|
||||
|
||||
rv=GWEN_Mutex_Lock(xsv->userMutex);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error obtaining lock on user mutex");
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv=AQH_HttpService_SaveUser(sv, user);
|
||||
if (rv<0) {
|
||||
GWEN_Mutex_Unlock(xsv->userMutex);
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error saving user \"%s\" (%d)", AQH_User_GetAlias(user), rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv=GWEN_Mutex_Unlock(xsv->userMutex);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error releasing lock on user mutex");
|
||||
return rv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
AQH_SESSION *AQH_HttpService_GetSession(AQH_SERVICE *sv, const char *sessionUid)
|
||||
{
|
||||
AQH_HTTP_SERVICE *xsv;
|
||||
@@ -255,7 +291,7 @@ AQH_MODULE *AQH_HttpService_LoadModule(const AQH_SERVICE *sv, const char *modNam
|
||||
db=GWEN_DB_Group_new("user");
|
||||
|
||||
nameBuf=_getModuleFilePath(sv, modName);
|
||||
rv=GWEN_DB_ReadFile(db, GWEN_Buffer_GetStart(nameBuf), GWEN_DB_FLAGS_DEFAULT | GWEN_DB_FLAGS_LOCKFILE);
|
||||
rv=GWEN_DB_ReadFile(db, GWEN_Buffer_GetStart(nameBuf), GWEN_DB_FLAGS_DEFAULT);
|
||||
if (rv<0) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||
GWEN_Buffer_free(nameBuf);
|
||||
@@ -368,7 +404,7 @@ AQH_USER *AQH_HttpService_LoadUser(const AQH_SERVICE *sv, const char *userAlias)
|
||||
db=GWEN_DB_Group_new("user");
|
||||
|
||||
nameBuf=_getUserFilePath(sv, userAlias);
|
||||
rv=GWEN_DB_ReadFile(db, GWEN_Buffer_GetStart(nameBuf), GWEN_DB_FLAGS_DEFAULT | GWEN_DB_FLAGS_LOCKFILE);
|
||||
rv=GWEN_DB_ReadFile(db, GWEN_Buffer_GetStart(nameBuf), GWEN_DB_FLAGS_DEFAULT);
|
||||
if (rv<0) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||
GWEN_Buffer_free(nameBuf);
|
||||
@@ -488,7 +524,7 @@ AQH_SESSION *AQH_HttpService_LoadSession(const AQH_SERVICE *sv, const char *sess
|
||||
db=GWEN_DB_Group_new("user");
|
||||
|
||||
nameBuf=_getSessionFilePath(sv, sessionUid);
|
||||
rv=GWEN_DB_ReadFile(db, GWEN_Buffer_GetStart(nameBuf), GWEN_DB_FLAGS_DEFAULT | GWEN_DB_FLAGS_LOCKFILE);
|
||||
rv=GWEN_DB_ReadFile(db, GWEN_Buffer_GetStart(nameBuf), GWEN_DB_FLAGS_DEFAULT);
|
||||
if (rv<0) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||
GWEN_Buffer_free(nameBuf);
|
||||
@@ -679,8 +715,8 @@ GWEN_BUFFER *_getConfigFilePath(const AQH_SERVICE *sv, const char *fileName)
|
||||
|
||||
nameBuf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
GWEN_Buffer_AppendString(nameBuf, configFolder);
|
||||
GWEN_Buffer_AppendString(nameBuf, GWEN_DIR_SEPARATOR_S AQH_HTTP_SERVICE_DIR_SESSIONS GWEN_DIR_SEPARATOR_S);
|
||||
GWEN_Text_EscapeToBuffer(fileName, nameBuf);
|
||||
GWEN_Buffer_AppendString(nameBuf, GWEN_DIR_SEPARATOR_S);
|
||||
GWEN_Buffer_AppendString(nameBuf, fileName);
|
||||
return nameBuf;
|
||||
}
|
||||
}
|
||||
@@ -958,7 +994,7 @@ int _writeDbFile(const char *fname, GWEN_DB_NODE *db)
|
||||
GWEN_Buffer_AppendString(tmpFilenameBuf, fname);
|
||||
GWEN_Buffer_AppendString(tmpFilenameBuf, ".tmp");
|
||||
unlink(GWEN_Buffer_GetStart(tmpFilenameBuf));
|
||||
rv=GWEN_DB_WriteFile(db, GWEN_Buffer_GetStart(tmpFilenameBuf), GWEN_DB_FLAGS_DEFAULT | GWEN_DB_FLAGS_LOCKFILE);
|
||||
rv=GWEN_DB_WriteFile(db, GWEN_Buffer_GetStart(tmpFilenameBuf), GWEN_DB_FLAGS_DEFAULT);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error writing db file \"%s\": %d", GWEN_Buffer_GetStart(tmpFilenameBuf), rv);
|
||||
GWEN_Buffer_free(tmpFilenameBuf);
|
||||
|
||||
@@ -19,27 +19,34 @@
|
||||
#include <gwenhywfar/url.h>
|
||||
|
||||
|
||||
int AQH_HttpService_LoadConfig(AQH_SERVICE *sv);
|
||||
int AQH_HttpService_SaveConfig(const AQH_SERVICE *sv);
|
||||
|
||||
AQH_MODULE *AQH_HttpService_GetModule(AQH_SERVICE *sv, const char *modName);
|
||||
AQH_USER *AQH_HttpService_GetUser(AQH_SERVICE *sv, const char *alias);
|
||||
AQH_SESSION *AQH_HttpService_GetSession(AQH_SERVICE *sv, const char *sessionUid);
|
||||
#define AQH_HTTP_SERVICE_ADMINUSER "admin"
|
||||
|
||||
|
||||
AQH_MODULE *AQH_HttpService_LoadModule(const AQH_SERVICE *sv, const char *modName);
|
||||
int AQH_HttpService_SaveModule(const AQH_SERVICE *sv, const AQH_MODULE *m);
|
||||
int AQH_HttpService_AddModule(AQH_SERVICE *sv, AQH_MODULE *m);
|
||||
|
||||
AQH_USER *AQH_HttpService_LoadUser(const AQH_SERVICE *sv, const char *userAlias);
|
||||
int AQH_HttpService_SaveUser(const AQH_SERVICE *sv, const AQH_USER *user);
|
||||
int AQH_HttpService_AddUser(AQH_SERVICE *sv, AQH_USER *user);
|
||||
int AQH_HttpService_DelUser(AQH_SERVICE *sv, AQH_USER *user);
|
||||
AQHOME_API int AQH_HttpService_LoadConfig(AQH_SERVICE *sv);
|
||||
AQHOME_API int AQH_HttpService_SaveConfig(const AQH_SERVICE *sv);
|
||||
|
||||
AQH_SESSION *AQH_HttpService_LoadSession(const AQH_SERVICE *sv, const char *sessionUid);
|
||||
int AQH_HttpService_SaveSession(const AQH_SERVICE *sv, const AQH_SESSION *session);
|
||||
int AQH_HttpService_AddSession(AQH_SERVICE *sv, AQH_SESSION *session);
|
||||
int AQH_HttpService_DelSession(AQH_SERVICE *sv, AQH_SESSION *session);
|
||||
AQHOME_API AQH_MODULE *AQH_HttpService_GetModule(AQH_SERVICE *sv, const char *modName);
|
||||
AQHOME_API AQH_USER *AQH_HttpService_GetUser(AQH_SERVICE *sv, const char *alias);
|
||||
AQHOME_API int AQH_HttpService_WriteUser(const AQH_SERVICE *sv, const AQH_USER *user);
|
||||
|
||||
AQHOME_API AQH_SESSION *AQH_HttpService_GetSession(AQH_SERVICE *sv, const char *sessionUid);
|
||||
|
||||
|
||||
AQHOME_API AQH_MODULE *AQH_HttpService_LoadModule(const AQH_SERVICE *sv, const char *modName);
|
||||
AQHOME_API int AQH_HttpService_SaveModule(const AQH_SERVICE *sv, const AQH_MODULE *m);
|
||||
AQHOME_API int AQH_HttpService_AddModule(AQH_SERVICE *sv, AQH_MODULE *m);
|
||||
|
||||
AQHOME_API AQH_USER *AQH_HttpService_LoadUser(const AQH_SERVICE *sv, const char *userAlias);
|
||||
AQHOME_API int AQH_HttpService_SaveUser(const AQH_SERVICE *sv, const AQH_USER *user);
|
||||
AQHOME_API int AQH_HttpService_AddUser(AQH_SERVICE *sv, AQH_USER *user);
|
||||
AQHOME_API int AQH_HttpService_DelUser(AQH_SERVICE *sv, AQH_USER *user);
|
||||
|
||||
AQHOME_API AQH_SESSION *AQH_HttpService_LoadSession(const AQH_SERVICE *sv, const char *sessionUid);
|
||||
AQHOME_API int AQH_HttpService_SaveSession(const AQH_SERVICE *sv, const AQH_SESSION *session);
|
||||
AQHOME_API int AQH_HttpService_AddSession(AQH_SERVICE *sv, AQH_SESSION *session);
|
||||
AQHOME_API int AQH_HttpService_DelSession(AQH_SERVICE *sv, AQH_SESSION *session);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "aqhome/http/httpservice_http.h"
|
||||
#include "aqhome/http/httpservice_conf.h"
|
||||
#include "aqhome/http/httpservice_p.h"
|
||||
#include "aqhome/http/urlhandler.h"
|
||||
|
||||
#include <gwenhywfar/db.h>
|
||||
#include <gwenhywfar/buffer.h>
|
||||
@@ -37,7 +38,7 @@
|
||||
|
||||
static void _writeDefaultResponseHeaderToBuffer(AQH_SERVICE *sv, int contentLength, GWEN_BUFFER *buf);
|
||||
static GWEN_BUFFER *_getPageFilePath(const AQH_SERVICE *sv, const char *langFolder, const char *fileName);
|
||||
static void _setRequestPerms(AQH_SERVICE *sv, AQH_HTTP_REQUEST *rq);
|
||||
static AQH_HTTP_URLHANDLER *_findMatchingUrlHandler(AQH_SERVICE *sv, const char *path);
|
||||
|
||||
|
||||
|
||||
@@ -52,10 +53,12 @@ GWEN_MSG *AQH_HttpService_HandleHttpRequest(AQH_SERVICE *sv, GWEN_MSG_ENDPOINT *
|
||||
AQH_HTTP_SERVICE *xsv;
|
||||
AQH_HTTP_REQUEST *rq;
|
||||
const char *s;
|
||||
AQH_MODULE *m=NULL;
|
||||
const char *cmd;
|
||||
const char *protocol;
|
||||
AQH_SESSION *session=NULL;
|
||||
GWEN_MSG *msgResponse;
|
||||
int rv;
|
||||
AQH_HTTP_URLHANDLER *uh;
|
||||
|
||||
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv);
|
||||
if (xsv==NULL) {
|
||||
@@ -63,17 +66,16 @@ GWEN_MSG *AQH_HttpService_HandleHttpRequest(AQH_SERVICE *sv, GWEN_MSG_ENDPOINT *
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (xsv->handleRequestFn==NULL) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "No request handler set");
|
||||
return AQH_HttpService_CreateResponseMsg(sv, 500, "Internal server error", "HTTP/1.1");
|
||||
}
|
||||
|
||||
rq=AQH_HttpRequest_new(endpoint, msgReceived);
|
||||
if (rq==NULL) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Could not create valie request from incoming message");
|
||||
return AQH_HttpService_CreateResponseMsg(sv, 500, "Internal server error", "HTTP/1.1");
|
||||
return AQH_HttpService_CreateResponseMsg(sv, 500, "Internal server error", "HTTP/1.1", NULL);
|
||||
}
|
||||
|
||||
cmd=AQH_HttpRequest_GetCommand(rq);
|
||||
protocol=AQH_HttpRequest_GetProtocol(rq);
|
||||
|
||||
#if 0
|
||||
s=AQH_HttpRequest_GetModuleName(rq);
|
||||
if (s && *s) {
|
||||
m=AQH_HttpService_GetModule(sv, s);
|
||||
@@ -83,6 +85,7 @@ GWEN_MSG *AQH_HttpService_HandleHttpRequest(AQH_SERVICE *sv, GWEN_MSG_ENDPOINT *
|
||||
else
|
||||
AQH_HttpRequest_SetModule(rq, m);
|
||||
}
|
||||
#endif
|
||||
|
||||
s=AQH_HttpRequest_GetSessionId(rq);
|
||||
if (s && *s) {
|
||||
@@ -91,17 +94,25 @@ GWEN_MSG *AQH_HttpService_HandleHttpRequest(AQH_SERVICE *sv, GWEN_MSG_ENDPOINT *
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Session \"%s\" not found", s);
|
||||
}
|
||||
else {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Found session \"%s\"", s);
|
||||
AQH_HttpRequest_SetSession(rq, session);
|
||||
}
|
||||
}
|
||||
|
||||
_setRequestPerms(sv, rq);
|
||||
s=AQH_HttpRequest_GetUrlPath(rq);
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Received \"%s\" request for url \"%s\"", cmd?cmd:"<no cmd>", s);
|
||||
uh=_findMatchingUrlHandler(sv, s);
|
||||
if (uh==NULL) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "No matching handler found for url \"%s\"", s);
|
||||
AQH_HttpRequest_free(rq);
|
||||
return AQH_HttpService_CreateResponseMsg(sv, 404, "Not found", protocol?protocol:"http/1.1", NULL);
|
||||
}
|
||||
|
||||
rv=xsv->handleRequestFn(sv, rq);
|
||||
rv=AQH_HttpUrlHandler_HandleMessage(uh, rq);
|
||||
if (rv<0) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Error handling request");
|
||||
AQH_HttpRequest_free(rq);
|
||||
return AQH_HttpService_CreateResponseMsg(sv, 500, "Internal server error", "http/1.1");
|
||||
return AQH_HttpService_CreateResponseMsg(sv, 500, "Internal server error", protocol?protocol:"http/1.1", NULL);
|
||||
}
|
||||
msgResponse=AQH_HttpRequest_TakeResponseMsg(rq);
|
||||
AQH_HttpRequest_free(rq);
|
||||
@@ -110,6 +121,68 @@ GWEN_MSG *AQH_HttpService_HandleHttpRequest(AQH_SERVICE *sv, GWEN_MSG_ENDPOINT *
|
||||
|
||||
|
||||
|
||||
void AQH_HttpService_AddUrlHandler(AQH_SERVICE *sv, AQH_HTTP_URLHANDLER *urlHandler)
|
||||
{
|
||||
AQH_HTTP_SERVICE *xsv;
|
||||
|
||||
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv);
|
||||
if (xsv==NULL) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Not a AQH_HttpService object");
|
||||
}
|
||||
else {
|
||||
AQH_HttpUrlHandler_List_Add(urlHandler, xsv->urlHandlerList);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_HttpService_SetRequestPerms(AQH_SERVICE *sv, AQH_HTTP_REQUEST *rq)
|
||||
{
|
||||
AQH_MODULE *m;
|
||||
AQH_SESSION *session;
|
||||
|
||||
AQH_HttpRequest_SetModulePerms(rq, 0);
|
||||
m=AQH_HttpRequest_GetModule(rq);
|
||||
session=AQH_HttpRequest_GetSession(rq);
|
||||
if (m) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Presetting module's guest perms");
|
||||
AQH_HttpRequest_SetModulePerms(rq, AQH_Module_GetGuestPerms(m));
|
||||
if (session) {
|
||||
AQH_USER * user;
|
||||
|
||||
user=AQH_Session_GetUser(session);
|
||||
if (user) {
|
||||
AQH_MODULE_PERMS_LIST *permsList;
|
||||
|
||||
permsList=AQH_User_GetModulePermList(user);
|
||||
if (permsList) {
|
||||
AQH_MODULE_PERMS *userPerms;
|
||||
|
||||
userPerms=AQH_ModulePerms_List_GetByModuleId(AQH_User_GetModulePermList(user), AQH_Module_GetId(m));
|
||||
if (userPerms) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Using user perms for module");
|
||||
AQH_HttpRequest_SetModulePerms(rq, AQH_ModulePerms_GetPerms(userPerms));
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "No module perms list in user, using module's guest perms");
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Session but no user, SNH!");
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "No session, using module's guest perms");
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "No module, no perms");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_HttpService_AddStatusLine(AQH_SERVICE *sv, int code, const char *msg, const char *proto, GWEN_BUFFER *buf)
|
||||
{
|
||||
GWEN_Buffer_AppendArgs(buf, "%s %03d %s \r\n", proto?proto:"HTTP/1.1", code, msg?msg:"");
|
||||
@@ -163,14 +236,40 @@ void AQH_HttpService_AddHeader(AQH_SERVICE *sv, GWEN_DB_NODE *dbHeader, GWEN_BUF
|
||||
|
||||
|
||||
|
||||
GWEN_MSG *AQH_HttpService_CreateResponseMsg(AQH_SERVICE *sv, int code, const char *text, const char *protocol)
|
||||
GWEN_MSG *AQH_HttpService_CreateResponseMsg(AQH_SERVICE *sv, int code, const char *text, const char *protocol, const char *page)
|
||||
{
|
||||
GWEN_BUFFER *buf;
|
||||
GWEN_MSG *msg;
|
||||
|
||||
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
AQH_HttpService_AddStatusLine(sv, code, text, protocol, buf);
|
||||
_writeDefaultResponseHeaderToBuffer(sv, 0, buf);
|
||||
_writeDefaultResponseHeaderToBuffer(sv, (page && *page)?strlen(page):0, buf);
|
||||
|
||||
if (page && *page)
|
||||
GWEN_Buffer_AppendString(buf, page);
|
||||
|
||||
msg=GWEN_Msg_fromBytes((const uint8_t*)GWEN_Buffer_GetStart(buf), GWEN_Buffer_GetUsedBytes(buf));
|
||||
GWEN_Buffer_free(buf);
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_MSG *AQH_HttpService_CreateRedirectingResponseMsg(AQH_SERVICE *sv, const char *protocol, const char *newPage)
|
||||
{
|
||||
GWEN_BUFFER *buf;
|
||||
GWEN_MSG *msg;
|
||||
GWEN_DB_NODE *db;
|
||||
|
||||
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
AQH_HttpService_AddStatusLine(sv, 303, "OK, redirecting to content", protocol, buf);
|
||||
db=GWEN_DB_Group_new("header");
|
||||
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Connection", "Keep-Alive");
|
||||
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Content-Type", "text/html; charset=utf-8");
|
||||
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Location", newPage);
|
||||
GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Content-Length", 0);
|
||||
AQH_HttpService_AddHeader(sv, db, buf);
|
||||
GWEN_DB_Group_free(db);
|
||||
|
||||
msg=GWEN_Msg_fromBytes((const uint8_t*)GWEN_Buffer_GetStart(buf), GWEN_Buffer_GetUsedBytes(buf));
|
||||
GWEN_Buffer_free(buf);
|
||||
@@ -201,6 +300,39 @@ int AQH_HttpService_AddFile(AQH_SERVICE *sv, GWEN_UNUSED AQH_SESSION *session, c
|
||||
|
||||
|
||||
|
||||
void AQH_HttpService_SetupModuleAndPerms(AQH_SERVICE *sv, AQH_HTTP_REQUEST *rq, const char *modulName)
|
||||
{
|
||||
AQH_SESSION *session;
|
||||
AQH_MODULE *m;
|
||||
|
||||
AQH_HttpRequest_SetModuleName(rq, modulName);
|
||||
m=AQH_HttpService_GetModule(sv, modulName);
|
||||
if (m==NULL) {
|
||||
DBG_ERROR(NULL, "Module \"%s\" not found", modulName);
|
||||
AQH_HttpRequest_SetModulePerms(rq, 0);
|
||||
}
|
||||
else {
|
||||
AQH_HttpRequest_SetModule(rq, m);
|
||||
}
|
||||
|
||||
session=AQH_HttpRequest_GetSession(rq);
|
||||
if (session) {
|
||||
AQH_USER *u;
|
||||
|
||||
u=AQH_Session_GetUser(session);
|
||||
if (u) {
|
||||
if (strcasecmp(AQH_User_GetAlias(u), AQH_HTTP_SERVICE_ADMINUSER)==0) {
|
||||
DBG_ERROR(NULL, "special admin user, full access granted");
|
||||
AQH_HttpRequest_SetModulePerms(rq, 0xffffffff);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
AQH_HttpService_SetRequestPerms(sv, rq);
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_BUFFER *_getPageFilePath(const AQH_SERVICE *sv, const char *langFolder, const char *fileName)
|
||||
{
|
||||
const char *sourceFolder;
|
||||
@@ -220,7 +352,7 @@ GWEN_BUFFER *_getPageFilePath(const AQH_SERVICE *sv, const char *langFolder, con
|
||||
GWEN_Buffer_AppendString(nameBuf, langFolder);
|
||||
GWEN_Buffer_AppendString(nameBuf, GWEN_DIR_SEPARATOR_S);
|
||||
}
|
||||
GWEN_Text_EscapeToBuffer(fileName, nameBuf);
|
||||
GWEN_Text_EscapeToBufferTolerant(fileName, nameBuf);
|
||||
return nameBuf;
|
||||
}
|
||||
}
|
||||
@@ -245,37 +377,28 @@ void _writeDefaultResponseHeaderToBuffer(AQH_SERVICE *sv, int contentLength, GWE
|
||||
|
||||
|
||||
|
||||
void _setRequestPerms(AQH_SERVICE *sv, AQH_HTTP_REQUEST *rq)
|
||||
AQH_HTTP_URLHANDLER *_findMatchingUrlHandler(AQH_SERVICE *sv, const char *path)
|
||||
{
|
||||
AQH_MODULE *m;
|
||||
AQH_SESSION *session;
|
||||
AQH_HTTP_SERVICE *xsv;
|
||||
AQH_HTTP_URLHANDLER *uh;
|
||||
|
||||
AQH_HttpRequest_SetModulePerms(rq, 0);
|
||||
m=AQH_HttpRequest_GetModule(rq);
|
||||
session=AQH_HttpRequest_GetSession(rq);
|
||||
if (m) {
|
||||
if (session) {
|
||||
AQH_USER * user;
|
||||
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv);
|
||||
if (xsv==NULL) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Not a AQH_HttpService object");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
user=AQH_Session_GetUser(session);
|
||||
if (user) {
|
||||
AQH_MODULE_PERMS *userPerms;
|
||||
|
||||
userPerms=AQH_ModulePerms_List_GetByModuleId(AQH_User_GetModulePermList(user), AQH_Module_GetId(m));
|
||||
if (userPerms)
|
||||
AQH_HttpRequest_SetModulePerms(rq, AQH_ModulePerms_GetPerms(userPerms));
|
||||
uh=AQH_HttpUrlHandler_List_First(xsv->urlHandlerList);
|
||||
while(uh) {
|
||||
if (AQH_HttpUrlHandler_UrlMatches(uh, path)) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Found matching url handler for \"%s\"", path);
|
||||
return uh;
|
||||
}
|
||||
else {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Session but no user, SNH!");
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "No session");
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "No module");
|
||||
uh=AQH_HttpUrlHandler_List_Next(uh);
|
||||
}
|
||||
DBG_INFO(AQH_LOGDOMAIN, "No matching url handler for \"%s\"", path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
|
||||
#include "aqhome/service/service.h"
|
||||
#include "aqhome/http/httprequest.h"
|
||||
#include "aqhome/http/urlhandler.h"
|
||||
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
#include <gwenhywfar/msg.h>
|
||||
@@ -22,6 +24,23 @@
|
||||
|
||||
AQHOME_API GWEN_MSG *AQH_HttpService_HandleHttpRequest(AQH_SERVICE *sv, GWEN_MSG_ENDPOINT *endpoint, const GWEN_MSG *msgReceived);
|
||||
|
||||
AQHOME_API void AQH_HttpService_AddUrlHandler(AQH_SERVICE *sv, AQH_HTTP_URLHANDLER *urlHandler);
|
||||
|
||||
|
||||
/**
|
||||
* Set modulname in request, get and set matching module and determine the calling users permissions in regard
|
||||
* to the selected module.
|
||||
*/
|
||||
AQHOME_API void AQH_HttpService_SetupModuleAndPerms(AQH_SERVICE *sv, AQH_HTTP_REQUEST *rq, const char *modulName);
|
||||
|
||||
|
||||
/**
|
||||
* Set permissions for this request according to session, user and module.
|
||||
*
|
||||
* The members session and module must have been set before calling this function.
|
||||
*/
|
||||
AQHOME_API void AQH_HttpService_SetRequestPerms(AQH_SERVICE *sv, AQH_HTTP_REQUEST *rq);
|
||||
|
||||
|
||||
AQHOME_API void AQH_HttpService_AddStatusLine(AQH_SERVICE *sv, int code, const char *msg, const char *proto, GWEN_BUFFER *buf);
|
||||
AQHOME_API void AQH_HttpService_AddHeader(AQH_SERVICE *sv, GWEN_DB_NODE *dbHeader, GWEN_BUFFER *buf);
|
||||
@@ -29,7 +48,12 @@ AQHOME_API void AQH_HttpService_AddHeader(AQH_SERVICE *sv, GWEN_DB_NODE *dbHeade
|
||||
AQHOME_API int AQH_HttpService_ParsePostBody(AQH_SERVICE *sv, const GWEN_MSG *msgReceived, GWEN_DB_NODE *dbBody);
|
||||
|
||||
|
||||
AQHOME_API GWEN_MSG *AQH_HttpService_CreateResponseMsg(AQH_SERVICE *sv, int code, const char *text, const char *protocol);
|
||||
AQHOME_API GWEN_MSG *AQH_HttpService_CreateResponseMsg(AQH_SERVICE *sv,
|
||||
int code, const char *text, const char *protocol,
|
||||
const char *page);
|
||||
|
||||
AQHOME_API GWEN_MSG *AQH_HttpService_CreateRedirectingResponseMsg(AQH_SERVICE *sv, const char *protocol, const char *newPage);
|
||||
|
||||
|
||||
AQHOME_API int AQH_HttpService_AddFile(AQH_SERVICE *sv, AQH_SESSION *session, const char *fname, GWEN_BUFFER *buf);
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
|
||||
|
||||
GWEN_MSG *AQH_HttpService_HandleLoginUrl(AQH_SERVICE *sv, const GWEN_MSG *msgReceived, const GWEN_URL *url);
|
||||
AQHOME_API GWEN_MSG *AQH_HttpService_HandleLoginUrl(AQH_SERVICE *sv, const GWEN_MSG *msgReceived, const GWEN_URL *url);
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ struct AQH_HTTP_SERVICE {
|
||||
GWEN_MUTEX *userMutex;
|
||||
GWEN_MUTEX *sessionMutex;
|
||||
|
||||
AQH_HTTP_SERVICE_HANDLEREQUEST_FN handleRequestFn;
|
||||
AQH_HTTP_URLHANDLER_LIST *urlHandlerList;
|
||||
};
|
||||
|
||||
|
||||
|
||||
239
aqhome/http/urlhandler.c
Normal file
239
aqhome/http/urlhandler.c
Normal file
@@ -0,0 +1,239 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./urlhandler_p.h"
|
||||
#include "aqhome/http/httpservice_http.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/misc.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
|
||||
|
||||
|
||||
GWEN_INHERIT_FUNCTIONS(AQH_HTTP_URLHANDLER)
|
||||
GWEN_LIST_FUNCTIONS(AQH_HTTP_URLHANDLER, AQH_HttpUrlHandler)
|
||||
|
||||
|
||||
|
||||
static int _addContentHeaders(AQH_HTTP_CONTENT *c, int m, GWEN_BUFFER *dbuf);
|
||||
static int _addContentFooters(AQH_HTTP_CONTENT *c, int m, GWEN_BUFFER *dbuf);
|
||||
|
||||
|
||||
|
||||
|
||||
AQH_HTTP_URLHANDLER *AQH_HttpUrlHandler_new(AQH_SERVICE *sv)
|
||||
{
|
||||
AQH_HTTP_URLHANDLER *uh;
|
||||
|
||||
GWEN_NEW_OBJECT(AQH_HTTP_URLHANDLER, uh);
|
||||
GWEN_INHERIT_INIT(AQH_HTTP_URLHANDLER, uh);
|
||||
GWEN_LIST_INIT(AQH_HTTP_URLHANDLER, uh);
|
||||
uh->urlPatternList=GWEN_StringList_new();
|
||||
uh->httpService=sv;
|
||||
|
||||
return uh;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_HttpUrlHandler_free(AQH_HTTP_URLHANDLER *uh)
|
||||
{
|
||||
if (uh) {
|
||||
GWEN_LIST_FINI(AQH_HTTP_URLHANDLER, uh);
|
||||
GWEN_INHERIT_FINI(AQH_HTTP_URLHANDLER, uh);
|
||||
GWEN_StringList_free(uh->urlPatternList);
|
||||
GWEN_FREE_OBJECT(uh);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_SERVICE *AQH_HttpUrlHandler_GetHttpService(const AQH_HTTP_URLHANDLER *uh)
|
||||
{
|
||||
return uh?uh->httpService:NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_HTTP_CONTENT *AQH_HttpUrlHandler_GetContentProvider(const AQH_HTTP_URLHANDLER *uh)
|
||||
{
|
||||
return uh?uh->httpContentProvider:NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_HttpUrlHandler_SetContentProvider(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_CONTENT *cp)
|
||||
{
|
||||
if (uh)
|
||||
uh->httpContentProvider=cp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_HttpUrlHandler_AddUrlPattern(AQH_HTTP_URLHANDLER *uh, const char *s)
|
||||
{
|
||||
if (uh && s && *s)
|
||||
GWEN_StringList_AppendString(uh->urlPatternList, s, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AQH_HttpUrlHandler_UrlMatches(const AQH_HTTP_URLHANDLER *uh, const char *s)
|
||||
{
|
||||
if (uh && s && *s) {
|
||||
GWEN_STRINGLISTENTRY *se;
|
||||
|
||||
se=GWEN_StringList_FirstEntry(uh->urlPatternList);
|
||||
while(se) {
|
||||
const char *pattern;
|
||||
|
||||
pattern=GWEN_StringListEntry_Data(se);
|
||||
if (GWEN_Text_ComparePattern(s, pattern, 0)!=-1)
|
||||
return 1;
|
||||
se=GWEN_StringListEntry_Next(se);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_HttpUrlHandler_SetHandleFn(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_URLHANDLER_HANDLE_FN fn)
|
||||
{
|
||||
if (uh)
|
||||
uh->handleFn=fn;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AQH_HttpUrlHandler_HandleMessage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
|
||||
{
|
||||
if (uh && uh->handleFn)
|
||||
return uh->handleFn(uh, rq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AQH_HttpUrlHandler_AddContentHeaders(AQH_HTTP_URLHANDLER *uh, int m, GWEN_BUFFER *dbuf)
|
||||
{
|
||||
return _addContentHeaders(uh->httpContentProvider, m, dbuf);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AQH_HttpUrlHandler_AddContentFooters(AQH_HTTP_URLHANDLER *uh, int m, GWEN_BUFFER *dbuf)
|
||||
{
|
||||
return _addContentFooters(uh->httpContentProvider, m, dbuf);
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_MSG *AQH_HttpUrlHandler_CreatePageMessage(AQH_HTTP_URLHANDLER *uh,
|
||||
AQH_HTTP_REQUEST *rq,
|
||||
const char *statusTextColor, const char *statusMsg,
|
||||
int withHeadersAndFooters,
|
||||
AQH_HTTP_URLHANDLER_WRITEPAGE_CB cb)
|
||||
{
|
||||
GWEN_BUFFER *pageBuf;
|
||||
int rv;
|
||||
GWEN_MSG *msgOut=NULL;
|
||||
const char *protocol;
|
||||
|
||||
protocol=AQH_HttpRequest_GetProtocol(rq);
|
||||
pageBuf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
if (withHeadersAndFooters) {
|
||||
rv=AQH_HttpUrlHandler_AddContentHeaders(uh, AQH_HTTP_CONTENT_MODE_DESKTOP, pageBuf);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error adding headers");
|
||||
GWEN_Buffer_free(pageBuf);
|
||||
return AQH_HttpService_CreateResponseMsg(uh->httpService, 500, "Internal Error", protocol, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (statusMsg)
|
||||
GWEN_Buffer_AppendArgs(pageBuf, "<p><font color=\"%s\">%s</font></p>", statusTextColor?statusTextColor:"black", statusMsg);
|
||||
if (cb) {
|
||||
rv=cb(uh, rq, pageBuf);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error adding headers");
|
||||
GWEN_Buffer_free(pageBuf);
|
||||
return AQH_HttpService_CreateResponseMsg(uh->httpService, 500, "Internal Error", protocol, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (withHeadersAndFooters) {
|
||||
rv=AQH_HttpUrlHandler_AddContentFooters(uh, AQH_HTTP_CONTENT_MODE_DESKTOP, pageBuf);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error adding footers");
|
||||
GWEN_Buffer_free(pageBuf);
|
||||
return AQH_HttpService_CreateResponseMsg(uh->httpService, 500, "Internal Error", protocol, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
msgOut=AQH_HttpService_CreateResponseMsg(uh->httpService, 200, "OK", protocol, GWEN_Buffer_GetStart(pageBuf));
|
||||
GWEN_Buffer_free(pageBuf);
|
||||
return msgOut;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _addContentHeaders(AQH_HTTP_CONTENT *c, int m, GWEN_BUFFER *dbuf)
|
||||
{
|
||||
AQH_HTTP_CONTENT *parent;
|
||||
int rv;
|
||||
|
||||
parent=AQH_HttpContent_Tree2_GetParent(c);
|
||||
if (parent) {
|
||||
rv=_addContentHeaders(parent, m, dbuf);
|
||||
if (rv<0) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Error adding content headers for \"%s\"", AQH_HttpContent_GetName(parent));
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
rv=AQH_HttpContent_AddOpeningContent(c, m, dbuf);
|
||||
if (rv<0) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Error adding content headers for \"%s\"", AQH_HttpContent_GetName(c));
|
||||
return rv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _addContentFooters(AQH_HTTP_CONTENT *c, int m, GWEN_BUFFER *dbuf)
|
||||
{
|
||||
AQH_HTTP_CONTENT *parent;
|
||||
int rv;
|
||||
|
||||
rv=AQH_HttpContent_AddClosingContent(c, m, dbuf);
|
||||
if (rv<0) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Error adding content footers for \"%s\"", AQH_HttpContent_GetName(c));
|
||||
return rv;
|
||||
}
|
||||
|
||||
parent=AQH_HttpContent_Tree2_GetParent(c);
|
||||
if (parent) {
|
||||
rv=_addContentFooters(parent, m, dbuf);
|
||||
if (rv<0) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Error adding content footers for \"%s\"", AQH_HttpContent_GetName(parent));
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
65
aqhome/http/urlhandler.h
Normal file
65
aqhome/http/urlhandler.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQH_HTTP_URLHANDLER_H
|
||||
#define AQH_HTTP_URLHANDLER_H
|
||||
|
||||
|
||||
#include <aqhome/api.h>
|
||||
#include <aqhome/http/httprequest.h>
|
||||
#include <aqhome/http/content.h>
|
||||
#include <aqhome/service/service.h>
|
||||
|
||||
#include <gwenhywfar/inherit.h>
|
||||
#include <gwenhywfar/stringlist.h>
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
#include <gwenhywfar/msg.h>
|
||||
|
||||
|
||||
typedef struct AQH_HTTP_URLHANDLER AQH_HTTP_URLHANDLER;
|
||||
GWEN_INHERIT_FUNCTION_LIB_DEFS(AQH_HTTP_URLHANDLER, AQHOME_API)
|
||||
GWEN_LIST_FUNCTION_LIB_DEFS(AQH_HTTP_URLHANDLER, AQH_HttpUrlHandler, AQHOME_API)
|
||||
|
||||
|
||||
typedef int (*AQH_HTTP_URLHANDLER_HANDLE_FN)(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
|
||||
|
||||
AQHOME_API AQH_HTTP_URLHANDLER *AQH_HttpUrlHandler_new(AQH_SERVICE *sv);
|
||||
AQHOME_API void AQH_HttpUrlHandler_free(AQH_HTTP_URLHANDLER *uh);
|
||||
|
||||
AQHOME_API AQH_SERVICE *AQH_HttpUrlHandler_GetHttpService(const AQH_HTTP_URLHANDLER *uh);
|
||||
|
||||
AQHOME_API void AQH_HttpUrlHandler_AddUrlPattern(AQH_HTTP_URLHANDLER *uh, const char *s);
|
||||
AQHOME_API int AQH_HttpUrlHandler_UrlMatches(const AQH_HTTP_URLHANDLER *uh, const char *s);
|
||||
|
||||
AQHOME_API AQH_HTTP_CONTENT *AQH_HttpUrlHandler_GetContentProvider(const AQH_HTTP_URLHANDLER *uh);
|
||||
AQHOME_API void AQH_HttpUrlHandler_SetContentProvider(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_CONTENT *cp);
|
||||
|
||||
AQHOME_API void AQH_HttpUrlHandler_SetHandleFn(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_URLHANDLER_HANDLE_FN fn);
|
||||
|
||||
AQHOME_API int AQH_HttpUrlHandler_AddContentHeaders(AQH_HTTP_URLHANDLER *uh, int m, GWEN_BUFFER *dbuf);
|
||||
AQHOME_API int AQH_HttpUrlHandler_AddContentFooters(AQH_HTTP_URLHANDLER *uh, int m, GWEN_BUFFER *dbuf);
|
||||
|
||||
|
||||
AQHOME_API int AQH_HttpUrlHandler_HandleMessage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
|
||||
|
||||
|
||||
|
||||
typedef int (*AQH_HTTP_URLHANDLER_WRITEPAGE_CB)(AQH_HTTP_URLHANDLER *uh,
|
||||
AQH_HTTP_REQUEST *rq,
|
||||
GWEN_BUFFER *pageBuf);
|
||||
AQHOME_API GWEN_MSG *AQH_HttpUrlHandler_CreatePageMessage(AQH_HTTP_URLHANDLER *uh,
|
||||
AQH_HTTP_REQUEST *rq,
|
||||
const char *statusTextColor, const char *statusMsg,
|
||||
int withHeadersAndFooters,
|
||||
AQH_HTTP_URLHANDLER_WRITEPAGE_CB cb);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
32
aqhome/http/urlhandler_p.h
Normal file
32
aqhome/http/urlhandler_p.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQH_HTTP_URLHANDLER_P_H
|
||||
#define AQH_HTTP_URLHANDLER_P_H
|
||||
|
||||
|
||||
#include "aqhome/http/urlhandler.h"
|
||||
|
||||
|
||||
typedef struct AQH_HTTP_URLHANDLER AQH_HTTP_URLHANDLER;
|
||||
struct AQH_HTTP_URLHANDLER {
|
||||
GWEN_INHERIT_ELEMENT(AQH_HTTP_URLHANDLER);
|
||||
GWEN_LIST_ELEMENT(AQH_HTTP_URLHANDLER);
|
||||
|
||||
AQH_SERVICE *httpService;
|
||||
GWEN_STRINGLIST *urlPatternList;
|
||||
AQH_HTTP_CONTENT *httpContentProvider;
|
||||
AQH_HTTP_URLHANDLER_HANDLE_FN handleFn;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
<flags></flags>
|
||||
</member>
|
||||
|
||||
<member name="roleList" type="AQH_ROLE_LIST">
|
||||
<member name="roleList" type="AQH_ROLE_LIST" elementName="role" >
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
|
||||
@@ -39,6 +39,25 @@
|
||||
|
||||
</defines>
|
||||
|
||||
<enums>
|
||||
|
||||
<enum id="AQH_USER_STATE" prefix="AQH_UserState_">
|
||||
<item name="suspended">
|
||||
<descr>User suspended</descr>
|
||||
</item>
|
||||
|
||||
<item name="waitForConfirmation">
|
||||
<descr>Waiting for email confirmation</descr>
|
||||
</item>
|
||||
|
||||
<item name="waitForApproval">
|
||||
<descr>Waiting for approval by admin</descr>
|
||||
</item>
|
||||
|
||||
</enum>
|
||||
|
||||
</enums>
|
||||
|
||||
|
||||
<members>
|
||||
|
||||
@@ -56,6 +75,13 @@
|
||||
<flags>with_flags</flags>
|
||||
</member>
|
||||
|
||||
<member name="state" type="int" maxlen="4">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags></flags>
|
||||
</member>
|
||||
|
||||
<member name="name" type="char_ptr" maxlen="16">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
|
||||
Reference in New Issue
Block a user