aqhome: more work on http service.
This commit is contained in:
@@ -47,12 +47,16 @@
|
|||||||
<headers dist="true" install="$(pkgincludedir)/http" >
|
<headers dist="true" install="$(pkgincludedir)/http" >
|
||||||
endpoint_http.h
|
endpoint_http.h
|
||||||
httpservice.h
|
httpservice.h
|
||||||
|
httpservice_conf.h
|
||||||
|
httpservice_http.h
|
||||||
|
httprequest.h
|
||||||
</headers>
|
</headers>
|
||||||
|
|
||||||
|
|
||||||
<headers dist="true" >
|
<headers dist="true" >
|
||||||
endpoint_http_p.h
|
endpoint_http_p.h
|
||||||
httpservice_p.h
|
httpservice_p.h
|
||||||
|
httprequest_p.h
|
||||||
</headers>
|
</headers>
|
||||||
|
|
||||||
|
|
||||||
@@ -61,6 +65,9 @@
|
|||||||
|
|
||||||
endpoint_http.c
|
endpoint_http.c
|
||||||
httpservice.c
|
httpservice.c
|
||||||
|
httpservice_conf.c
|
||||||
|
httpservice_http.c
|
||||||
|
httprequest.c
|
||||||
</sources>
|
</sources>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
605
aqhome/http/httprequest.c
Normal file
605
aqhome/http/httprequest.c
Normal file
@@ -0,0 +1,605 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* 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 "./httprequest_p.h"
|
||||||
|
|
||||||
|
#include <gwenhywfar/debug.h>
|
||||||
|
#include <gwenhywfar/text.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define AQH_HTTP_REQUEST_SESSIONCOOKIE "sessionid"
|
||||||
|
|
||||||
|
|
||||||
|
GWEN_TREE2_FUNCTIONS(AQH_HTTP_REQUEST, AQH_HttpRequest);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------------------------------
|
||||||
|
* forward declarations
|
||||||
|
* ------------------------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int _getParsedDbInfo(AQH_HTTP_REQUEST *rq, const GWEN_MSG *msg);
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------------------------------
|
||||||
|
* implementations
|
||||||
|
* ------------------------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
AQH_HTTP_REQUEST *AQH_HttpRequest_new(GWEN_MSG_ENDPOINT *endpoint, const GWEN_MSG *receivedMsg)
|
||||||
|
{
|
||||||
|
AQH_HTTP_REQUEST *rq;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
GWEN_NEW_OBJECT(AQH_HTTP_REQUEST, rq);
|
||||||
|
GWEN_TREE2_INIT(AQH_HTTP_REQUEST, rq, AQH_HttpRequest);
|
||||||
|
|
||||||
|
rq->endpoint=endpoint;
|
||||||
|
rq->receivedMsg=receivedMsg;
|
||||||
|
|
||||||
|
rv=_inspectReceivedMessage(rq, receivedMsg);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||||
|
AQH_HttpRequest_free(rq);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return rq;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AQH_HttpRequest_free(AQH_HTTP_REQUEST *rq)
|
||||||
|
{
|
||||||
|
if (rq) {
|
||||||
|
GWEN_TREE2_FINI(AQH_HTTP_REQUEST, rq, AQH_HttpRequest);
|
||||||
|
free(rq->sessionId);
|
||||||
|
free(rq->moduleName);
|
||||||
|
free(rq->responseText);
|
||||||
|
GWEN_Msg_free(rq->responseMsg);
|
||||||
|
GWEN_Url_free(rq->url);
|
||||||
|
GWEN_DB_Group_free(rq->dbPostBody);
|
||||||
|
|
||||||
|
GWEN_FREE_OBJECT(rq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GWEN_MSG_ENDPOINT *AQH_HttpRequest_GetEndpoint(const AQH_HTTP_REQUEST *rq)
|
||||||
|
{
|
||||||
|
return rq?(rq->endpoint):NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const GWEN_MSG *AQH_HttpRequest_GetReceivedMsg(const AQH_HTTP_REQUEST *rq)
|
||||||
|
{
|
||||||
|
return rq?(rq->receivedMsg):NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const char *AQH_HttpRequest_GetCommand(const AQH_HTTP_REQUEST *rq)
|
||||||
|
{
|
||||||
|
return rq?(rq->command):NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const char *AQH_HttpRequest_GetProtocol(const AQH_HTTP_REQUEST *rq)
|
||||||
|
{
|
||||||
|
return rq?(rq->protocol):NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GWEN_URL *AQH_HttpRequest_GetUrl(const AQH_HTTP_REQUEST *rq)
|
||||||
|
{
|
||||||
|
return rq?(rq->url):NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AQH_HttpRequest_SetUrl(AQH_HTTP_REQUEST *rq, GWEN_URL *url)
|
||||||
|
{
|
||||||
|
if (rq) {
|
||||||
|
GWEN_Url_free(rq->url);
|
||||||
|
rq->url=url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GWEN_DB_NODE *AQH_HttpRequest_GetDbCommand(const AQH_HTTP_REQUEST *rq)
|
||||||
|
{
|
||||||
|
return rq?(rq->dbCommand):NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GWEN_DB_NODE *AQH_HttpRequest_GetDbHeader(const AQH_HTTP_REQUEST *rq)
|
||||||
|
{
|
||||||
|
return rq?(rq->dbHeader):NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GWEN_DB_NODE *AQH_HttpRequest_GetDbCookies(const AQH_HTTP_REQUEST *rq)
|
||||||
|
{
|
||||||
|
return rq?(rq->dbCookies):NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const char *AQH_HttpRequest_GetSessionId(const AQH_HTTP_REQUEST *rq)
|
||||||
|
{
|
||||||
|
return rq?(rq->sessionId):NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AQH_HttpRequest_SetSessionId(AQH_HTTP_REQUEST *rq, const char *s)
|
||||||
|
{
|
||||||
|
if (rq) {
|
||||||
|
free(rq->sessionId);
|
||||||
|
rq->sessionId=s?strdup(s):NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const char *AQH_HttpRequest_GetModuleName(const AQH_HTTP_REQUEST *rq)
|
||||||
|
{
|
||||||
|
return rq?(rq->moduleName):NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AQH_HttpRequest_SetModuleName(AQH_HTTP_REQUEST *rq, const char *s)
|
||||||
|
{
|
||||||
|
if (rq) {
|
||||||
|
free(rq->moduleName);
|
||||||
|
rq->moduleName=s?strdup(s):NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AQH_SESSION *AQH_HttpRequest_GetSession(const AQH_HTTP_REQUEST *rq)
|
||||||
|
{
|
||||||
|
return rq?(rq->session):NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AQH_HttpRequest_SetSession(AQH_HTTP_REQUEST *rq, AQH_SESSION *session)
|
||||||
|
{
|
||||||
|
if (rq)
|
||||||
|
rq->session=session;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AQH_MODULE *AQH_HttpRequest_GetModule(const AQH_HTTP_REQUEST *rq)
|
||||||
|
{
|
||||||
|
return rq?(rq->module):NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AQH_HttpRequest_SetModule(AQH_HTTP_REQUEST *rq, AQH_MODULE *m)
|
||||||
|
{
|
||||||
|
if (rq)
|
||||||
|
rq->module=m;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t AQH_HttpRequest_GetModulePerms(const AQH_HTTP_REQUEST *rq)
|
||||||
|
{
|
||||||
|
return rq?(rq->modulePerms):0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AQH_HttpRequest_SetModulePerms(AQH_HTTP_REQUEST *rq, uint32_t i)
|
||||||
|
{
|
||||||
|
if (rq)
|
||||||
|
rq->modulePerms=i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int AQH_HttpRequest_GetResponseCode(const AQH_HTTP_REQUEST *rq)
|
||||||
|
{
|
||||||
|
return rq?(rq->responseCode):0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AQH_HttpRequest_SetResponseCode(AQH_HTTP_REQUEST *rq, int i)
|
||||||
|
{
|
||||||
|
if (rq)
|
||||||
|
rq->responseCode=i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const char *AQH_HttpRequest_GetResponseText(const AQH_HTTP_REQUEST *rq)
|
||||||
|
{
|
||||||
|
return rq?(rq->responseText):NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AQH_HttpRequest_SetResponseText(AQH_HTTP_REQUEST *rq, const char *s)
|
||||||
|
{
|
||||||
|
if (rq) {
|
||||||
|
free(rq->responseText);
|
||||||
|
rq->responseText=s?strdup(s):NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GWEN_MSG *AQH_HttpRequest_GetResponseMsg(const AQH_HTTP_REQUEST *rq)
|
||||||
|
{
|
||||||
|
return rq?(rq->responseMsg):NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GWEN_MSG *AQH_HttpRequest_TakeResponseMsg(AQH_HTTP_REQUEST *rq)
|
||||||
|
{
|
||||||
|
if (rq) {
|
||||||
|
GWEN_MSG *msg;
|
||||||
|
|
||||||
|
msg=rq->responseMsg;
|
||||||
|
rq->responseMsg=NULL;
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AQH_HttpRequest_SetResponseMsg(AQH_HTTP_REQUEST *rq, GWEN_MSG *msg)
|
||||||
|
{
|
||||||
|
if (rq && msg) {
|
||||||
|
GWEN_Msg_free(rq->responseMsg);
|
||||||
|
rq->responseMsg=msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int _inspectReceivedMessage(AQH_HTTP_REQUEST *rq, const GWEN_MSG *msg)
|
||||||
|
{
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
rv=_getParsedDbInfo(rq, msg);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv=_inspectMsgCommand(rq, msg);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
_inspectMsgHeader(rq, msg);
|
||||||
|
|
||||||
|
rv=_inspectMsgBody(rq, msg);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int _getParsedDbInfo(AQH_HTTP_REQUEST *rq, const GWEN_MSG *msg)
|
||||||
|
{
|
||||||
|
GWEN_DB_NODE *dbParsedInfo;
|
||||||
|
GWEN_DB_NODE *db;
|
||||||
|
|
||||||
|
dbParsedInfo=GWEN_Msg_GetDbParsedInfo(msg);
|
||||||
|
if (dbParsedInfo==NULL) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "No parsed info db, msg probably not generated by HTTP endpoint module");
|
||||||
|
return GWEN_ERROR_GENERIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
db=GWEN_DB_GetGroup(dbParsedInfo, GWEN_PATH_FLAGS_PATHMUSTEXIST, "command");
|
||||||
|
if (db==NULL) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "No parsed command db, msg probably not generated by HTTP endpoint module");
|
||||||
|
return GWEN_ERROR_GENERIC;
|
||||||
|
}
|
||||||
|
rq->dbCommand=db;
|
||||||
|
|
||||||
|
db=GWEN_DB_GetGroup(dbParsedInfo, GWEN_PATH_FLAGS_PATHMUSTEXIST, "header");
|
||||||
|
if (db==NULL) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "No parsed header db, msg probably not generated by HTTP endpoint module or no header recvd, ignoring");
|
||||||
|
}
|
||||||
|
rq->dbHeader=db;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int _inspectMsgCommand(AQH_HTTP_REQUEST *rq, const GWEN_MSG *msg)
|
||||||
|
{
|
||||||
|
const char *s;
|
||||||
|
|
||||||
|
s=GWEN_DB_GetCharValue(rq->dbCommand, "command", 0, NULL);
|
||||||
|
if (!(s && *s)) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "No command in request");
|
||||||
|
return GWEN_ERROR_GENERIC;
|
||||||
|
}
|
||||||
|
rq->command=s;
|
||||||
|
|
||||||
|
s=GWEN_DB_GetCharValue(rq->dbCommand, "protocol", 0, NULL);
|
||||||
|
if (!(s && *s)) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "No protocol in request");
|
||||||
|
return GWEN_ERROR_GENERIC;
|
||||||
|
}
|
||||||
|
rq->protocol=s;
|
||||||
|
|
||||||
|
s=GWEN_DB_GetCharValue(rq->dbCommand, "url", 0, NULL);
|
||||||
|
if (!(s && *s)) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "No url in request");
|
||||||
|
return GWEN_ERROR_GENERIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
rq->url=GWEN_Url_fromCommandString(s);
|
||||||
|
if (rq->url==NULL) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Invalid URL [%s]", s);
|
||||||
|
return GWEN_ERROR_GENERIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
_setModuleNameFromUrl(rq);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void _inspectMsgHeader(AQH_HTTP_REQUEST *rq, const GWEN_MSG *msg)
|
||||||
|
{
|
||||||
|
if (rq->dbHeader)
|
||||||
|
rq->dbCookies=_extractCookies(rq->dbHeader);
|
||||||
|
if (rq->dbCookies) {
|
||||||
|
const char *s;
|
||||||
|
|
||||||
|
s=GWEN_DB_GetCharValue(rq->dbCookies, AQH_HTTP_REQUEST_SESSIONCOOKIE, 0, NULL);
|
||||||
|
if (s && *s)
|
||||||
|
AQH_HttpRequest_SetSessionId(rq, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int _inspectMsgBody(AQH_HTTP_REQUEST *rq, const GWEN_MSG *msg)
|
||||||
|
{
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
rq->recvdBodySize=GWEN_Msg_GetParsedPayloadSize(msg);
|
||||||
|
if (rq->recvdBodySize>0)
|
||||||
|
rq->recvdBodyPtr=GWEN_Msg_GetConstBuffer(msg)+GWEN_Msg_GetParsedPayloadOffset(msg);
|
||||||
|
|
||||||
|
if (rq->dbHeader && rq->recvdBodySize>0 && strcasecmp(rq->command, "POST")==0) {
|
||||||
|
const char *s;
|
||||||
|
|
||||||
|
/* check whether we need to parse POST body */
|
||||||
|
s=GWEN_DB_GetCharValue(rq->dbCommand, "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);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GWEN_DB_NODE *_extractCookies(GWEN_DB_NODE *dbHeader)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
GWEN_DB_NODE *dbCookies;
|
||||||
|
|
||||||
|
dbCookies=GWEN_DB_GetGroup(dbHeader, 0, "cookies");
|
||||||
|
for (i=0; ; i++) {
|
||||||
|
const char *sCookie;
|
||||||
|
|
||||||
|
sCookie=GWEN_DB_GetCharValue(dbHeader, "Cookie", i, NULL);
|
||||||
|
if (sCookie && *sCookie) {
|
||||||
|
const char *s;
|
||||||
|
|
||||||
|
s=sCookie;
|
||||||
|
while(*s) {
|
||||||
|
while(*s && *s<33)
|
||||||
|
s++;
|
||||||
|
|
||||||
|
if (*s) {
|
||||||
|
const char *nameStart;
|
||||||
|
int nameLen;
|
||||||
|
|
||||||
|
nameStart=s++;
|
||||||
|
while(*s && *s!='=')
|
||||||
|
s++;
|
||||||
|
if (*s=='=') {
|
||||||
|
nameLen=s-nameStart;
|
||||||
|
s++;
|
||||||
|
while(*s && *s<33)
|
||||||
|
s++;
|
||||||
|
if (*s) {
|
||||||
|
const char *valueStart;
|
||||||
|
int valueLen;
|
||||||
|
|
||||||
|
valueStart=s;
|
||||||
|
while(*s && *s!=';')
|
||||||
|
s++;
|
||||||
|
valueLen=s-valueStart;
|
||||||
|
|
||||||
|
_setCookieValue(dbCookies, nameStart, nameLen, valueStart, valueLen, 0);
|
||||||
|
|
||||||
|
if (*s)
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} /* while(*s) */
|
||||||
|
} /* if (sCookie && *sCookie) */
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
} /* for */
|
||||||
|
return dbCookies;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void _setCookieValue(GWEN_DB_NODE *dbCookies, const char *nameStart, int nameLen, const char *valueStart, int valueLen, uint32_t dbFlags)
|
||||||
|
{
|
||||||
|
if (nameLen && valueLen) {
|
||||||
|
int i;
|
||||||
|
char *sName;
|
||||||
|
char *sValue;
|
||||||
|
|
||||||
|
for (i=nameLen-1; i>0; i--) {
|
||||||
|
if (nameStart[i]>32)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sName=GWEN_Text_strndup(nameStart, i+1);
|
||||||
|
|
||||||
|
for (i=valueLen-1; i>0; i--) {
|
||||||
|
if (valueStart[i]>32)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sValue=GWEN_Text_strndup(valueStart, i+1);
|
||||||
|
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "Received Cookie: [%s]=[%s]", sName, sValue);
|
||||||
|
GWEN_DB_SetCharValue(dbCookies, dbFlags, sName, sValue);
|
||||||
|
free(sValue);
|
||||||
|
free(sName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
76
aqhome/http/httprequest.h
Normal file
76
aqhome/http/httprequest.h
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* 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_REQUEST_H
|
||||||
|
#define AQH_HTTP_REQUEST_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "aqhome/service/session.h"
|
||||||
|
#include "aqhome/service/module.h"
|
||||||
|
|
||||||
|
#include <gwenhywfar/tree2.h>
|
||||||
|
#include <gwenhywfar/endpoint.h>
|
||||||
|
#include <gwenhywfar/msg.h>
|
||||||
|
#include <gwenhywfar/url.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct AQH_HTTP_REQUEST AQH_HTTP_REQUEST;
|
||||||
|
GWEN_TREE2_FUNCTION_LIB_DEFS(AQH_HTTP_REQUEST, AQH_HttpRequest, AQHOME_API);
|
||||||
|
|
||||||
|
AQHOME_API AQH_HTTP_REQUEST *AQH_HttpRequest_new(GWEN_MSG_ENDPOINT *endpoint, const GWEN_MSG *receivedMsg);
|
||||||
|
AQHOME_API void AQH_HttpRequest_free(AQH_HTTP_REQUEST *rq);
|
||||||
|
|
||||||
|
AQHOME_API GWEN_MSG_ENDPOINT *AQH_HttpRequest_GetEndpoint(const AQH_HTTP_REQUEST *rq);
|
||||||
|
|
||||||
|
AQHOME_API const GWEN_MSG *AQH_HttpRequest_GetReceivedMsg(const AQH_HTTP_REQUEST *rq);
|
||||||
|
|
||||||
|
AQHOME_API const char *AQH_HttpRequest_GetCommand(const AQH_HTTP_REQUEST *rq);
|
||||||
|
|
||||||
|
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 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 const char *AQH_HttpRequest_GetSessionId(const AQH_HTTP_REQUEST *rq);
|
||||||
|
AQHOME_API void AQH_HttpRequest_SetSessionId(AQH_HTTP_REQUEST *rq, const char *s);
|
||||||
|
|
||||||
|
AQHOME_API const char *AQH_HttpRequest_GetModuleName(const AQH_HTTP_REQUEST *rq);
|
||||||
|
AQHOME_API void AQH_HttpRequest_SetModuleName(AQH_HTTP_REQUEST *rq, const char *s);
|
||||||
|
|
||||||
|
AQHOME_API AQH_SESSION *AQH_HttpRequest_GetSession(const AQH_HTTP_REQUEST *rq);
|
||||||
|
AQHOME_API void AQH_HttpRequest_SetSession(AQH_HTTP_REQUEST *rq, AQH_SESSION *session);
|
||||||
|
|
||||||
|
AQHOME_API AQH_MODULE *AQH_HttpRequest_GetModule(const AQH_HTTP_REQUEST *rq);
|
||||||
|
AQHOME_API void AQH_HttpRequest_SetModule(AQH_HTTP_REQUEST *rq, AQH_MODULE *m);
|
||||||
|
|
||||||
|
AQHOME_API uint32_t AQH_HttpRequest_GetModulePerms(const AQH_HTTP_REQUEST *rq);
|
||||||
|
AQHOME_API void AQH_HttpRequest_SetModulePerms(AQH_HTTP_REQUEST *rq, uint32_t i);
|
||||||
|
|
||||||
|
|
||||||
|
AQHOME_API int AQH_HttpRequest_GetResponseCode(const AQH_HTTP_REQUEST *rq);
|
||||||
|
AQHOME_API void AQH_HttpRequest_SetResponseCode(AQH_HTTP_REQUEST *rq, int i);
|
||||||
|
|
||||||
|
AQHOME_API const char *AQH_HttpRequest_GetResponseText(const AQH_HTTP_REQUEST *rq);
|
||||||
|
AQHOME_API void AQH_HttpRequest_SetResponseText(AQH_HTTP_REQUEST *rq, const char *s);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
59
aqhome/http/httprequest_p.h
Normal file
59
aqhome/http/httprequest_p.h
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* 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_REQUEST_P_H
|
||||||
|
#define AQH_HTTP_REQUEST_P_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "aqhome/http/httprequest.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct AQH_HTTP_REQUEST AQH_HTTP_REQUEST;
|
||||||
|
struct AQH_HTTP_REQUEST {
|
||||||
|
GWEN_TREE2_ELEMENT(AQH_HTTP_REQUEST)
|
||||||
|
|
||||||
|
GWEN_MSG_ENDPOINT *endpoint;
|
||||||
|
|
||||||
|
/* received stuff */
|
||||||
|
const GWEN_MSG *receivedMsg; /* don't free */
|
||||||
|
|
||||||
|
const char *command; /* don't free */
|
||||||
|
const char *protocol; /* don't free */
|
||||||
|
GWEN_URL *url;
|
||||||
|
|
||||||
|
GWEN_DB_NODE *dbCommand; /* don't free */
|
||||||
|
GWEN_DB_NODE *dbHeader; /* don't free */
|
||||||
|
GWEN_DB_NODE *dbCookies; /* don't free */
|
||||||
|
|
||||||
|
uint32_t recvdBodySize;
|
||||||
|
const uint8_t *recvdBodyPtr;
|
||||||
|
|
||||||
|
/* derived stuff */
|
||||||
|
char *sessionId;
|
||||||
|
char *moduleName;
|
||||||
|
|
||||||
|
AQH_SESSION *session; /* don't free */
|
||||||
|
AQH_MODULE *module; /* don't free */
|
||||||
|
uint32_t modulePerms;
|
||||||
|
|
||||||
|
GWEN_DB_NODE *dbPostBody;
|
||||||
|
|
||||||
|
|
||||||
|
/* response stuff */
|
||||||
|
int responseCode;
|
||||||
|
char *responseText;
|
||||||
|
GWEN_MSG *responseMsg;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -25,9 +25,6 @@ GWEN_INHERIT(AQH_SERVICE, AQH_HTTP_SERVICE)
|
|||||||
|
|
||||||
static void GWENHYWFAR_CB _freeData(void *bp, void *p);
|
static void GWENHYWFAR_CB _freeData(void *bp, void *p);
|
||||||
|
|
||||||
static int _parsePostBody(const char *s, int contentLength, GWEN_DB_NODE *dbBody);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -37,6 +34,10 @@ void AQH_HttpService_Extend(AQH_SERVICE *sv)
|
|||||||
|
|
||||||
GWEN_NEW_OBJECT(AQH_HTTP_SERVICE, xsv);
|
GWEN_NEW_OBJECT(AQH_HTTP_SERVICE, xsv);
|
||||||
GWEN_INHERIT_SETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv, xsv, _freeData);
|
GWEN_INHERIT_SETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv, xsv, _freeData);
|
||||||
|
|
||||||
|
xsv->moduleMutex=GWEN_Mutex_new();
|
||||||
|
xsv->userMutex=GWEN_Mutex_new();
|
||||||
|
xsv->sessionMutex=GWEN_Mutex_new();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -46,6 +47,12 @@ void _freeData(void *bp, void *p)
|
|||||||
AQH_HTTP_SERVICE *xsv;
|
AQH_HTTP_SERVICE *xsv;
|
||||||
|
|
||||||
xsv=(AQH_HTTP_SERVICE*) p;
|
xsv=(AQH_HTTP_SERVICE*) p;
|
||||||
|
|
||||||
|
GWEN_Mutex_free(xsv->moduleMutex);
|
||||||
|
GWEN_Mutex_free(xsv->userMutex);
|
||||||
|
GWEN_Mutex_free(xsv->sessionMutex);
|
||||||
|
|
||||||
|
free(xsv->configFolder);
|
||||||
free(xsv->sourceFolder);
|
free(xsv->sourceFolder);
|
||||||
free(xsv->siteHeader);
|
free(xsv->siteHeader);
|
||||||
free(xsv->siteFooter);
|
free(xsv->siteFooter);
|
||||||
@@ -54,6 +61,54 @@ 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) {
|
||||||
|
AQH_HTTP_SERVICE *xsv;
|
||||||
|
|
||||||
|
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv);
|
||||||
|
if (xsv)
|
||||||
|
return xsv->configFolder;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AQH_HttpService_SetConfigFolder(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->configFolder);
|
||||||
|
xsv->configFolder=s?strdup(s):NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const char *AQH_HttpService_GetSourceFolder(const AQH_SERVICE *sv)
|
const char *AQH_HttpService_GetSourceFolder(const AQH_SERVICE *sv)
|
||||||
{
|
{
|
||||||
if (sv) {
|
if (sv) {
|
||||||
@@ -83,6 +138,64 @@ void AQH_HttpService_SetSourceFolder(AQH_SERVICE *sv, const char *s)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t AQH_HttpService_GetNextModuleId(AQH_SERVICE *sv)
|
||||||
|
{
|
||||||
|
if (sv) {
|
||||||
|
AQH_HTTP_SERVICE *xsv;
|
||||||
|
|
||||||
|
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv);
|
||||||
|
if (xsv) {
|
||||||
|
return ++(xsv->lastModuleId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t AQH_HttpService_GetNextUserId(AQH_SERVICE *sv)
|
||||||
|
{
|
||||||
|
if (sv) {
|
||||||
|
AQH_HTTP_SERVICE *xsv;
|
||||||
|
|
||||||
|
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv);
|
||||||
|
if (xsv) {
|
||||||
|
return ++(xsv->lastUserId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int AQH_HttpService_GetMaxSessionAgeInSecs(const AQH_SERVICE *sv)
|
||||||
|
{
|
||||||
|
if (sv) {
|
||||||
|
AQH_HTTP_SERVICE *xsv;
|
||||||
|
|
||||||
|
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv);
|
||||||
|
if (xsv) {
|
||||||
|
return xsv->maxSessionAgeInSecs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AQH_HttpService_SetMaxSessionAgeInSecs(AQH_SERVICE *sv, int i)
|
||||||
|
{
|
||||||
|
if (sv) {
|
||||||
|
AQH_HTTP_SERVICE *xsv;
|
||||||
|
|
||||||
|
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv);
|
||||||
|
if (xsv)
|
||||||
|
xsv->maxSessionAgeInSecs=i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const char *AQH_HttpService_GetSiteHeader(const AQH_SERVICE *sv)
|
const char *AQH_HttpService_GetSiteHeader(const AQH_SERVICE *sv)
|
||||||
{
|
{
|
||||||
if (sv) {
|
if (sv) {
|
||||||
@@ -141,183 +254,3 @@ void AQH_HttpService_SetSiteFooter(AQH_SERVICE *sv, const char *s)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
GWEN_DB_NODE *dbParsedInfo;
|
|
||||||
GWEN_DB_NODE *dbHeader;
|
|
||||||
const char *contentType;
|
|
||||||
int contentLength;
|
|
||||||
const char *s;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (contentLength<1) {
|
|
||||||
DBG_ERROR(NULL, "Empty message body");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
s=(const char*)(GWEN_Msg_GetConstBuffer(msgReceived)+GWEN_Msg_GetParsedPayloadOffset(msgReceived));
|
|
||||||
return _parsePostBody(s, contentLength, dbBody);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _parsePostBody(const char *s, int contentLength, GWEN_DB_NODE *dbBody)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -13,33 +13,45 @@
|
|||||||
|
|
||||||
#include "aqhome/service/service.h"
|
#include "aqhome/service/service.h"
|
||||||
|
|
||||||
|
#include "aqhome/http/httprequest.h"
|
||||||
|
|
||||||
|
#include <gwenhywfar/msg.h>
|
||||||
#include <gwenhywfar/db.h>
|
#include <gwenhywfar/db.h>
|
||||||
#include <gwenhywfar/buffer.h>
|
#include <gwenhywfar/buffer.h>
|
||||||
#include <gwenhywfar/msg.h>
|
#include <gwenhywfar/url.h>
|
||||||
|
#include <gwenhywfar/mutex.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void AQH_HttpService_Extend(AQH_SERVICE *sv);
|
typedef int (*AQH_HTTP_SERVICE_HANDLEREQUEST_FN)(AQH_SERVICE *sv, AQH_HTTP_REQUEST *request);
|
||||||
|
|
||||||
|
|
||||||
const char *AQH_HttpService_GetSourceFolder(const AQH_SERVICE *sv);
|
AQHOME_API void AQH_HttpService_Extend(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);
|
AQHOME_API const char *AQH_HttpService_GetConfigFolder(const AQH_SERVICE *sv);
|
||||||
void AQH_HttpService_SetSiteFooter(AQH_SERVICE *sv, const char *s);
|
AQHOME_API void AQH_HttpService_SetConfigFolder(AQH_SERVICE *sv, const char *s);
|
||||||
|
|
||||||
|
|
||||||
int AQH_HttpService_AddFile(AQH_SERVICE *sv, const char *fname, GWEN_BUFFER *buf);
|
AQHOME_API const char *AQH_HttpService_GetSourceFolder(const AQH_SERVICE *sv);
|
||||||
void AQH_HttpService_AddStatusLine(AQH_SERVICE *sv, int code, const char *msg, const char *proto, GWEN_BUFFER *buf);
|
AQHOME_API void AQH_HttpService_SetSourceFolder(AQH_SERVICE *sv, const char *s);
|
||||||
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);
|
AQHOME_API const char *AQH_HttpService_GetSiteHeader(const AQH_SERVICE *sv);
|
||||||
|
AQHOME_API void AQH_HttpService_SetSiteHeader(AQH_SERVICE *sv, const char *s);
|
||||||
|
|
||||||
|
|
||||||
|
AQHOME_API const char *AQH_HttpService_GetSiteFooter(const AQH_SERVICE *sv);
|
||||||
|
AQHOME_API void AQH_HttpService_SetSiteFooter(AQH_SERVICE *sv, const char *s);
|
||||||
|
|
||||||
|
|
||||||
|
AQHOME_API uint32_t AQH_HttpService_GetNextModuleId(AQH_SERVICE *sv);
|
||||||
|
AQHOME_API uint32_t AQH_HttpService_GetNextUserId(AQH_SERVICE *sv);
|
||||||
|
|
||||||
|
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
|
#endif
|
||||||
|
|||||||
982
aqhome/http/httpservice_conf.c
Normal file
982
aqhome/http/httpservice_conf.c
Normal file
@@ -0,0 +1,982 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* 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_conf.h"
|
||||||
|
#include "aqhome/http/httpservice_p.h"
|
||||||
|
|
||||||
|
#include <gwenhywfar/db.h>
|
||||||
|
#include <gwenhywfar/buffer.h>
|
||||||
|
#include <gwenhywfar/text.h>
|
||||||
|
#include <gwenhywfar/debug.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define AQH_HTTP_SERVICE_FILE_CONFIG "service.conf"
|
||||||
|
#define AQH_HTTP_SERVICE_DIR_MODS "modules"
|
||||||
|
#define AQH_HTTP_SERVICE_DIR_USERS "users"
|
||||||
|
#define AQH_HTTP_SERVICE_DIR_SESSIONS "sessions"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef GWEN_INHERIT_REF
|
||||||
|
GWEN_INHERIT_REF(AQH_SERVICE, AQH_HTTP_SERVICE)
|
||||||
|
#else
|
||||||
|
extern uint32_t AQH_HTTP_SERVICE_ID;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------------------------------
|
||||||
|
* forward declarations
|
||||||
|
* ------------------------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void _calculateUserPerms(AQH_SERVICE *sv, AQH_USER *user);
|
||||||
|
static void _calculateModuleUserPerms(AQH_SERVICE *sv, AQH_MODULE_PERMS *p);
|
||||||
|
static AQH_MODULE *_ensureModule(AQH_SERVICE *sv, const char *modName);
|
||||||
|
static AQH_USER *_ensureUser(AQH_SERVICE *sv, const char *alias);
|
||||||
|
static AQH_SESSION *_ensureSession(AQH_SERVICE *sv, const char *sessionUid);
|
||||||
|
static GWEN_BUFFER *_getConfigFilePath(const AQH_SERVICE *sv, const char *fileName);
|
||||||
|
static GWEN_BUFFER *_getModuleFilePath(const AQH_SERVICE *sv, const char *modName);
|
||||||
|
static GWEN_BUFFER *_getUserFilePath(const AQH_SERVICE *sv, const char *userAlias);
|
||||||
|
static GWEN_BUFFER *_getSessionFilePath(const AQH_SERVICE *sv, const char *sessionUid);
|
||||||
|
static int _checkUser(const AQH_USER *user, int ignoreMissingId);
|
||||||
|
static int _checkSession(const AQH_SESSION *session);
|
||||||
|
static int _checkModule(const AQH_MODULE *m, int ignoreMissingId);
|
||||||
|
static int _checkRoleList(const AQH_ROLE_LIST *roleList, int ignoreMissingId);
|
||||||
|
static int _writeDbFile(const char *fname, GWEN_DB_NODE *db);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------------------------------
|
||||||
|
* implementations
|
||||||
|
* ------------------------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
int AQH_HttpService_LoadConfig(AQH_SERVICE *sv)
|
||||||
|
{
|
||||||
|
AQH_HTTP_SERVICE *xsv;
|
||||||
|
GWEN_BUFFER *nameBuf;
|
||||||
|
int rv;
|
||||||
|
GWEN_DB_NODE *db;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||||
|
GWEN_Buffer_free(nameBuf);
|
||||||
|
GWEN_DB_Group_free(db);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
GWEN_Buffer_free(nameBuf);
|
||||||
|
|
||||||
|
xsv->lastModuleId=GWEN_DB_GetIntValue(db, "lastModuleId", 0, 0);
|
||||||
|
xsv->lastUserId=GWEN_DB_GetIntValue(db, "lastUserId", 0, 0);
|
||||||
|
xsv->maxSessionAgeInSecs=GWEN_DB_GetIntValue(db, "maxSessionAgeInSecs", 0, AQH_HTTP_SERVICE_DEFAULT_MAXSESSIONAGE);
|
||||||
|
|
||||||
|
GWEN_DB_Group_free(db);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int AQH_HttpService_SaveConfig(const AQH_SERVICE *sv)
|
||||||
|
{
|
||||||
|
AQH_HTTP_SERVICE *xsv;
|
||||||
|
int rv;
|
||||||
|
GWEN_BUFFER *nameBuf;
|
||||||
|
GWEN_DB_NODE *db;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
db=GWEN_DB_Group_new("service");
|
||||||
|
GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "lastModuleId", xsv->lastModuleId);
|
||||||
|
GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "lastUserId", xsv->lastUserId);
|
||||||
|
GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "maxSessionAgeInSecs", xsv->maxSessionAgeInSecs);
|
||||||
|
|
||||||
|
nameBuf=_getConfigFilePath(sv, AQH_HTTP_SERVICE_FILE_CONFIG);
|
||||||
|
rv=_writeDbFile(GWEN_Buffer_GetStart(nameBuf), db);
|
||||||
|
GWEN_Buffer_free(nameBuf);
|
||||||
|
GWEN_DB_Group_free(db);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AQH_MODULE *AQH_HttpService_GetModule(AQH_SERVICE *sv, const char *modName)
|
||||||
|
{
|
||||||
|
AQH_HTTP_SERVICE *xsv;
|
||||||
|
AQH_MODULE *m;
|
||||||
|
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 NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv=GWEN_Mutex_Lock(xsv->moduleMutex);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Error obtaining lock on module mutex");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
m=_ensureModule(sv, modName);
|
||||||
|
|
||||||
|
rv=GWEN_Mutex_Unlock(xsv->moduleMutex);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Error releasing lock on module mutex");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m==NULL) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "here");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AQH_USER *AQH_HttpService_GetUser(AQH_SERVICE *sv, const char *alias)
|
||||||
|
{
|
||||||
|
AQH_HTTP_SERVICE *xsv;
|
||||||
|
AQH_USER *user;
|
||||||
|
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 NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv=GWEN_Mutex_Lock(xsv->userMutex);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Error obtaining lock on user mutex");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
user=_ensureUser(sv, alias);
|
||||||
|
|
||||||
|
rv=GWEN_Mutex_Unlock(xsv->userMutex);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Error releasing lock on user mutex");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user==NULL) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "here");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AQH_SESSION *AQH_HttpService_GetSession(AQH_SERVICE *sv, const char *sessionUid)
|
||||||
|
{
|
||||||
|
AQH_HTTP_SERVICE *xsv;
|
||||||
|
AQH_SESSION *session;
|
||||||
|
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 NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv=GWEN_Mutex_Lock(xsv->sessionMutex);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Error obtaining lock on session mutex");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
session=_ensureSession(sv, sessionUid);
|
||||||
|
|
||||||
|
rv=GWEN_Mutex_Unlock(xsv->sessionMutex);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Error releasing lock on session mutex");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session==NULL) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "here");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AQH_MODULE *AQH_HttpService_LoadModule(const AQH_SERVICE *sv, const char *modName)
|
||||||
|
{
|
||||||
|
GWEN_BUFFER *nameBuf;
|
||||||
|
int rv;
|
||||||
|
GWEN_DB_NODE *db;
|
||||||
|
AQH_MODULE *m;
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||||
|
GWEN_Buffer_free(nameBuf);
|
||||||
|
GWEN_DB_Group_free(db);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
GWEN_Buffer_free(nameBuf);
|
||||||
|
|
||||||
|
m=AQH_Module_fromDb(db);
|
||||||
|
if (m==NULL) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Error loading module \"%s\" from config group", modName);
|
||||||
|
GWEN_DB_Group_free(db);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
GWEN_DB_Group_free(db);
|
||||||
|
|
||||||
|
rv=_checkModule(m, 0);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "Invalid data for module \"%s\"", modName);
|
||||||
|
AQH_Module_free(m);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int AQH_HttpService_SaveModule(const AQH_SERVICE *sv, const AQH_MODULE *m)
|
||||||
|
{
|
||||||
|
int rv;
|
||||||
|
const char *modName;
|
||||||
|
GWEN_BUFFER *nameBuf;
|
||||||
|
GWEN_DB_NODE *db;
|
||||||
|
|
||||||
|
rv=_checkModule(m, 0);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
db=GWEN_DB_Group_new("module");
|
||||||
|
rv=AQH_Module_toDb(m, db);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||||
|
GWEN_DB_Group_free(db);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
modName=AQH_Module_GetName(m);
|
||||||
|
nameBuf=_getModuleFilePath(sv, modName);
|
||||||
|
rv=_writeDbFile(GWEN_Buffer_GetStart(nameBuf), db);
|
||||||
|
GWEN_Buffer_free(nameBuf);
|
||||||
|
GWEN_DB_Group_free(db);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int AQH_HttpService_AddModule(AQH_SERVICE *sv, AQH_MODULE *m)
|
||||||
|
{
|
||||||
|
int rv;
|
||||||
|
uint32_t id;
|
||||||
|
AQH_ROLE_LIST *roleList;
|
||||||
|
AQH_ROLE *r;
|
||||||
|
|
||||||
|
rv=_checkModule(m, 1);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Not adding invalid module (%d)", rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* assign module id */
|
||||||
|
id=AQH_HttpService_GetNextModuleId(sv);
|
||||||
|
AQH_Module_SetId(m, id);
|
||||||
|
|
||||||
|
/* assign role ids */
|
||||||
|
roleList=AQH_Module_GetRoleList(m);
|
||||||
|
id=1;
|
||||||
|
r=AQH_Role_List_First(roleList);
|
||||||
|
while(r) {
|
||||||
|
AQH_Role_SetId(r, id++);
|
||||||
|
r=AQH_Role_List_Next(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
rv=AQH_HttpService_SaveModule(sv, m);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Error saving module module \"%s\" (%d)", AQH_Module_GetName(m), rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
AQH_Service_AddModule(sv, m);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AQH_USER *AQH_HttpService_LoadUser(const AQH_SERVICE *sv, const char *userAlias)
|
||||||
|
{
|
||||||
|
GWEN_BUFFER *nameBuf;
|
||||||
|
int rv;
|
||||||
|
GWEN_DB_NODE *db;
|
||||||
|
AQH_USER *user;
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||||
|
GWEN_Buffer_free(nameBuf);
|
||||||
|
GWEN_DB_Group_free(db);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
GWEN_Buffer_free(nameBuf);
|
||||||
|
|
||||||
|
user=AQH_User_fromDb(db);
|
||||||
|
if (user==NULL) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Error loading user \"%s\" from config group", userAlias);
|
||||||
|
GWEN_DB_Group_free(db);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
GWEN_DB_Group_free(db);
|
||||||
|
|
||||||
|
rv=_checkUser(user, 0);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "Invalid data for user \"%s\"", userAlias);
|
||||||
|
AQH_User_free(user);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int AQH_HttpService_SaveUser(const AQH_SERVICE *sv, const AQH_USER *user)
|
||||||
|
{
|
||||||
|
int rv;
|
||||||
|
const char *sAlias;
|
||||||
|
GWEN_BUFFER *nameBuf;
|
||||||
|
GWEN_DB_NODE *db;
|
||||||
|
|
||||||
|
rv=_checkUser(user, 0);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
db=GWEN_DB_Group_new("user");
|
||||||
|
rv=AQH_User_toDb(user, db);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||||
|
GWEN_DB_Group_free(db);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
sAlias=AQH_User_GetAlias(user);
|
||||||
|
nameBuf=_getUserFilePath(sv, sAlias);
|
||||||
|
rv=_writeDbFile(GWEN_Buffer_GetStart(nameBuf), db);
|
||||||
|
GWEN_Buffer_free(nameBuf);
|
||||||
|
GWEN_DB_Group_free(db);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int AQH_HttpService_AddUser(AQH_SERVICE *sv, AQH_USER *user)
|
||||||
|
{
|
||||||
|
int rv;
|
||||||
|
uint32_t id;
|
||||||
|
|
||||||
|
rv=_checkUser(user, 0);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* assign user id */
|
||||||
|
id=AQH_HttpService_GetNextUserId(sv);
|
||||||
|
AQH_User_SetId(user, id);
|
||||||
|
|
||||||
|
rv=AQH_HttpService_SaveUser(sv, user);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
AQH_Service_AddUser(sv, user);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int AQH_HttpService_DelUser(AQH_SERVICE *sv, AQH_USER *user)
|
||||||
|
{
|
||||||
|
const char *sAlias;
|
||||||
|
GWEN_BUFFER *nameBuf;
|
||||||
|
uint32_t userId;
|
||||||
|
|
||||||
|
sAlias=AQH_User_GetAlias(user);
|
||||||
|
userId=AQH_User_GetId(user);
|
||||||
|
nameBuf=_getUserFilePath(sv, sAlias);
|
||||||
|
unlink(GWEN_Buffer_GetStart(nameBuf));
|
||||||
|
GWEN_Buffer_free(nameBuf);
|
||||||
|
AQH_Service_DelUser(sv, userId);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AQH_SESSION *AQH_HttpService_LoadSession(const AQH_SERVICE *sv, const char *sessionUid)
|
||||||
|
{
|
||||||
|
GWEN_BUFFER *nameBuf;
|
||||||
|
int rv;
|
||||||
|
GWEN_DB_NODE *db;
|
||||||
|
AQH_SESSION *session;
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||||
|
GWEN_Buffer_free(nameBuf);
|
||||||
|
GWEN_DB_Group_free(db);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
GWEN_Buffer_free(nameBuf);
|
||||||
|
|
||||||
|
session=AQH_Session_fromDb(db);
|
||||||
|
if (session==NULL) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Error loading session \"%s\" from config group", sessionUid);
|
||||||
|
GWEN_DB_Group_free(db);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
GWEN_DB_Group_free(db);
|
||||||
|
|
||||||
|
rv=_checkSession(session);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "Invalid data for session \"%s\"", sessionUid);
|
||||||
|
AQH_Session_free(session);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int AQH_HttpService_SaveSession(const AQH_SERVICE *sv, const AQH_SESSION *session)
|
||||||
|
{
|
||||||
|
int rv;
|
||||||
|
const char *sUid;
|
||||||
|
GWEN_BUFFER *nameBuf;
|
||||||
|
GWEN_DB_NODE *db;
|
||||||
|
|
||||||
|
rv=_checkSession(session);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
db=GWEN_DB_Group_new("user");
|
||||||
|
rv=AQH_Session_toDb(session, db);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||||
|
GWEN_DB_Group_free(db);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
sUid=AQH_Session_GetUid(session);
|
||||||
|
nameBuf=_getSessionFilePath(sv, sUid);
|
||||||
|
rv=_writeDbFile(GWEN_Buffer_GetStart(nameBuf), db);
|
||||||
|
GWEN_Buffer_free(nameBuf);
|
||||||
|
GWEN_DB_Group_free(db);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int AQH_HttpService_AddSession(AQH_SERVICE *sv, AQH_SESSION *session)
|
||||||
|
{
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
rv=_checkSession(session);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv=AQH_HttpService_SaveSession(sv, session);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
AQH_Service_AddSession(sv, session);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int AQH_HttpService_DelSession(AQH_SERVICE *sv, AQH_SESSION *session)
|
||||||
|
{
|
||||||
|
const char *uid;
|
||||||
|
GWEN_BUFFER *nameBuf;
|
||||||
|
|
||||||
|
uid=AQH_Session_GetUid(session);
|
||||||
|
nameBuf=_getSessionFilePath(sv, uid);
|
||||||
|
unlink(GWEN_Buffer_GetStart(nameBuf));
|
||||||
|
GWEN_Buffer_free(nameBuf);
|
||||||
|
AQH_Service_DelSession(sv, uid);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AQH_MODULE *_ensureModule(AQH_SERVICE *sv, const char *modName)
|
||||||
|
{
|
||||||
|
AQH_MODULE *module;
|
||||||
|
|
||||||
|
module=AQH_Service_GetModuleByName(sv, modName);
|
||||||
|
if (module)
|
||||||
|
return module;
|
||||||
|
|
||||||
|
module=AQH_HttpService_LoadModule(sv, modName);
|
||||||
|
if (module==NULL) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Could not load module \"%s\"", modName);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
AQH_Service_AddModule(sv, module);
|
||||||
|
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AQH_USER *_ensureUser(AQH_SERVICE *sv, const char *alias)
|
||||||
|
{
|
||||||
|
AQH_USER *user;
|
||||||
|
|
||||||
|
user=AQH_Service_GetUserByAlias(sv, alias);
|
||||||
|
if (user)
|
||||||
|
return user;
|
||||||
|
|
||||||
|
user=AQH_HttpService_LoadUser(sv, alias);
|
||||||
|
if (user==NULL) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Could not load user \"%s\"", alias);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
_calculateUserPerms(sv, user);
|
||||||
|
|
||||||
|
AQH_Service_AddUser(sv, user);
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AQH_SESSION *_ensureSession(AQH_SERVICE *sv, const char *sessionUid)
|
||||||
|
{
|
||||||
|
AQH_SESSION *session;
|
||||||
|
|
||||||
|
session=AQH_Service_GetSessionByUid(sv, sessionUid);
|
||||||
|
if (session)
|
||||||
|
return session;
|
||||||
|
|
||||||
|
session=AQH_HttpService_LoadSession(sv, sessionUid);
|
||||||
|
if (session) {
|
||||||
|
AQH_USER *user;
|
||||||
|
|
||||||
|
user=AQH_HttpService_GetUser(sv, AQH_Session_GetUserAlias(session));
|
||||||
|
if (user==NULL) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "User \"%s\" for session \"%s\" not available", AQH_Session_GetUserAlias(session), sessionUid);
|
||||||
|
AQH_Session_free(session);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
AQH_User_Attach(user);
|
||||||
|
AQH_Session_SetUser(session, user);
|
||||||
|
AQH_Service_AddSession(sv, session);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session==NULL) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Could not load session \"%s\"", sessionUid);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GWEN_BUFFER *_getConfigFilePath(const AQH_SERVICE *sv, const char *fileName)
|
||||||
|
{
|
||||||
|
const char *configFolder;
|
||||||
|
|
||||||
|
configFolder=AQH_HttpService_GetConfigFolder(sv);
|
||||||
|
if (!(configFolder && *configFolder)) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "No config folder given");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
GWEN_BUFFER *nameBuf;
|
||||||
|
|
||||||
|
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);
|
||||||
|
return nameBuf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GWEN_BUFFER *_getModuleFilePath(const AQH_SERVICE *sv, const char *modName)
|
||||||
|
{
|
||||||
|
const char *configFolder;
|
||||||
|
|
||||||
|
configFolder=AQH_HttpService_GetConfigFolder(sv);
|
||||||
|
if (!(configFolder && *configFolder)) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "No config folder given");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
GWEN_BUFFER *nameBuf;
|
||||||
|
|
||||||
|
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_MODS GWEN_DIR_SEPARATOR_S);
|
||||||
|
GWEN_Text_EscapeToBuffer(modName, nameBuf);
|
||||||
|
GWEN_Buffer_AppendString(nameBuf, ".conf");
|
||||||
|
return nameBuf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GWEN_BUFFER *_getUserFilePath(const AQH_SERVICE *sv, const char *userAlias)
|
||||||
|
{
|
||||||
|
const char *configFolder;
|
||||||
|
|
||||||
|
configFolder=AQH_HttpService_GetConfigFolder(sv);
|
||||||
|
if (!(configFolder && *configFolder)) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "No config folder given");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
GWEN_BUFFER *nameBuf;
|
||||||
|
|
||||||
|
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_USERS GWEN_DIR_SEPARATOR_S);
|
||||||
|
GWEN_Text_EscapeToBuffer(userAlias, nameBuf);
|
||||||
|
GWEN_Buffer_AppendString(nameBuf, ".conf");
|
||||||
|
return nameBuf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GWEN_BUFFER *_getSessionFilePath(const AQH_SERVICE *sv, const char *sessionUid)
|
||||||
|
{
|
||||||
|
const char *configFolder;
|
||||||
|
|
||||||
|
configFolder=AQH_HttpService_GetConfigFolder(sv);
|
||||||
|
if (!(configFolder && *configFolder)) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "No config folder given");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
GWEN_BUFFER *nameBuf;
|
||||||
|
|
||||||
|
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(sessionUid, nameBuf);
|
||||||
|
GWEN_Buffer_AppendString(nameBuf, ".conf");
|
||||||
|
return nameBuf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int _checkUser(const AQH_USER *user, int ignoreMissingId)
|
||||||
|
{
|
||||||
|
const char *s;
|
||||||
|
|
||||||
|
if (!ignoreMissingId) {
|
||||||
|
uint32_t id;
|
||||||
|
|
||||||
|
id=AQH_User_GetId(user);
|
||||||
|
if (id==0) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Invalid user: no id");
|
||||||
|
return GWEN_ERROR_BAD_DATA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s=AQH_User_GetAlias(user);
|
||||||
|
if (!(s && *s)) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Invalid user: no alias");
|
||||||
|
return GWEN_ERROR_BAD_DATA;
|
||||||
|
}
|
||||||
|
s=AQH_User_GetHashedPassword(user);
|
||||||
|
if (!(s && *s)) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Invalid user: no password");
|
||||||
|
return GWEN_ERROR_BAD_DATA;
|
||||||
|
}
|
||||||
|
s=AQH_User_GetEmail(user);
|
||||||
|
if (!(s && *s)) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Invalid user: no email");
|
||||||
|
return GWEN_ERROR_BAD_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int _checkSession(const AQH_SESSION *session)
|
||||||
|
{
|
||||||
|
const char *s;
|
||||||
|
|
||||||
|
s=AQH_Session_GetUid(session);
|
||||||
|
if (!(s && *s)) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Invalid session: no uid");
|
||||||
|
return GWEN_ERROR_BAD_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
s=AQH_Session_GetUserAlias(session);
|
||||||
|
if (!(s && *s)) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Invalid session: no user alias");
|
||||||
|
return GWEN_ERROR_BAD_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AQH_Session_GetTimestampCreation(session)==NULL) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Invalid session: no creation time");
|
||||||
|
return GWEN_ERROR_BAD_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int _checkModule(const AQH_MODULE *m, int ignoreMissingId)
|
||||||
|
{
|
||||||
|
const char *s;
|
||||||
|
const AQH_ROLE_LIST *roleList;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
if (!ignoreMissingId) {
|
||||||
|
if (AQH_Module_GetId(m)==0) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Invalid module: missing id");
|
||||||
|
return GWEN_ERROR_BAD_DATA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s=AQH_Module_GetName(m);
|
||||||
|
if (!(s && *s)) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Invalid module: missing name");
|
||||||
|
return GWEN_ERROR_BAD_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
roleList=AQH_Module_GetRoleList(m);
|
||||||
|
if (roleList==NULL || AQH_Role_List_GetCount(roleList)<1) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Invalid module: empty or missing role list");
|
||||||
|
return GWEN_ERROR_BAD_DATA;
|
||||||
|
}
|
||||||
|
rv=_checkRoleList(roleList, ignoreMissingId);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Invalid module %s: invalid role definition", AQH_Module_GetName(m));
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int _checkRoleList(const AQH_ROLE_LIST *roleList, int ignoreMissingId)
|
||||||
|
{
|
||||||
|
const AQH_ROLE *r;
|
||||||
|
|
||||||
|
r=AQH_Role_List_First(roleList);
|
||||||
|
while(r) {
|
||||||
|
const char *s;
|
||||||
|
|
||||||
|
if (!ignoreMissingId) {
|
||||||
|
if (AQH_Role_GetId(r)==0) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Invalid role: missing id");
|
||||||
|
return GWEN_ERROR_BAD_DATA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s=AQH_Role_GetName(r);
|
||||||
|
if (!(s && *s)) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Invalid role: missing name");
|
||||||
|
return GWEN_ERROR_BAD_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
r=AQH_Role_List_Next(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void _calculateUserPerms(AQH_SERVICE *sv, AQH_USER *user)
|
||||||
|
{
|
||||||
|
AQH_MODULE_PERMS_LIST *permList;
|
||||||
|
|
||||||
|
permList=AQH_User_GetModulePermList(user);
|
||||||
|
if (permList) {
|
||||||
|
AQH_MODULE_PERMS *p;
|
||||||
|
|
||||||
|
p=AQH_ModulePerms_List_First(permList);
|
||||||
|
while(p) {
|
||||||
|
_calculateModuleUserPerms(sv, p);
|
||||||
|
p=AQH_ModulePerms_List_Next(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AQH_User_AddRuntimeFlags(user, AQH_USER_RTFLAGS_PERMSCALC);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void _calculateModuleUserPerms(AQH_SERVICE *sv, AQH_MODULE_PERMS *p)
|
||||||
|
{
|
||||||
|
uint32_t perms=0;
|
||||||
|
uint32_t addPerms=0;
|
||||||
|
uint32_t delPerms=0;
|
||||||
|
const AQH_MODULE *m;
|
||||||
|
|
||||||
|
m=AQH_Service_GetModuleById(sv, AQH_ModulePerms_GetModuleId(p));
|
||||||
|
if (m==NULL) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Module \"%d\" not found, ignoring", AQH_ModulePerms_GetModuleId(p));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const AQH_ROLE_LIST *roleList;
|
||||||
|
|
||||||
|
roleList=AQH_Module_GetRoleList(m);
|
||||||
|
if (roleList) {
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
j=AQH_ModulePerms_GetRoleArrayArraySize();
|
||||||
|
for(i=0; i<j; i++) {
|
||||||
|
uint8_t roleId;
|
||||||
|
|
||||||
|
roleId=AQH_ModulePerms_GetRoleArrayAt(p, i);
|
||||||
|
if (roleId>0) {
|
||||||
|
AQH_ROLE *r;
|
||||||
|
|
||||||
|
r=AQH_Role_List_GetById(roleList, roleId);
|
||||||
|
if (r==NULL) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Role %d not found in module \"%s\", ignoring", roleId, AQH_Module_GetName(m));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "Module \"%s\": adding perms for role \"%s\"", AQH_Module_GetName(m), AQH_Role_GetName(r));
|
||||||
|
perms|=AQH_Role_GetPerms(r);
|
||||||
|
addPerms|=AQH_Role_GetExplAddPerms(r);
|
||||||
|
delPerms|=AQH_Role_GetExplDelPerms(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
perms|=addPerms;
|
||||||
|
perms&=~delPerms;
|
||||||
|
AQH_ModulePerms_SetPerms(p, perms);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int _writeDbFile(const char *fname, GWEN_DB_NODE *db)
|
||||||
|
{
|
||||||
|
GWEN_BUFFER *tmpFilenameBuf;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
tmpFilenameBuf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||||
|
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);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Error writing db file \"%s\": %d", GWEN_Buffer_GetStart(tmpFilenameBuf), rv);
|
||||||
|
GWEN_Buffer_free(tmpFilenameBuf);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
if (rename(GWEN_Buffer_GetStart(tmpFilenameBuf), fname)<0) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Error renaming tmp file to \"%s\": %d (%s)", fname, errno, strerror(errno));
|
||||||
|
GWEN_Buffer_free(tmpFilenameBuf);
|
||||||
|
return GWEN_ERROR_IO;
|
||||||
|
}
|
||||||
|
unlink(GWEN_Buffer_GetStart(tmpFilenameBuf));
|
||||||
|
GWEN_Buffer_free(tmpFilenameBuf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
48
aqhome/http/httpservice_conf.h
Normal file
48
aqhome/http/httpservice_conf.h
Normal 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_CONF_H
|
||||||
|
#define AQH_HTTP_SERVICE_CONF_H
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "aqhome/service/service.h"
|
||||||
|
|
||||||
|
#include <gwenhywfar/db.h>
|
||||||
|
#include <gwenhywfar/buffer.h>
|
||||||
|
#include <gwenhywfar/msg.h>
|
||||||
|
#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);
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
281
aqhome/http/httpservice_http.c
Normal file
281
aqhome/http/httpservice_http.c
Normal file
@@ -0,0 +1,281 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* 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_http.h"
|
||||||
|
#include "aqhome/http/httpservice_conf.h"
|
||||||
|
#include "aqhome/http/httpservice_p.h"
|
||||||
|
|
||||||
|
#include <gwenhywfar/db.h>
|
||||||
|
#include <gwenhywfar/buffer.h>
|
||||||
|
#include <gwenhywfar/text.h>
|
||||||
|
#include <gwenhywfar/debug.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef GWEN_INHERIT_REF
|
||||||
|
GWEN_INHERIT_REF(AQH_SERVICE, AQH_HTTP_SERVICE)
|
||||||
|
#else
|
||||||
|
extern uint32_t AQH_HTTP_SERVICE_ID;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------------------------------
|
||||||
|
* forward declarations
|
||||||
|
* ------------------------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------------------------------
|
||||||
|
* implementations
|
||||||
|
* ------------------------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
GWEN_MSG *AQH_HttpService_HandleHttpRequest(AQH_SERVICE *sv, GWEN_MSG_ENDPOINT *endpoint, const GWEN_MSG *msgReceived)
|
||||||
|
{
|
||||||
|
AQH_HTTP_SERVICE *xsv;
|
||||||
|
AQH_HTTP_REQUEST *rq;
|
||||||
|
const char *s;
|
||||||
|
AQH_MODULE *m=NULL;
|
||||||
|
AQH_SESSION *session=NULL;
|
||||||
|
GWEN_MSG *msgResponse;
|
||||||
|
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 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
s=AQH_HttpRequest_GetModuleName(rq);
|
||||||
|
if (s && *s) {
|
||||||
|
m=AQH_HttpService_GetModule(sv, s);
|
||||||
|
if (m==NULL) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "Module \"%s\" not found", s);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
AQH_HttpRequest_SetModule(rq, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
s=AQH_HttpRequest_GetSessionId(rq);
|
||||||
|
if (s && *s) {
|
||||||
|
session=AQH_HttpService_GetSession(sv, s);
|
||||||
|
if (session==NULL) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "Session \"%s\" not found", s);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
AQH_HttpRequest_SetSession(rq, session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_setRequestPerms(sv, rq);
|
||||||
|
|
||||||
|
rv=xsv->handleRequestFn(sv, 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");
|
||||||
|
}
|
||||||
|
msgResponse=AQH_HttpRequest_TakeResponseMsg(rq);
|
||||||
|
AQH_HttpRequest_free(rq);
|
||||||
|
return msgResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GWEN_MSG *AQH_HttpService_CreateResponseMsg(AQH_SERVICE *sv, int code, const char *text, const char *protocol)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
msg=GWEN_Msg_fromBytes((const uint8_t*)GWEN_Buffer_GetStart(buf), GWEN_Buffer_GetUsedBytes(buf));
|
||||||
|
GWEN_Buffer_free(buf);
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int AQH_HttpService_AddFile(AQH_SERVICE *sv, GWEN_UNUSED AQH_SESSION *session, const char *fname, GWEN_BUFFER *buf)
|
||||||
|
{
|
||||||
|
if (fname && *fname) {
|
||||||
|
int rv;
|
||||||
|
GWEN_BUFFER *nameBuf;
|
||||||
|
|
||||||
|
nameBuf=_getPageFilePath(sv, NULL, fname);
|
||||||
|
|
||||||
|
rv=GWEN_SyncIo_Helper_ReadFile(GWEN_Buffer_GetStart(nameBuf), buf);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Error reading file \"%s\": %d", fname, rv);
|
||||||
|
GWEN_Buffer_free(nameBuf);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
GWEN_Buffer_free(nameBuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GWEN_BUFFER *_getPageFilePath(const AQH_SERVICE *sv, const char *langFolder, const char *fileName)
|
||||||
|
{
|
||||||
|
const char *sourceFolder;
|
||||||
|
|
||||||
|
sourceFolder=AQH_HttpService_GetSourceFolder(sv);
|
||||||
|
if (!(sourceFolder && *sourceFolder)) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "No source folder given");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
GWEN_BUFFER *nameBuf;
|
||||||
|
|
||||||
|
nameBuf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||||
|
GWEN_Buffer_AppendString(nameBuf, sourceFolder);
|
||||||
|
GWEN_Buffer_AppendString(nameBuf, GWEN_DIR_SEPARATOR_S);
|
||||||
|
if (langFolder && *langFolder) {
|
||||||
|
GWEN_Buffer_AppendString(nameBuf, langFolder);
|
||||||
|
GWEN_Buffer_AppendString(nameBuf, GWEN_DIR_SEPARATOR_S);
|
||||||
|
}
|
||||||
|
GWEN_Text_EscapeToBuffer(fileName, nameBuf);
|
||||||
|
return nameBuf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void _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) {
|
||||||
|
if (session) {
|
||||||
|
AQH_USER * user;
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "Session but no user, SNH!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "No session");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "No module");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
40
aqhome/http/httpservice_http.h
Normal file
40
aqhome/http/httpservice_http.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* 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_HTTP_H
|
||||||
|
#define AQH_HTTP_SERVICE_HTTP_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "aqhome/service/service.h"
|
||||||
|
|
||||||
|
#include <gwenhywfar/endpoint.h>
|
||||||
|
#include <gwenhywfar/msg.h>
|
||||||
|
#include <gwenhywfar/url.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define AQH_HTTP_SERVICE_SESSIONCOOKIE "sessionid"
|
||||||
|
|
||||||
|
|
||||||
|
AQHOME_API GWEN_MSG *AQH_HttpService_HandleHttpRequest(AQH_SERVICE *sv, GWEN_MSG_ENDPOINT *endpoint, const GWEN_MSG *msgReceived);
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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 int AQH_HttpService_AddFile(AQH_SERVICE *sv, AQH_SESSION *session, const char *fname, GWEN_BUFFER *buf);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
45
aqhome/http/httpservice_login.c
Normal file
45
aqhome/http/httpservice_login.c
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* 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_login.h"
|
||||||
|
#include "aqhome/http/httpservice_p.h"
|
||||||
|
|
||||||
|
#include <gwenhywfar/db.h>
|
||||||
|
#include <gwenhywfar/buffer.h>
|
||||||
|
#include <gwenhywfar/text.h>
|
||||||
|
#include <gwenhywfar/debug.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Login process:
|
||||||
|
- GET: send a login page
|
||||||
|
- POST:
|
||||||
|
- get USER and PASS
|
||||||
|
- look for user (maybe add virtual function to load a user?)
|
||||||
|
- check password
|
||||||
|
- if all okay:
|
||||||
|
- create session
|
||||||
|
- add header "set-cookie"
|
||||||
|
- redirect to main page
|
||||||
|
*/
|
||||||
|
|
||||||
|
GWEN_MSG *AQH_HttpService_HandleLoginUrl(AQH_SERVICE *sv, const GWEN_MSG *msgReceived, const GWEN_URL *url)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
30
aqhome/http/httpservice_login.h
Normal file
30
aqhome/http/httpservice_login.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* 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_LOGIN_H
|
||||||
|
#define AQH_HTTP_SERVICE_LOGIN_H
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "aqhome/http/httpservice.h"
|
||||||
|
|
||||||
|
#include <gwenhywfar/db.h>
|
||||||
|
#include <gwenhywfar/buffer.h>
|
||||||
|
#include <gwenhywfar/msg.h>
|
||||||
|
#include <gwenhywfar/url.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GWEN_MSG *AQH_HttpService_HandleLoginUrl(AQH_SERVICE *sv, const GWEN_MSG *msgReceived, const GWEN_URL *url);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -13,14 +13,27 @@
|
|||||||
#include "aqhome/http/httpservice.h"
|
#include "aqhome/http/httpservice.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define AQH_HTTP_SERVICE_DEFAULT_MAXSESSIONAGE 600 /* 10m */
|
||||||
|
|
||||||
|
|
||||||
typedef struct AQH_HTTP_SERVICE AQH_HTTP_SERVICE;
|
typedef struct AQH_HTTP_SERVICE AQH_HTTP_SERVICE;
|
||||||
struct AQH_HTTP_SERVICE {
|
struct AQH_HTTP_SERVICE {
|
||||||
char *sourceFolder;
|
char *sourceFolder;
|
||||||
|
char *configFolder;
|
||||||
|
|
||||||
char *siteHeader;
|
char *siteHeader;
|
||||||
char *siteFooter;
|
char *siteFooter;
|
||||||
|
|
||||||
|
uint32_t lastModuleId;
|
||||||
|
uint32_t lastUserId;
|
||||||
|
|
||||||
|
int maxSessionAgeInSecs;
|
||||||
|
|
||||||
|
GWEN_MUTEX *moduleMutex;
|
||||||
|
GWEN_MUTEX *userMutex;
|
||||||
|
GWEN_MUTEX *sessionMutex;
|
||||||
|
|
||||||
|
AQH_HTTP_SERVICE_HANDLEREQUEST_FN handleRequestFn;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -64,6 +64,8 @@
|
|||||||
<preset>NULL</preset>
|
<preset>NULL</preset>
|
||||||
<access>public</access>
|
<access>public</access>
|
||||||
<flags>own</flags>
|
<flags>own</flags>
|
||||||
|
<getflags>none</getflags>
|
||||||
|
<setflags>none</setflags>
|
||||||
</member>
|
</member>
|
||||||
|
|
||||||
</members>
|
</members>
|
||||||
|
|||||||
@@ -38,13 +38,6 @@
|
|||||||
<flags>with_getbymember</flags>
|
<flags>with_getbymember</flags>
|
||||||
</member>
|
</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">
|
<member name="exclAddPerms" type="uint32_t" maxlen="4">
|
||||||
<default>0</default>
|
<default>0</default>
|
||||||
<preset>0</preset>
|
<preset>0</preset>
|
||||||
@@ -59,13 +52,21 @@
|
|||||||
<flags></flags>
|
<flags></flags>
|
||||||
</member>
|
</member>
|
||||||
|
|
||||||
<member name="roleArray" type="uint32_t_array" maxlen="16">
|
<member name="roleArray" type="uint8_t_array" maxlen="16">
|
||||||
<default>0</default>
|
<default>0</default>
|
||||||
<preset>0</preset>
|
<preset>0</preset>
|
||||||
<access>public</access>
|
<access>public</access>
|
||||||
<flags></flags>
|
<flags></flags>
|
||||||
</member>
|
</member>
|
||||||
|
|
||||||
|
|
||||||
|
<member name="perms" type="uint32_t" maxlen="4">
|
||||||
|
<default>0</default>
|
||||||
|
<preset>0</preset>
|
||||||
|
<access>public</access>
|
||||||
|
<flags>volatile</flags>
|
||||||
|
</member>
|
||||||
|
|
||||||
</members>
|
</members>
|
||||||
|
|
||||||
</type>
|
</type>
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
<members>
|
<members>
|
||||||
|
|
||||||
<member name="id" type="uint32_t" maxlen="4">
|
<member name="id" type="uint8_t" maxlen="1">
|
||||||
<default>0</default>
|
<default>0</default>
|
||||||
<preset>0</preset>
|
<preset>0</preset>
|
||||||
<access>public</access>
|
<access>public</access>
|
||||||
@@ -50,14 +50,14 @@
|
|||||||
<flags></flags>
|
<flags></flags>
|
||||||
</member>
|
</member>
|
||||||
|
|
||||||
<member name="exclAddPerms" type="uint32_t" maxlen="4">
|
<member name="explAddPerms" type="uint32_t" maxlen="4">
|
||||||
<default>0</default>
|
<default>0</default>
|
||||||
<preset>0</preset>
|
<preset>0</preset>
|
||||||
<access>public</access>
|
<access>public</access>
|
||||||
<flags></flags>
|
<flags></flags>
|
||||||
</member>
|
</member>
|
||||||
|
|
||||||
<member name="exclDelPerms" type="uint32_t" maxlen="4">
|
<member name="explDelPerms" type="uint32_t" maxlen="4">
|
||||||
<default>0</default>
|
<default>0</default>
|
||||||
<preset>0</preset>
|
<preset>0</preset>
|
||||||
<access>public</access>
|
<access>public</access>
|
||||||
|
|||||||
@@ -149,9 +149,9 @@ AQH_SESSION_LIST *AQH_Service_GetSessionList(const AQH_SERVICE *sv)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
AQH_SESSION *AQH_Service_GetSessionById(const AQH_SERVICE *sv, uint32_t sessionId)
|
AQH_SESSION *AQH_Service_GetSessionByUid(const AQH_SERVICE *sv, const char *sessionUid)
|
||||||
{
|
{
|
||||||
return sv?AQH_Session_List_GetById(sv->sessionList, sessionId):NULL;
|
return sv?AQH_Session_List_GetByUid(sv->sessionList, sessionUid):NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -164,12 +164,12 @@ void AQH_Service_AddSession(AQH_SERVICE *sv, AQH_SESSION *session)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void AQH_Service_DelSession(AQH_SERVICE *sv, uint32_t id)
|
void AQH_Service_DelSession(AQH_SERVICE *sv, const char *sid)
|
||||||
{
|
{
|
||||||
if (sv && id) {
|
if (sv && sid && *sid) {
|
||||||
AQH_SESSION *session;
|
AQH_SESSION *session;
|
||||||
|
|
||||||
session=AQH_Session_List_GetById(sv->sessionList, id);
|
session=AQH_Session_List_GetByUid(sv->sessionList, sid);
|
||||||
if (session) {
|
if (session) {
|
||||||
AQH_Session_List_Del(session);
|
AQH_Session_List_Del(session);
|
||||||
AQH_Session_free(session);
|
AQH_Session_free(session);
|
||||||
|
|||||||
@@ -44,9 +44,9 @@ 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 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_LIST *AQH_Service_GetSessionList(const AQH_SERVICE *sv);
|
||||||
AQHOME_API AQH_SESSION *AQH_Service_GetSessionById(const AQH_SERVICE *sv, uint32_t sessionId);
|
AQHOME_API AQH_SESSION *AQH_Service_GetSessionByUid(const AQH_SERVICE *sv, const char *sessionUid);
|
||||||
AQHOME_API void AQH_Service_AddSession(AQH_SERVICE *sv, AQH_SESSION *session);
|
AQHOME_API void AQH_Service_AddSession(AQH_SERVICE *sv, AQH_SESSION *session);
|
||||||
AQHOME_API void AQH_Service_DelSession(AQH_SERVICE *sv, uint32_t id);
|
AQHOME_API void AQH_Service_DelSession(AQH_SERVICE *sv, const char *sid);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
with_db
|
with_db
|
||||||
with_list1
|
with_list1
|
||||||
with_list2
|
with_list2
|
||||||
|
nodup
|
||||||
|
nocopy
|
||||||
</flags>
|
</flags>
|
||||||
|
|
||||||
<headers>
|
<headers>
|
||||||
@@ -31,18 +33,11 @@
|
|||||||
|
|
||||||
<members>
|
<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">
|
<member name="uid" type="char_ptr" maxlen="64">
|
||||||
<default>0</default>
|
<default>0</default>
|
||||||
<preset>0</preset>
|
<preset>0</preset>
|
||||||
<access>public</access>
|
<access>public</access>
|
||||||
<flags></flags>
|
<flags>with_getbymember</flags>
|
||||||
</member>
|
</member>
|
||||||
|
|
||||||
<member name="flags" type="uint32_t" maxlen="4">
|
<member name="flags" type="uint32_t" maxlen="4">
|
||||||
@@ -52,9 +47,9 @@
|
|||||||
<flags>with_flags</flags>
|
<flags>with_flags</flags>
|
||||||
</member>
|
</member>
|
||||||
|
|
||||||
<member name="userId" type="uint32_t" maxlen="4">
|
<member name="userAlias" type="char_ptr" maxlen="64">
|
||||||
<default>0</default>
|
<default>NULL</default>
|
||||||
<preset>0</preset>
|
<preset>NULL</preset>
|
||||||
<access>public</access>
|
<access>public</access>
|
||||||
<flags></flags>
|
<flags></flags>
|
||||||
</member>
|
</member>
|
||||||
@@ -87,8 +82,8 @@
|
|||||||
<preset>NULL</preset>
|
<preset>NULL</preset>
|
||||||
<access>public</access>
|
<access>public</access>
|
||||||
<setflags>assign</setflags>
|
<setflags>assign</setflags>
|
||||||
<dupflags>assign</dupflags>
|
<getflags>none</getflags>
|
||||||
<flags>volatile</flags>
|
<flags>volatile nodup nocopy</flags>
|
||||||
</member>
|
</member>
|
||||||
|
|
||||||
</members>
|
</members>
|
||||||
|
|||||||
@@ -14,6 +14,9 @@
|
|||||||
with_db
|
with_db
|
||||||
with_list1
|
with_list1
|
||||||
with_list2
|
with_list2
|
||||||
|
with_refcount
|
||||||
|
nodup
|
||||||
|
nocopy
|
||||||
</flags>
|
</flags>
|
||||||
|
|
||||||
<headers>
|
<headers>
|
||||||
@@ -28,6 +31,14 @@
|
|||||||
|
|
||||||
</lang>
|
</lang>
|
||||||
|
|
||||||
|
<defines>
|
||||||
|
<define id="AQH_USER_RTFLAGS" prefix="AQH_USER_RTFLAGS_">
|
||||||
|
<item name="MODIFIED" value="0x00000001" />
|
||||||
|
<item name="PERMSCALC" value="0x00000002" />
|
||||||
|
</define>
|
||||||
|
|
||||||
|
</defines>
|
||||||
|
|
||||||
|
|
||||||
<members>
|
<members>
|
||||||
|
|
||||||
@@ -103,6 +114,14 @@
|
|||||||
<flags>own</flags>
|
<flags>own</flags>
|
||||||
</member>
|
</member>
|
||||||
|
|
||||||
|
|
||||||
|
<member name="runtimeFlags" type="uint32_t" maxlen="4">
|
||||||
|
<default>0</default>
|
||||||
|
<preset>0</preset>
|
||||||
|
<access>public</access>
|
||||||
|
<flags>volatile with_flags</flags>
|
||||||
|
</member>
|
||||||
|
|
||||||
</members>
|
</members>
|
||||||
|
|
||||||
</type>
|
</type>
|
||||||
|
|||||||
Reference in New Issue
Block a user