diff --git a/.gitignore b/.gitignore index fb3350f..9201dfd 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ aqhome.log aqhomed.vg aqhome-mqttlog.vg aqhome-storage.vg +aqhome-storage.pid diff --git a/apps/aqhome-storage/0BUILD b/apps/aqhome-storage/0BUILD index 8194cf6..4dc0482 100644 --- a/apps/aqhome-storage/0BUILD +++ b/apps/aqhome-storage/0BUILD @@ -45,6 +45,8 @@ cleanup.h u_login.h u_rooms.h + u_static.h + u_static_p.h aqhomehttp.h aqhomehttp_p.h @@ -61,6 +63,7 @@ cleanup.c u_login.c u_rooms.c + u_static.c main.c aqhomehttp.c diff --git a/apps/aqhome-storage/aqhomestorage_p.h b/apps/aqhome-storage/aqhomestorage_p.h index 7eef60e..76a2f2f 100644 --- a/apps/aqhome-storage/aqhomestorage_p.h +++ b/apps/aqhome-storage/aqhomestorage_p.h @@ -32,6 +32,7 @@ #define AQHOME_STORAGE_SITEHEADER "site-header.html" #define AQHOME_STORAGE_SITEFOOTER "site-footer.html" +#define AQHOME_STORAGE_STATIC_RELFOLDER "static" struct AQHOME_STORAGE { diff --git a/apps/aqhome-storage/init_http.c b/apps/aqhome-storage/init_http.c index 3b59ad6..5f38309 100644 --- a/apps/aqhome-storage/init_http.c +++ b/apps/aqhome-storage/init_http.c @@ -16,6 +16,7 @@ #include "./aqhomehttp.h" #include "./u_login.h" #include "./u_rooms.h" +#include "./u_static.h" #include "aqhome/msg/endpoint_tty.h" #include "aqhome/ipc/endpoint_ipc.h" @@ -72,6 +73,7 @@ static GWEN_MSG_ENDPOINT *_acceptHttpFn(GWEN_MSG_ENDPOINT *ep, GWEN_SOCKET *sk, static int _createUrlHandler_login(AQHOME_STORAGE *aqh); static int _createUrlHandler_rooms(AQHOME_STORAGE *aqh); +static int _createUrlHandler_static(AQHOME_STORAGE *aqh); @@ -116,6 +118,12 @@ int AqHomeStorage_SetupHttp(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs) return rv; } + rv=_createUrlHandler_static(aqh); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + return rv; + } + } return 0; } @@ -241,4 +249,24 @@ int _createUrlHandler_rooms(AQHOME_STORAGE *aqh) +int _createUrlHandler_static(AQHOME_STORAGE *aqh) +{ + AQH_HTTP_URLHANDLER *uh; + GWEN_BUFFER *nameBuf; + const char *sourceFolder; + + sourceFolder=AQH_HttpService_GetSourceFolder(aqh->httpService); + nameBuf=GWEN_Buffer_new(0, 256, 0, 1); + GWEN_Buffer_AppendString(nameBuf, sourceFolder); + GWEN_Buffer_AppendString(nameBuf, GWEN_DIR_SEPARATOR_S AQHOME_STORAGE_STATIC_RELFOLDER GWEN_DIR_SEPARATOR_S "pics"); + + uh=AQH_StaticHttpUrlHandler_new(aqh->httpService, GWEN_Buffer_GetStart(nameBuf)); + GWEN_Buffer_free(nameBuf); + AQH_HttpUrlHandler_AddUrlPattern(uh, "/pics/*"); + AQH_HttpService_AddUrlHandler(aqh->httpService, uh); + return 0; +} + + + diff --git a/apps/aqhome-storage/u_rooms.c b/apps/aqhome-storage/u_rooms.c index b261e8a..3a1e0b9 100644 --- a/apps/aqhome-storage/u_rooms.c +++ b/apps/aqhome-storage/u_rooms.c @@ -42,9 +42,13 @@ static GWEN_MSG *_handlePost(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq); static void _handleGetList(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_BUFFER *pageBuf); static void _handleGetAdd(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_BUFFER *pageBuf); +static void _handleGetEdit(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, int id, GWEN_BUFFER *pageBuf); static GWEN_MSG *_handlePostAdd(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq); +static GWEN_MSG *_handlePostEdit(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, int id); static int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf); +static int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf); static GWEN_MSG *_addRoomCreateResponse(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq); +static GWEN_MSG *_editRoomCreateResponse(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, int id); @@ -125,6 +129,8 @@ GWEN_MSG *_handleGet(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq) _handleGetList(uh, rq, pageBuf); else if (strcasecmp(s, "add")==0) _handleGetAdd(uh, rq, pageBuf); + else if (strcasecmp(s, "edit")==0) + _handleGetEdit(uh, rq, GWEN_StringList_StringAsIntAt(sl, 2, 0), pageBuf); else { DBG_ERROR(NULL, "Invalid url (2nd member is [%s])", s); GWEN_Buffer_free(pageBuf); @@ -170,6 +176,8 @@ GWEN_MSG *_handlePost(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq) if (s && *s) { if (strcasecmp(s, "add")==0) return _handlePostAdd(uh, rq); + else if (strcasecmp(s, "edit")==0) + return _handlePostEdit(uh, rq, GWEN_StringList_StringAsIntAt(sl, 2, 0)); else { DBG_ERROR(NULL, "Invalid url (2nd member is [%s])", s); return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 404, "Not found", protocol, NULL); @@ -207,7 +215,7 @@ void _handleGetList(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_BUFFER * "

