aqhome: added service definitions, started implementing HTTP service.

This commit is contained in:
Martin Preuss
2023-07-24 21:49:17 +02:00
parent db5d6cb980
commit 16ce958964
33 changed files with 2346 additions and 7 deletions

View File

@@ -66,6 +66,7 @@
http
hexfile
data
service
</subdirs>
@@ -77,6 +78,7 @@
aqhhttp
aqhhexfile
aqhdata
aqhservice
</useTargets>
<libraries>

View File

@@ -47,12 +47,18 @@
<headers dist="true" install="$(pkgincludedir)/http" >
endpoint_http.h
urlhandler.h
content.h
content_files.h
httpservice.h
</headers>
<headers dist="true" >
endpoint_http_p.h
urlhandler_p.h
content_p.h
content_files_p.h
httpservice_p.h
</headers>
@@ -61,6 +67,9 @@
endpoint_http.c
urlhandler.c
content.c
content_files.c
httpservice.c
</sources>

84
aqhome/http/content.c Normal file
View 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 "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(void)
{
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);
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);
}
}
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;
}

58
aqhome/http/content.h Normal file
View File

@@ -0,0 +1,58 @@
/****************************************************************************
* 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_CONTENT_H
#define AQHOME_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(void);
AQHOME_API void AQH_HttpContent_free(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);
#ifdef __cplusplus
}
#endif
#endif

145
aqhome/http/content_files.c Normal file
View File

@@ -0,0 +1,145 @@
/****************************************************************************
* 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 *headerFilename, const char *footerFilename)
{
AQH_HTTP_CONTENT *cp;
AQH_HTTP_CONTENT_FILES *xcp;
cp=AQH_HttpContent_new();
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;
}

View 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_CONTENT_FILES_H
#define AQHOME_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 *headerFilename, const char *footerFilename);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,28 @@
/****************************************************************************
* 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_CONTENT_FILES_P_H
#define AQHOME_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

27
aqhome/http/content_p.h Normal file
View File

@@ -0,0 +1,27 @@
/****************************************************************************
* 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_CONTENT_P_H
#define AQHOME_CONTENT_P_H
#include "aqhome/http/content.h"
struct AQH_HTTP_CONTENT {
GWEN_INHERIT_ELEMENT(AQH_HTTP_CONTENT);
GWEN_TREE2_ELEMENT(AQH_HTTP_CONTENT);
AQH_HTTP_CONTENT_ADD_OPENING_CONTENT_FN addOpeningContentFn;
AQH_HTTP_CONTENT_ADD_CLOSING_CONTENT_FN addClosingContentFn;
};
#endif

View File

@@ -395,7 +395,8 @@ int _distributeBufferInHeaderMode(GWEN_MSG_ENDPOINT *ep, const uint8_t *bufferPt
}
else {
xep->currentBodyPos=GWEN_Buffer_GetPos(xep->currentReadBuffer);
xep->currentBodySize=contentLength;
xep->currentBodySize=contentLength;
xep->remainingBodySize=contentLength;
xep->readMode=AQH_EndpointHttpd_ReadMode_Body;
}
}
@@ -411,16 +412,16 @@ int _distributeBufferInBodyMode(GWEN_MSG_ENDPOINT *ep, const uint8_t *bufferPtr,
AQH_ENDPOINT_HTTP *xep;
xep=GWEN_INHERIT_GETDATA(GWEN_MSG_ENDPOINT, AQH_ENDPOINT_HTTP, ep);
if (xep->currentBodySize>0) {
if (xep->remainingBodySize>0) {
int len;
len=bufferLen;
if (len>xep->currentBodySize)
len=xep->currentBodySize;
if (len>xep->remainingBodySize)
len=xep->remainingBodySize;
if (len) {
GWEN_Buffer_AppendBytes(xep->currentReadBuffer, (const char*) bufferPtr, len);
xep->currentBodySize-=len;
if (xep->currentBodySize==0) {
xep->remainingBodySize-=len;
if (xep->remainingBodySize==0) {
DBG_INFO(AQH_LOGDOMAIN, "Body completely received");
_finishMessageAndStartNext(ep);
}
@@ -475,6 +476,10 @@ void _finishMessageAndStartNext(GWEN_MSG_ENDPOINT *ep)
xep=GWEN_INHERIT_GETDATA(GWEN_MSG_ENDPOINT, AQH_ENDPOINT_HTTP, ep);
msg=GWEN_Msg_fromBytes((const uint8_t*)GWEN_Buffer_GetStart(xep->currentReadBuffer), GWEN_Buffer_GetUsedBytes(xep->currentReadBuffer));
if (xep->currentBodySize) {
GWEN_Msg_SetParsedPayloadOffset(msg, xep->currentBodyPos);
GWEN_Msg_SetParsedPayloadSize(msg, xep->currentBodySize);
}
dbParsedData=GWEN_DB_Group_new("parsedData");
if (xep->dbCurrentReadCommand)
GWEN_DB_AddGroup(dbParsedData, xep->dbCurrentReadCommand);
@@ -488,6 +493,7 @@ void _finishMessageAndStartNext(GWEN_MSG_ENDPOINT *ep)
xep->currentHeaderPos=0;
xep->currentBodyPos=0;
xep->currentBodySize=0;
xep->remainingBodySize=0;
xep->lastLineStartPos=0;
xep->dbCurrentReadCommand=NULL;
xep->dbCurrentReadHeader=NULL;
@@ -511,6 +517,7 @@ void _abortMessage(GWEN_MSG_ENDPOINT *ep)
xep->currentHeaderPos=0;
xep->currentBodyPos=0;
xep->currentBodySize=0;
xep->remainingBodySize=0;
xep->lastLineStartPos=0;
if (xep->dbCurrentReadCommand)
GWEN_DB_Group_free(xep->dbCurrentReadCommand);

View File

@@ -43,6 +43,7 @@ struct AQH_ENDPOINT_HTTP {
int currentHeaderPos;
int currentBodyPos;
int currentBodySize;
int remainingBodySize;
int lastLineStartPos;
};

328
aqhome/http/httpservice.c Normal file
View File

@@ -0,0 +1,328 @@
/****************************************************************************
* 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/httpservice_p.h"
#include <gwenhywfar/db.h>
#include <gwenhywfar/buffer.h>
#include <gwenhywfar/text.h>
#include <gwenhywfar/debug.h>
GWEN_INHERIT(AQH_SERVICE, AQH_HTTP_SERVICE)
static void GWENHYWFAR_CB _freeData(void *bp, void *p);
static int _checkHeaderGetBodySize(const GWEN_MSG *msgReceived);
void AQH_HttpService_Extend(AQH_SERVICE *sv)
{
AQH_HTTP_SERVICE *xsv;
GWEN_NEW_OBJECT(AQH_HTTP_SERVICE, xsv);
GWEN_INHERIT_SETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv, xsv, _freeData);
}
void _freeData(void *bp, void *p)
{
AQH_HTTP_SERVICE *xsv;
xsv=(AQH_HTTP_SERVICE*) p;
free(xsv->sourceFolder);
free(xsv->siteHeader);
free(xsv->siteFooter);
GWEN_FREE_OBJECT(xsv);
}
const char *AQH_HttpService_GetSourceFolder(const AQH_SERVICE *sv)
{
if (sv) {
AQH_HTTP_SERVICE *xsv;
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv);
if (xsv)
return xsv->sourceFolder;
}
return NULL;
}
void AQH_HttpService_SetSourceFolder(AQH_SERVICE *sv, const char *s)
{
if (sv) {
AQH_HTTP_SERVICE *xsv;
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv);
if (xsv) {
free(xsv->sourceFolder);
xsv->sourceFolder=s?strdup(s):NULL;
}
}
}
const char *AQH_HttpService_GetSiteHeader(const AQH_SERVICE *sv)
{
if (sv) {
AQH_HTTP_SERVICE *xsv;
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv);
if (xsv)
return xsv->siteHeader;
}
return NULL;
}
void AQH_HttpService_SetSiteHeader(AQH_SERVICE *sv, const char *s)
{
if (sv) {
AQH_HTTP_SERVICE *xsv;
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv);
if (xsv) {
free(xsv->siteHeader);
xsv->siteHeader=s?strdup(s):NULL;
}
}
}
const char *AQH_HttpService_GetSiteFooter(const AQH_SERVICE *sv)
{
if (sv) {
AQH_HTTP_SERVICE *xsv;
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv);
if (xsv)
return xsv->siteFooter;
}
return NULL;
}
void AQH_HttpService_SetSiteFooter(AQH_SERVICE *sv, const char *s)
{
if (sv) {
AQH_HTTP_SERVICE *xsv;
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv);
if (xsv) {
free(xsv->siteFooter);
xsv->siteFooter=s?strdup(s):NULL;
}
}
}
int AQH_HttpService_AddFile(AQH_SERVICE *sv, const char *fname, GWEN_BUFFER *buf)
{
if (fname && *fname) {
AQH_HTTP_SERVICE *xsv;
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv);
if (xsv) {
int rv;
GWEN_BUFFER *fnbuf;
fnbuf=GWEN_Buffer_new(0, 256, 0, 1);
if (xsv->sourceFolder) {
GWEN_Buffer_AppendString(fnbuf, xsv->sourceFolder);
GWEN_Buffer_AppendString(fnbuf, GWEN_DIR_SEPARATOR_S);
}
GWEN_Buffer_AppendString(fnbuf, fname);
rv=GWEN_SyncIo_Helper_ReadFile(GWEN_Buffer_GetStart(fnbuf), buf);
if (rv<0) {
DBG_ERROR(AQH_LOGDOMAIN, "Error reading file \"%s\": %d", GWEN_Buffer_GetStart(fnbuf), rv);
GWEN_Buffer_free(fnbuf);
return rv;
}
GWEN_Buffer_free(fnbuf);
}
else {
DBG_ERROR(AQH_LOGDOMAIN, "No http service object");
}
}
return 0;
}
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:"");
}
void AQH_HttpService_AddHeader(AQH_SERVICE *sv, GWEN_DB_NODE *dbHeader, GWEN_BUFFER *buf)
{
GWEN_DB_NODE *dbVar;
dbVar=GWEN_DB_GetFirstVar(dbHeader);
while (dbVar) {
GWEN_DB_NODE *dbVal;
/* only handle first value */
dbVal=GWEN_DB_GetFirstValue(dbVar);
if (dbVal) {
const char *sVar;
sVar=GWEN_DB_VariableName(dbVar);
if (sVar && *sVar) {
GWEN_DB_NODE_TYPE vtype;
vtype=GWEN_DB_GetValueType(dbVal);
if (vtype==GWEN_DB_NodeType_ValueChar) {
const char *sValue;
sValue=GWEN_DB_GetCharValueFromNode(dbVal);
if (sValue)
GWEN_Buffer_AppendArgs(buf, "%s:%s\r\n", sVar, sValue);
} /* if char */
else if (vtype==GWEN_DB_NodeType_ValueInt) {
int i;
i=GWEN_DB_GetIntValueFromNode(dbVal);
if (i!=-1 || strcasecmp(sVar, "Content-Length")==0)
GWEN_Buffer_AppendArgs(buf, "%s:%d\r\n", sVar, i);
} /* if int */
else {
DBG_INFO(AQH_LOGDOMAIN, "Variable type %d of var [%s] not supported, ignoring", vtype, sVar);
}
} /* if sVar */
}
dbVar=GWEN_DB_GetNextVar(dbVar);
}
/* finalize header */
GWEN_Buffer_AppendString(buf, "\r\n");
}
int AQH_HttpService_ParsePostBody(AQH_SERVICE *sv, const GWEN_MSG *msgReceived, GWEN_DB_NODE *dbBody)
{
int contentLength;
const char *s;
contentLength=_checkHeaderGetBodySize(msgReceived);
if (contentLength<1) {
DBG_ERROR(NULL, "Empty message body");
return 0;
}
s=(const char*)(GWEN_Msg_GetConstBuffer(msgReceived)+GWEN_Msg_GetParsedPayloadOffset(msgReceived));
while(contentLength>0) {
const char *sNameStart;
int nameLen;
while((contentLength>0) && (*s<33)) {
contentLength--;
s++;
}
sNameStart=s;
while((contentLength>0) && (*s!='=') && (*s!='&')) {
contentLength--;
s++;
}
nameLen=s-sNameStart;
if ((contentLength>0) && (*s=='=')) {
const char *sValueStart;
int valueLen;
s++;
while((contentLength>0) && (*s<33)) {
s++;
contentLength--;
}
sValueStart=s;
while((contentLength>0) && (*s!='&')) {
contentLength--;
s++;
}
valueLen=s-sValueStart;
if (nameLen && valueLen) {
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)
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=='&'))
s++;
}
} /* while */
return 0;
}
int _checkHeaderGetBodySize(const GWEN_MSG *msgReceived)
{
GWEN_DB_NODE *dbParsedInfo;
GWEN_DB_NODE *dbHeader;
const char *contentType;
int contentLength;
dbParsedInfo=GWEN_Msg_GetDbParsedInfo(msgReceived);
if (dbParsedInfo==NULL) {
DBG_ERROR(AQH_LOGDOMAIN, "No parsed info in received message");
return GWEN_ERROR_BAD_DATA;
}
dbHeader=GWEN_DB_GetGroup(dbParsedInfo, GWEN_PATH_FLAGS_PATHMUSTEXIST, "header");
if (dbHeader==NULL) {
DBG_ERROR(AQH_LOGDOMAIN, "No http header group in received message");
return GWEN_ERROR_BAD_DATA;
}
contentType=GWEN_DB_GetCharValue(dbHeader, "content-type", 0, NULL);
if (!(contentType && *contentType && strcasecmp(contentType, "application/x-www-form-urlencoded")==0)) {
DBG_ERROR(NULL, "Invalid or missing content type [%s]", contentType?contentType:"<no type>");
return GWEN_ERROR_BAD_DATA;
}
contentLength=GWEN_Msg_GetParsedPayloadSize(msgReceived);
if (contentLength<1) {
DBG_ERROR(NULL, "Empty message body");
return 0;
}
return contentLength;
}

