aqhome: more work on http service.
This commit is contained in:
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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user