%s

" "" "" - " " + " " "", I18N("Rooms"), I18N("Name"), @@ -226,10 +234,15 @@ void _handleGetList(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_BUFFER * id=(long unsigned int) AQH_Room_GetId(r); name=AQH_Room_GetName(r); descr=AQH_Room_GetDescription(r); - GWEN_Buffer_AppendArgs(pageBuf, "", id, name?name:"", descr?descr:""); - - r=AQH_Room_List_Next(r); - } + GWEN_Buffer_AppendArgs(pageBuf, + "" + "" + "", + id, name?name:"", descr?descr:"", id); + + r=AQH_Room_List_Next(r); + } } GWEN_Buffer_AppendString(pageBuf, ""); GWEN_Buffer_AppendArgs(pageBuf, "
Id%s%s
Id%s%s
%lu%s%s
%lu%s%s" + "
%s
", I18N("Add Room")); @@ -256,7 +269,61 @@ void _handleGetAdd(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_BUFFER *p } else { DBG_INFO(NULL, "No permissions to add a room."); - GWEN_Buffer_AppendString(pageBuf, "

No permissions to add a room.

"); + GWEN_Buffer_AppendArgs(pageBuf, "

%s

", I18N("No permissions to add a room.")); + } +} + + + +void _handleGetEdit(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, int id, GWEN_BUFFER *pageBuf) +{ + uint32_t perms; + + DBG_ERROR(NULL, "EDIT"); + perms=AQH_HttpRequest_GetModulePerms(rq); + if (perms & AQHOME_HTTP_PERMS_EDIT_ROOM) { + AQH_SERVICE *sv; + AQH_STORAGE *sto; + + sv=AQH_HttpUrlHandler_GetHttpService(uh); + sto=AqHomeHttpService_GetStorage(sv); + if (sto) { + if (id>0) { + const AQH_ROOM *r; + + r=AQH_Storage_GetRoomById(sto, id); + if (r) { + GWEN_DB_NODE *db; + int rv; + + db=GWEN_DB_Group_new("room"); + rv=AQH_Room_toDb(r, db); + if (rv>=0) + _writeEditPage(uh, rq, NULL, pageBuf); + else { + DBG_ERROR(NULL, "Error writing room %d to db", id); + GWEN_Buffer_AppendArgs(pageBuf, "

%s

", I18N("Internal error.")); + } + GWEN_DB_Group_free(db); + } + else { + DBG_ERROR(NULL, "Room %d not found", id); + GWEN_Buffer_AppendArgs(pageBuf, "

%s

", I18N("Room not found.")); + } + } + else { + DBG_ERROR(NULL, "Missing room id"); + GWEN_Buffer_AppendArgs(pageBuf, "

%s

", I18N("Missing or invalid room id.")); + } + } + else { + DBG_ERROR(NULL, "No storage"); + GWEN_Buffer_AppendArgs(pageBuf, "

%s

", I18N("Internal error.")); + } + } + else { + DBG_INFO(NULL, "No permissions to edit a room."); + GWEN_Buffer_AppendArgs(pageBuf, "

%s