48
aqhome/http/httpservice.h Normal file
View File

@@ -0,0 +1,48 @@
/****************************************************************************
* 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_SERVICE_H
#define AQH_HTTP_SERVICE_H
#include "aqhome/service/service.h"
#include <gwenhywfar/db.h>
#include <gwenhywfar/buffer.h>
#include <gwenhywfar/msg.h>
void AQH_HttpService_Extend(AQH_SERVICE *sv);
const char *AQH_HttpService_GetSourceFolder(const AQH_SERVICE *sv);
void AQH_HttpService_SetSourceFolder(AQH_SERVICE *sv, const char *s);
const char *AQH_HttpService_GetSiteHeader(const AQH_SERVICE *sv);
void AQH_HttpService_SetSiteHeader(AQH_SERVICE *sv, const char *s);
const char *AQH_HttpService_GetSiteFooter(const AQH_SERVICE *sv);
void AQH_HttpService_SetSiteFooter(AQH_SERVICE *sv, const char *s);
int AQH_HttpService_AddFile(AQH_SERVICE *sv, const char *fname, GWEN_BUFFER *buf);
void AQH_HttpService_AddStatusLine(AQH_SERVICE *sv, int code, const char *msg, const char *proto, GWEN_BUFFER *buf);
void AQH_HttpService_AddHeader(AQH_SERVICE *sv, GWEN_DB_NODE *dbHeader, GWEN_BUFFER *buf);
int AQH_HttpService_ParsePostBody(AQH_SERVICE *sv, const GWEN_MSG *msgReceived, GWEN_DB_NODE *dbBody);
#endif

View File

@@ -0,0 +1,31 @@
/****************************************************************************
* 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_SERVICE_P_H
#define AQH_HTTP_SERVICE_P_H
#include "aqhome/http/httpservice.h"
typedef struct AQH_HTTP_SERVICE AQH_HTTP_SERVICE;
struct AQH_HTTP_SERVICE {
char *sourceFolder;
char *siteHeader;
char *siteFooter;
};
#endif

View File

@@ -51,6 +51,21 @@ void AQH_UrlHandler_free(AQH_URLHANDLER *uh)
AQH_HTTP_CONTENT *AQH_UrlHandler_GetContentProvider(const AQH_URLHANDLER *uh)
{
return uh?uh->httpContentProvider:NULL;
}
void AQH_UrlHandler_SetContentProvider(AQH_URLHANDLER *uh, AQH_HTTP_CONTENT *cp)
{
if (uh)
uh->httpContentProvider=cp;
}
void AQH_UrlHandler_AddUrlPattern(AQH_URLHANDLER *uh, const char *s)
{
if (uh && s && *s)

View File

@@ -11,6 +11,8 @@
#include <aqhome/api.h>
#include "aqhome/http/content.h"
#include <gwenhywfar/inherit.h>
#include <gwenhywfar/stringlist.h>
#include <gwenhywfar/endpoint.h>
@@ -30,6 +32,9 @@ typedef GWEN_MSG*(*AQH_URLHANDLER_HANDLE_FN)(AQH_URLHANDLER *uh, GWEN_MSG_ENDPOI
AQHOME_API AQH_URLHANDLER *AQH_UrlHandler_new(void);
AQHOME_API void AQH_UrlHandler_free(AQH_URLHANDLER *uh);
AQHOME_API AQH_HTTP_CONTENT *AQH_UrlHandler_GetContentProvider(const AQH_URLHANDLER *uh);
AQHOME_API void AQH_UrlHandler_SetContentProvider(AQH_URLHANDLER *uh, AQH_HTTP_CONTENT *cp);
AQHOME_API void AQH_UrlHandler_AddUrlPattern(AQH_URLHANDLER *uh, const char *s);
AQHOME_API int AQH_UrlHandler_UrlMatches(const AQH_URLHANDLER *uh, const char *s);

View File

@@ -19,6 +19,8 @@ struct AQH_URLHANDLER {
GWEN_STRINGLIST *urlPatternList;
AQH_URLHANDLER_HANDLE_FN handleFn;
AQH_HTTP_CONTENT *httpContentProvider;
};

81
aqhome/service/0BUILD Normal file
View File

@@ -0,0 +1,81 @@
<?xml?>
<gwbuild>
<target type="ConvenienceLibrary" name="aqhservice" >
<includes type="c" >
$(gwenhywfar_cflags)
-I$(topsrcdir)
-I$(topbuilddir)
</includes>
<includes type="tm2" >
--include=$(builddir)
--include=$(srcdir)
</includes>
<define name="BUILDING_AQHOME" />
<setVar name="local/cflags">$(visibility_cflags)</setVar>
<setVar name="tm2flags" >
--api=AQHOME_API
</setVar>
<setVar name="local/typefiles" >
module.t2d
moduleperms.t2d
role.t2d
user.t2d
session.t2d
</setVar>
<setVar name="local/built_sources" >
</setVar>
<setVar name="local/built_headers_pub">
</setVar>
<setVar name="local/built_headers_priv" >
</setVar>
<headers dist="false" install="$(pkgincludedir)/service" >
$(local/built_headers_pub)
</headers>
<headers dist="true" install="$(pkgincludedir)/service" >
service.h
</headers>
<headers dist="true" >
service_p.h
</headers>
<sources>
$(local/typefiles)
service.c
</sources>
<extradist>
</extradist>
<useTargets>
</useTargets>
<subdirs>
</subdirs>
</target>
</gwbuild>

74
aqhome/service/module.t2d Normal file
View File

@@ -0,0 +1,74 @@
<?xml?>
<tm2>
<type id="AQH_MODULE" type="pointer">
<descr>
</descr>
<lang id="c">
<identifier>AQH_MODULE</identifier>
<prefix>AQH_Module</prefix>
<baseFileName>module</baseFileName>
<flags>
with_inherit
with_xml
with_db
with_list1
with_list2
</flags>
<headers>
<header type="sys" loc="pre">aqhome/api.h</header>
<header type="sys" loc="pre">gwenhywfar/error.h</header>
<header type="sys" loc="post">aqhome/service/role.h</header>
</headers>
<inlines>
</inlines>
</lang>
<members>
<member name="id" type="uint32_t" maxlen="4">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags>with_getbymember</flags>
</member>
<member name="name" type="char_ptr" maxlen="16">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags>with_getbymember</flags>
</member>
<member name="descr" type="char_ptr" maxlen="256">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags></flags>
</member>
<member name="guestPerms" type="uint32_t" maxlen="4">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags></flags>
</member>
<member name="roleList" type="AQH_ROLE_LIST">
<default>NULL</default>
<preset>NULL</preset>
<access>public</access>
<flags>own</flags>
</member>
</members>
</type>
</tm2>

View File

@@ -0,0 +1,74 @@
<?xml?>
<tm2>
<type id="AQH_MODULE_PERMS" type="pointer">
<descr>
</descr>
<lang id="c">
<identifier>AQH_MODULE_PERMS</identifier>
<prefix>AQH_ModulePerms</prefix>
<baseFileName>moduleperms</baseFileName>
<flags>
with_inherit
with_xml
with_db
with_list1
with_list2
</flags>
<headers>
<header type="sys" loc="pre">aqhome/api.h</header>
<header type="sys" loc="pre">gwenhywfar/error.h</header>
<header type="sys" loc="post">aqhome/service/role.h</header>
</headers>
<inlines>
</inlines>
</lang>
<members>
<member name="moduleId" type="uint32_t" maxlen="4">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags>with_getbymember</flags>
</member>
<member name="perms" type="uint32_t" maxlen="4">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags></flags>
</member>
<member name="exclAddPerms" type="uint32_t" maxlen="4">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags></flags>
</member>
<member name="exclDelPerms" type="uint32_t" maxlen="4">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags></flags>
</member>
<member name="roleArray" type="uint32_t_array" maxlen="16">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags></flags>
</member>
</members>
</type>
</tm2>

72
aqhome/service/role.t2d Normal file
View File

@@ -0,0 +1,72 @@
<?xml?>
<tm2>
<type id="AQH_ROLE" type="pointer">
<descr>
</descr>
<lang id="c">
<identifier>AQH_ROLE</identifier>
<prefix>AQH_Role</prefix>
<baseFileName>role</baseFileName>
<flags>
with_xml
with_db
with_list1
with_list2
</flags>
<headers>
<header type="sys" loc="pre">aqhome/api.h</header>
<header type="sys" loc="pre">gwenhywfar/error.h</header>
</headers>
<inlines>
</inlines>
</lang>
<members>
<member name="id" type="uint32_t" maxlen="4">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags>with_getbymember</flags>
</member>
<member name="name" type="char_ptr" maxlen="16">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags></flags>
</member>
<member name="perms" type="uint32_t" maxlen="4">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags></flags>
</member>
<member name="exclAddPerms" type="uint32_t" maxlen="4">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags></flags>
</member>
<member name="exclDelPerms" type="uint32_t" maxlen="4">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags></flags>
</member>
</members>
</type>
</tm2>

186
aqhome/service/service.c Normal file
View File

@@ -0,0 +1,186 @@
/****************************************************************************
* 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/service/service_p.h"
#include <gwenhywfar/debug.h>
GWEN_INHERIT_FUNCTIONS(AQH_SERVICE);
GWEN_LIST_FUNCTIONS(AQH_SERVICE, AQH_Service);
AQH_SERVICE *AQH_Service_new(void)
{
AQH_SERVICE *sv;
GWEN_NEW_OBJECT(AQH_SERVICE, sv);
GWEN_INHERIT_INIT(AQH_SERVICE, sv);
GWEN_LIST_INIT(AQH_SERVICE, sv);
sv->userList=AQH_User_List_new();
sv->moduleList=AQH_Module_List_new();
sv->sessionList=AQH_Session_List_new();
return sv;
}
void AQH_Service_free(AQH_SERVICE *sv)
{
if (sv) {
GWEN_LIST_FINI(AQH_SERVICE, sv);
AQH_User_List_free(sv->userList);
AQH_Module_List_free(sv->moduleList);
AQH_Session_List_free(sv->sessionList);
GWEN_INHERIT_FINI(AQH_SERVICE, sv);
GWEN_FREE_OBJECT(sv);
}
}
AQH_USER_LIST *AQH_Service_GetUserList(const AQH_SERVICE *sv)
{
return sv?sv->userList:NULL;
}
AQH_USER *AQH_Service_GetUserById(const AQH_SERVICE *sv, uint32_t id)
{
return sv?AQH_User_List_GetById(sv->userList, id):NULL;
}
AQH_USER *AQH_Service_GetUserByAlias(const AQH_SERVICE *sv, const char *s)
{
return sv?AQH_User_List_GetByAlias(sv->userList, s):NULL;
}
void AQH_Service_AddUser(AQH_SERVICE *sv, AQH_USER *u)
{
if (sv && u)
AQH_User_List_Add(u, sv->userList);
}
void AQH_Service_DelUser(AQH_SERVICE *sv, uint32_t userId)
{
if (sv && userId) {
AQH_USER *u;
u=AQH_User_List_GetById(sv->userList, userId);
if (u) {
AQH_User_List_Del(u);
AQH_User_free(u);
}
}
}
AQH_MODULE_LIST *AQH_Service_GetModuleList(const AQH_SERVICE *sv)
{
return sv?sv->moduleList:NULL;
}
AQH_MODULE *AQH_Service_GetModuleById(const AQH_SERVICE *sv, uint32_t id)
{
return sv?AQH_Module_List_GetById(sv->moduleList, id):NULL;
}
AQH_MODULE *AQH_Service_GetModuleByName(const AQH_SERVICE *sv, const char *s)
{
return sv?AQH_Module_List_GetByName(sv->moduleList, s):NULL;
}
void AQH_Service_AddModule(AQH_SERVICE *sv, AQH_MODULE *m)
{
if (sv && m)
AQH_Module_List_Add(m, sv->moduleList);
}
void AQH_Service_DelModule(AQH_SERVICE *sv, uint32_t moduleId)
{
if (sv && moduleId) {
AQH_MODULE *m;
m=AQH_Module_List_GetById(sv->moduleList, moduleId);
if (m) {
AQH_Module_List_Del(m);
AQH_Module_free(m);
}
}
}
AQH_SESSION_LIST *AQH_Service_GetSessionList(const AQH_SERVICE *sv)
{
return sv?sv->sessionList:NULL;
}
AQH_SESSION *AQH_Service_GetSessionById(const AQH_SERVICE *sv, uint32_t sessionId)
{
return sv?AQH_Session_List_GetById(sv->sessionList, sessionId):NULL;
}
void AQH_Service_AddSession(AQH_SERVICE *sv, AQH_SESSION *session)
{
if (sv && session)
AQH_Session_List_Add(session, sv->sessionList);
}
void AQH_Service_DelSession(AQH_SERVICE *sv, uint32_t id)
{
if (sv && id) {
AQH_SESSION *session;
session=AQH_Session_List_GetById(sv->sessionList, id);
if (session) {
AQH_Session_List_Del(session);
AQH_Session_free(session);
}
}
}

53
aqhome/service/service.h Normal file
View File

@@ -0,0 +1,53 @@
/****************************************************************************
* 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_SERVICE_H
#define AQHOME_SERVICE_H
#include <aqhome/api.h>
#include <gwenhywfar/inherit.h>
#include <gwenhywfar/list.h>
typedef struct AQH_SERVICE AQH_SERVICE;
GWEN_INHERIT_FUNCTION_LIB_DEFS(AQH_SERVICE, AQHOME_API);
GWEN_LIST_FUNCTION_LIB_DEFS(AQH_SERVICE, AQH_Service, AQHOME_API);
#include "aqhome/service/user.h"
#include "aqhome/service/module.h"
#include "aqhome/service/session.h"
AQHOME_API AQH_SERVICE *AQH_Service_new(void);
AQHOME_API void AQH_Service_free(AQH_SERVICE *sv);
AQHOME_API AQH_USER_LIST *AQH_Service_GetUserList(const AQH_SERVICE *sv);
AQHOME_API AQH_USER *AQH_Service_GetUserById(const AQH_SERVICE *sv, uint32_t id);
AQHOME_API AQH_USER *AQH_Service_GetUserByAlias(const AQH_SERVICE *sv, const char *s);
AQHOME_API void AQH_Service_AddUser(AQH_SERVICE *sv, AQH_USER *u);
AQHOME_API void AQH_Service_DelUser(AQH_SERVICE *sv, uint32_t userId);
AQHOME_API AQH_MODULE_LIST *AQH_Service_GetModuleList(const AQH_SERVICE *sv);
AQHOME_API AQH_MODULE *AQH_Service_GetModuleById(const AQH_SERVICE *sv, uint32_t id);
AQHOME_API AQH_MODULE *AQH_Service_GetModuleByName(const AQH_SERVICE *sv, const char *s);
AQHOME_API void AQH_Service_AddModule(AQH_SERVICE *sv, AQH_MODULE *m);
AQHOME_API void AQH_Service_DelModule(AQH_SERVICE *sv, uint32_t moduleId);
AQHOME_API AQH_SESSION_LIST *AQH_Service_GetSessionList(const AQH_SERVICE *sv);
AQHOME_API AQH_SESSION *AQH_Service_GetSessionById(const AQH_SERVICE *sv, uint32_t sessionId);
AQHOME_API void AQH_Service_AddSession(AQH_SERVICE *sv, AQH_SESSION *session);
AQHOME_API void AQH_Service_DelSession(AQH_SERVICE *sv, uint32_t id);
#endif

View 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_SERVICE_P_H
#define AQHOME_SERVICE_P_H
#include "aqhome/service/service.h"
struct AQH_SERVICE {
GWEN_INHERIT_ELEMENT(AQH_SERVICE);
GWEN_LIST_ELEMENT(AQH_SERVICE);
AQH_USER_LIST *userList;
AQH_MODULE_LIST *moduleList;
AQH_SESSION_LIST *sessionList;
};
#endif

View File

@@ -0,0 +1,99 @@
<?xml?>
<tm2>
<type id="AQH_SESSION" type="pointer">
<descr>
</descr>
<lang id="c">
<identifier>AQH_SESSION</identifier>
<prefix>AQH_Session</prefix>
<baseFileName>session</baseFileName>
<flags>
with_xml
with_db
with_list1
with_list2
</flags>
<headers>
<header type="sys" loc="pre">aqhome/api.h</header>
<header type="sys" loc="pre">gwenhywfar/error.h</header>
<header type="sys" loc="pre">gwenhywfar/timestamp.h</header>
<header type="sys" loc="post">aqhome/service/user.h</header>
</headers>
<inlines>
</inlines>
</lang>
<members>
<member name="id" type="uint32_t" maxlen="4">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags>with_getbymember</flags>
</member>
<member name="uid" type="char_ptr" maxlen="64">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags></flags>
</member>
<member name="flags" type="uint32_t" maxlen="4">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags>with_flags</flags>
</member>
<member name="userId" type="uint32_t" maxlen="4">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags></flags>
</member>
<member name="state" type="int" maxlen="4">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags></flags>
</member>
<member name="tempToken" type="char_ptr" maxlen="64">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags></flags>
</member>
<member name="timestampCreation" type="gwen_timestamp" maxlen="8">
<default>NULL</default>
<preset>NULL</preset>
<access>public</access>
<flags>own</flags>
</member>
<member name="user" type="AQH_USER">
<default>NULL</default>
<preset>NULL</preset>
<access>public</access>
<setflags>assign</setflags>
<dupflags>assign</dupflags>
<flags>volatile</flags>
</member>
</members>
</type>
</tm2>

111
aqhome/service/user.t2d Normal file
View File

@@ -0,0 +1,111 @@
<?xml?>
<tm2>
<type id="AQH_USER" type="pointer">
<descr>
</descr>
<lang id="c">
<identifier>AQH_USER</identifier>
<prefix>AQH_User</prefix>
<baseFileName>user</baseFileName>
<flags>
with_xml
with_db
with_list1
with_list2
</flags>
<headers>
<header type="sys" loc="pre">aqhome/api.h</header>
<header type="sys" loc="pre">gwenhywfar/error.h</header>
<header type="sys" loc="pre">gwenhywfar/timestamp.h</header>
<header type="sys" loc="post">aqhome/service/moduleperms.h</header>
</headers>
<inlines>
</inlines>
</lang>
<members>
<member name="id" type="uint32_t" maxlen="4">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags>with_getbymember</flags>
</member>
<member name="flags" type="uint32_t" maxlen="4">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags>with_flags</flags>
</member>
<member name="name" type="char_ptr" maxlen="16">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags></flags>
</member>
<member name="alias" type="char_ptr" maxlen="16">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags>with_getbymember</flags>
</member>
<member name="hashedPassword" type="char_ptr" maxlen="128">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags></flags>
</member>
<member name="email" type="char_ptr" maxlen="128">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags></flags>
</member>
<member name="notes" type="char_ptr" maxlen="256">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags></flags>
</member>
<member name="timestampCreation" type="gwen_timestamp" maxlen="8">
<default>NULL</default>
<preset>NULL</preset>
<access>public</access>
<flags>own</flags>
</member>
<member name="timestampLastLogin" type="gwen_timestamp" maxlen="8">
<default>NULL</default>
<preset>NULL</preset>
<access>public</access>
<flags>own</flags>
</member>
<member name="modulePermList" type="AQH_MODULE_PERMS_LIST">
<default>NULL</default>
<preset>NULL</preset>
<access>public</access>
<getflags>none</getflags>
<setflags>none</setflags>
<flags>own</flags>
</member>
</members>
</type>
</tm2>