", I18N("No permissions to edit a room.")); } } @@ -297,6 +364,44 @@ int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *d +int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf) +{ + unsigned long int id; + const char *name=NULL; + const char *descr=NULL; + + if (dbValues) { + id=GWEN_DB_GetIntValue(dbValues, "id", 0, 0); + name=GWEN_DB_GetCharValue(dbValues, "name", 0, NULL); + descr=GWEN_DB_GetCharValue(dbValues, "description", 0, NULL); + } + GWEN_Buffer_AppendArgs(pageBuf, + "

%s


\n" + "
" + " " + " " + " " + " " + " " + " " + " " + " " + " " + "
" + " " + "
", + I18N("Edit a Room"), + id, + I18N("Room Name"), + name?name:"", + I18N("Description"), + descr?descr:"", + I18N("Submit")); + return 0; +} + + + GWEN_MSG *_handlePostAdd(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq) { const char *protocol; @@ -325,6 +430,34 @@ GWEN_MSG *_handlePostAdd(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq) +GWEN_MSG *_handlePostEdit(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, int id) +{ + const char *protocol; + AQH_SERVICE *sv; + uint32_t perms; + + protocol=AQH_HttpRequest_GetProtocol(rq); + sv=AQH_HttpUrlHandler_GetHttpService(uh); + perms=AQH_HttpRequest_GetModulePerms(rq); + if (perms & AQHOME_HTTP_PERMS_ADD_ROOM) { + AQH_STORAGE *sto; + + sto=AqHomeHttpService_GetStorage(sv); + if (sto) { + return _editRoomCreateResponse(uh, rq, id); + } + else { + DBG_ERROR(NULL, "No storage"); + return AQH_HttpService_CreateResponseMsg(sv, 500, "Internal error", protocol, NULL); + } + } + else { + return AQH_HttpService_CreateResponseMsg(sv, 403, "Forbidden", protocol, NULL); + } +} + + + GWEN_MSG *_addRoomCreateResponse(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq) { AQH_SERVICE *sv; @@ -382,4 +515,62 @@ GWEN_MSG *_addRoomCreateResponse(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq) +GWEN_MSG *_editRoomCreateResponse(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, int id) +{ + AQH_SERVICE *sv; + const char *protocol; + GWEN_DB_NODE *db; + const char *roomName; + const char *roomDescr; + AQH_STORAGE *sto; + + sv=AQH_HttpUrlHandler_GetHttpService(uh); + protocol=AQH_HttpRequest_GetProtocol(rq); + db=AQH_HttpRequest_GetDbPostBody(rq); + + roomName=GWEN_DB_GetCharValue(db, "name", 0, NULL); + roomDescr=GWEN_DB_GetCharValue(db, "description", 0, NULL); + + if (!(roomName && *roomName)) { + DBG_INFO(NULL, "Missing room name"); + return AQH_HttpUrlHandler_CreatePageMessage(uh, rq, "red", I18N("Missing room name"), 1, db, _writeAddPage); + } + + sto=AqHomeHttpService_GetStorage(sv); + if (sto) { + AQH_ROOM *r; + int rv; + + rv=AqHomeHttpService_LockStorage(sv); + if (rv<0) { + DBG_ERROR(NULL, "Error locking storage"); + return AQH_HttpService_CreateResponseMsg(sv, 500, "Internal error", protocol, NULL); + } + + r=AQH_Storage_GetRoomById(sto, id); + if (r==NULL) { + AqHomeHttpService_UnlockStorage(sv); + DBG_ERROR(NULL, "Room %d not found", id); + return AQH_HttpUrlHandler_CreatePageMessage(uh, rq, "red", I18N("Room not found"), 1, db, _writeEditPage); + } + + /* edit room */ + AQH_Room_SetName(r, roomName); + if (roomDescr && *roomDescr) + AQH_Room_SetDescription(r, roomDescr); + AQH_Storage_AddRuntimeFlags(sto, AQH_STORAGE_RTFLAGS_MODIFIED); + + rv=AqHomeHttpService_UnlockStorage(sv); + if (rv<0) { + DBG_ERROR(NULL, "Error unlocking storage"); + return AQH_HttpService_CreateResponseMsg(sv, 500, "Internal error", protocol, NULL); + } + return AQH_HttpService_CreateRedirectingResponseMsg(sv, protocol, "/rooms/list"); + } + else + return AQH_HttpService_CreateResponseMsg(sv, 500, "Internal error", protocol, NULL); +} + + + diff --git a/apps/aqhome-storage/u_static.c b/apps/aqhome-storage/u_static.c new file mode 100644 index 0000000..d7af540 --- /dev/null +++ b/apps/aqhome-storage/u_static.c @@ -0,0 +1,291 @@ +/**************************************************************************** + * 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 +#endif + + +#include "./u_static_p.h" +#include "./aqhomehttp.h" +#include "aqhome/http/httpservice.h" +#include "aqhome/http/httpservice_http.h" +#include "aqhome/http/httpservice_conf.h" + +#include +#include +#include + + +GWEN_INHERIT(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_STATIC); + + + +/* ------------------------------------------------------------------------------------------------ + * defines + * ------------------------------------------------------------------------------------------------ + */ + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void GWENHYWFAR_CB _freeData(void *bp, void *p); +static int _handleUrl(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq); +static GWEN_MSG *_handleGet(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq); +static void _readFileList(AQH_HTTP_URLHANDLER *uh); +static GWEN_BUFFER *_readFileIntoBuffer(AQH_HTTP_URLHANDLER *uh, const char *requestedFilename); +static const char *_getContentTypeFromFilename(const char *filename); +static GWEN_MSG *_createFileResponseMsg(AQH_HTTP_URLHANDLER *uh, + const char *protocol, + const char *contentType, + const uint8_t *ptr, uint32_t len); + + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + +AQH_HTTP_URLHANDLER *AQH_StaticHttpUrlHandler_new(AQH_SERVICE *sv, const char *folder) +{ + AQH_HTTP_URLHANDLER *uh; + AQH_URLHANDLER_STATIC *xuh; + + uh=AQH_HttpUrlHandler_new(sv); + GWEN_NEW_OBJECT(AQH_URLHANDLER_STATIC, xuh); + GWEN_INHERIT_SETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_STATIC, uh, xuh, _freeData); + + AQH_HttpUrlHandler_SetFolder(uh, folder); + AQH_HttpUrlHandler_SetHandleFn(uh, _handleUrl); + + _readFileList(uh); + + return uh; +} + + + +void _freeData(void *bp, void *p) +{ + AQH_URLHANDLER_STATIC *xuh; + + xuh=(AQH_URLHANDLER_STATIC*)p; + GWEN_StringList_free(xuh->fileList); + GWEN_FREE_OBJECT(xuh); +} + + + +int _handleUrl(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq) +{ + const char *protocol; + const char *cmd; + GWEN_MSG *msgOut; + + AQH_HttpService_SetupModuleAndPerms(AQH_HttpUrlHandler_GetHttpService(uh), rq, "aqhome"); + AQH_HttpRequest_SetupUrlPathMembers(rq); + + protocol=AQH_HttpRequest_GetProtocol(rq); + cmd=AQH_HttpRequest_GetCommand(rq); + if (cmd && *cmd) { + if (strcasecmp(cmd, "GET")==0) + msgOut=_handleGet(uh, rq); + else { + msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 405, "Method not allowed", protocol, NULL); + } + AQH_HttpRequest_SetResponseMsg(rq, msgOut); + return 0; + } + else { + DBG_ERROR(AQH_LOGDOMAIN, "No command in request"); + return GWEN_ERROR_INVALID; + } +} + + + +GWEN_MSG *_handleGet(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq) +{ + AQH_URLHANDLER_STATIC *xuh; + AQH_SERVICE *sv; + const char *protocol; + const GWEN_STRINGLIST *sl; + + xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_STATIC, uh); + if (xuh==NULL) { + DBG_ERROR(NULL, "Not a AQH_URLHANDLER_STATIC object"); + return NULL; + } + + sv=AQH_HttpUrlHandler_GetHttpService(uh); + protocol=AQH_HttpRequest_GetProtocol(rq); + + /* handle middle part (header - middle - footer) */ + sl=AQH_HttpRequest_GetUrlPathMembers(rq); + if (sl) { + const char *s; + + s=GWEN_StringList_StringAt(sl, 1); + if (!(s && *s)) { + DBG_ERROR(NULL, "Invalid url (2nd member is [%s])", s); + return AQH_HttpService_CreateResponseMsg(sv, 404, "Not found", protocol, NULL); + } + else { + GWEN_BUFFER *fileBuf; + const char *contentType; + GWEN_MSG *msgOut; + + contentType=_getContentTypeFromFilename(s); + DBG_INFO(NULL, "Reading file \"%s\" (%s)", s, contentType); + fileBuf=_readFileIntoBuffer(uh, s); + if (fileBuf==NULL) { + DBG_INFO(NULL, "here"); + return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 404, "Not found", protocol, NULL); + } + msgOut=_createFileResponseMsg(uh, protocol, contentType, + (const uint8_t*) GWEN_Buffer_GetStart(fileBuf), GWEN_Buffer_GetUsedBytes(fileBuf)); + GWEN_Buffer_free(fileBuf); + return msgOut; + } + } + else { + DBG_ERROR(NULL, "No list of url members"); + return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL); + } +} + + + +void _readFileList(AQH_HTTP_URLHANDLER *uh) +{ + AQH_URLHANDLER_STATIC *xuh; + const char *folder; + + xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_STATIC, uh); + + GWEN_StringList_free(xuh->fileList); + xuh->fileList=NULL; + folder=AQH_HttpUrlHandler_GetFolder(uh); + if (folder && *folder) { + GWEN_STRINGLIST *fileList; + + fileList=AQH_HttpService_GetFolderFileList(folder, NULL, 1); + if (fileList) { + GWEN_StringList_RemoveString(fileList, "."); + GWEN_StringList_RemoveString(fileList, ".."); + GWEN_StringList_free(xuh->fileList); + xuh->fileList=fileList; + } + else { + DBG_INFO(NULL, "No file list (empty folder?)"); + } + } +} + + + +GWEN_BUFFER *_readFileIntoBuffer(AQH_HTTP_URLHANDLER *uh, const char *requestedFilename) +{ + AQH_URLHANDLER_STATIC *xuh; + const char *folder; + + xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_STATIC, uh); + folder=AQH_HttpUrlHandler_GetFolder(uh); + + if (!(xuh->fileList && GWEN_StringList_Count(xuh->fileList)>0)) { + DBG_INFO(NULL, "Reading file list for folder \"%s\"", folder); + _readFileList(uh); + } + + if (!(xuh->fileList && GWEN_StringList_Count(xuh->fileList)>0)) { + DBG_INFO(NULL, "No file list (empty or missing/bad folder? Permissions?"); + return NULL; + } + + if (GWEN_StringList_HasString(xuh->fileList, requestedFilename)) { + GWEN_BUFFER *nameBuf; + GWEN_BUFFER *fileBuf; + int rv; + + fileBuf=GWEN_Buffer_new(0, 1024, 0, 1); + nameBuf=GWEN_Buffer_new(0, 256, 0, 1); + GWEN_Buffer_AppendString(nameBuf, folder); + GWEN_Buffer_AppendString(nameBuf, GWEN_DIR_SEPARATOR_S); + GWEN_Buffer_AppendString(nameBuf, requestedFilename); + DBG_INFO(NULL, "Reading file \"%s\"", GWEN_Buffer_GetStart(nameBuf)); + rv=GWEN_SyncIo_Helper_ReadFile(GWEN_Buffer_GetStart(nameBuf), fileBuf); + if (rv<0) { + DBG_ERROR(NULL, "Error reading file \"%s\" (%d)", GWEN_Buffer_GetStart(nameBuf), rv); + GWEN_Buffer_free(nameBuf); + GWEN_Buffer_free(fileBuf); + return NULL; + } + GWEN_Buffer_free(nameBuf); + return fileBuf; + } + else { + DBG_INFO(NULL, "File \"%s\" not found in folder \"%s\"", requestedFilename, folder); + return NULL; + } +} + + + +GWEN_MSG *_createFileResponseMsg(AQH_HTTP_URLHANDLER *uh, + const char *protocol, + const char *contentType, + const uint8_t *ptr, uint32_t len) +{ + GWEN_BUFFER *buf; + GWEN_MSG *msg; + GWEN_DB_NODE *db; + + buf=GWEN_Buffer_new(0, len+256, 0, 1); + AQH_HttpService_AddStatusLine(AQH_HttpUrlHandler_GetHttpService(uh), 200, "OK", protocol, buf); + + db=GWEN_DB_Group_new("header"); + GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Connection", "Keep-Alive"); + GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Content-Type", contentType); + GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Content-Length", len); + AQH_HttpService_AddHeader(AQH_HttpUrlHandler_GetHttpService(uh), db, buf); + GWEN_DB_Group_free(db); + + GWEN_Buffer_AppendBytes(buf, (const char *) ptr, len); + + msg=GWEN_Msg_fromBytes((const uint8_t*)GWEN_Buffer_GetStart(buf), GWEN_Buffer_GetUsedBytes(buf)); + GWEN_Buffer_free(buf); + return msg; +} + + + +const char *_getContentTypeFromFilename(const char *filename) +{ + if (filename) { + const char *s; + + s=strrchr(filename, '.'); + if (s) { + if (strcasecmp(s, ".png")==0) + return "image/png"; + else if (strcasecmp(s, ".jpg")==0) + return "image/jpg"; + } + } + return "application/x-binary"; +} + + + + diff --git a/apps/aqhome-storage/u_static.h b/apps/aqhome-storage/u_static.h new file mode 100644 index 0000000..c692387 --- /dev/null +++ b/apps/aqhome-storage/u_static.h @@ -0,0 +1,24 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2023 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifndef AQHOME_STORAGE_U_STATIC_H +#define AQHOME_STORAGE_U_STATIC_H + + +#include "aqhome/http/urlhandler.h" + +#include + + +AQH_HTTP_URLHANDLER *AQH_StaticHttpUrlHandler_new(AQH_SERVICE *sv, const char *folder); + + + +#endif + + diff --git a/apps/aqhome-storage/u_static_p.h b/apps/aqhome-storage/u_static_p.h new file mode 100644 index 0000000..1439dd1 --- /dev/null +++ b/apps/aqhome-storage/u_static_p.h @@ -0,0 +1,27 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2023 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifndef AQHOME_STORAGE_U_STATIC_P_H +#define AQHOME_STORAGE_U_STATIC_P_H + + +#include "./u_static.h" + +#include + + +typedef struct AQH_URLHANDLER_STATIC AQH_URLHANDLER_STATIC; +struct AQH_URLHANDLER_STATIC { + GWEN_STRINGLIST *fileList; +}; + + + +#endif + + diff --git a/aqhome/http/httpservice_conf.c b/aqhome/http/httpservice_conf.c index 94b0fb9..15da098 100644 --- a/aqhome/http/httpservice_conf.c +++ b/aqhome/http/httpservice_conf.c @@ -63,7 +63,6 @@ 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); -static GWEN_STRINGLIST *_getConfFileList(const char *folder, const char *mask); static AQH_SESSION_LIST *_readAllSessionsIntoList(const AQH_SERVICE *sv); static AQH_SESSION *_readSessionFromFile(const char *filename); @@ -761,6 +760,31 @@ int AQH_HttpService_DelSession(AQH_SERVICE *sv, AQH_SESSION *session) +GWEN_STRINGLIST *AQH_HttpService_GetFolderFileList(const char *folder, const char *mask, int senseCase) +{ + GWEN_STRINGLIST *sl; + int rv; + + sl=GWEN_StringList_new(); + GWEN_StringList_SetSenseCase(sl, senseCase); + + rv=GWEN_Directory_GetFileEntries(folder, sl, mask); + if (rv<0) { + DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv); + GWEN_StringList_free(sl); + return NULL; + } + if (GWEN_StringList_Count(sl)<1) { + DBG_INFO(AQH_LOGDOMAIN, "Empty string list"); + GWEN_StringList_free(sl); + return NULL; + } + + return sl; +} + + + AQH_MODULE *_ensureModule(AQH_SERVICE *sv, const char *modName) { AQH_MODULE *module; @@ -1159,29 +1183,6 @@ GWEN_BUFFER *_getSessionFolder(const AQH_SERVICE *sv) -GWEN_STRINGLIST *_getConfFileList(const char *folder, const char *mask) -{ - GWEN_STRINGLIST *sl; - int rv; - - sl=GWEN_StringList_new(); - rv=GWEN_Directory_GetFileEntries(folder, sl, mask); - if (rv<0) { - DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv); - GWEN_StringList_free(sl); - return NULL; - } - if (GWEN_StringList_Count(sl)<1) { - DBG_INFO(AQH_LOGDOMAIN, "Empty string list"); - GWEN_StringList_free(sl); - return NULL; - } - - return sl; -} - - - AQH_SESSION_LIST *_readAllSessionsIntoList(const AQH_SERVICE *sv) { GWEN_BUFFER *folderBuf; @@ -1190,7 +1191,7 @@ AQH_SESSION_LIST *_readAllSessionsIntoList(const AQH_SERVICE *sv) if (folderBuf) { GWEN_STRINGLIST *fileList; - fileList=_getConfFileList(GWEN_Buffer_GetStart(folderBuf), "*.conf"); + fileList=AQH_HttpService_GetFolderFileList(GWEN_Buffer_GetStart(folderBuf), "*.conf", 1); if (fileList) { AQH_SESSION_LIST *sessionList; uint32_t pos; diff --git a/aqhome/http/httpservice_conf.h b/aqhome/http/httpservice_conf.h index 3104eb0..5924dbf 100644 --- a/aqhome/http/httpservice_conf.h +++ b/aqhome/http/httpservice_conf.h @@ -52,6 +52,8 @@ AQHOME_API int AQH_HttpService_DelSession(AQH_SERVICE *sv, AQH_SESSION *session) AQHOME_API void AQH_HttpService_LoadAllSessions(AQH_SERVICE *sv); +AQHOME_API GWEN_STRINGLIST *AQH_HttpService_GetFolderFileList(const char *folder, const char *mask, int senseCase); + #endif diff --git a/aqhome/http/urlhandler.c b/aqhome/http/urlhandler.c index 3484eaa..4e131e8 100644 --- a/aqhome/http/urlhandler.c +++ b/aqhome/http/urlhandler.c @@ -53,6 +53,8 @@ void AQH_HttpUrlHandler_free(AQH_HTTP_URLHANDLER *uh) if (uh) { GWEN_LIST_FINI(AQH_HTTP_URLHANDLER, uh); GWEN_INHERIT_FINI(AQH_HTTP_URLHANDLER, uh); + + free(uh->folder); GWEN_StringList_free(uh->urlPatternList); GWEN_FREE_OBJECT(uh); } @@ -90,6 +92,23 @@ void AQH_HttpUrlHandler_AddUrlPattern(AQH_HTTP_URLHANDLER *uh, const char *s) +const char *AQH_HttpUrlHandler_GetFolder(const AQH_HTTP_URLHANDLER *uh) +{ + return uh?uh->folder:NULL; +} + + + +void AQH_HttpUrlHandler_SetFolder(AQH_HTTP_URLHANDLER *uh, const char *s) +{ + if (uh) { + free(uh->folder); + uh->folder=s?strdup(s):NULL; + } +} + + + int AQH_HttpUrlHandler_UrlMatches(const AQH_HTTP_URLHANDLER *uh, const char *s) { if (uh && s && *s) { diff --git a/aqhome/http/urlhandler.h b/aqhome/http/urlhandler.h index 1946555..80ededc 100644 --- a/aqhome/http/urlhandler.h +++ b/aqhome/http/urlhandler.h @@ -39,6 +39,9 @@ AQHOME_API int AQH_HttpUrlHandler_UrlMatches(const AQH_HTTP_URLHANDLER *uh, cons AQHOME_API AQH_HTTP_CONTENT *AQH_HttpUrlHandler_GetContentProvider(const AQH_HTTP_URLHANDLER *uh); AQHOME_API void AQH_HttpUrlHandler_SetContentProvider(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_CONTENT *cp); +AQHOME_API const char *AQH_HttpUrlHandler_GetFolder(const AQH_HTTP_URLHANDLER *uh); +AQHOME_API void AQH_HttpUrlHandler_SetFolder(AQH_HTTP_URLHANDLER *uh, const char *s); + AQHOME_API void AQH_HttpUrlHandler_SetHandleFn(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_URLHANDLER_HANDLE_FN fn); AQHOME_API int AQH_HttpUrlHandler_AddContentHeaders(AQH_HTTP_URLHANDLER *uh, int m, GWEN_BUFFER *dbuf); diff --git a/aqhome/http/urlhandler_p.h b/aqhome/http/urlhandler_p.h index c2c0f07..edc3390 100644 --- a/aqhome/http/urlhandler_p.h +++ b/aqhome/http/urlhandler_p.h @@ -21,6 +21,8 @@ struct AQH_HTTP_URLHANDLER { AQH_SERVICE *httpService; GWEN_STRINGLIST *urlPatternList; AQH_HTTP_CONTENT *httpContentProvider; + char *folder; + AQH_HTTP_URLHANDLER_HANDLE_FN handleFn; };