addd urlhandler for static content, more reusing of code.
This commit is contained in:
291
apps/aqhome-storage/u_static.c
Normal file
291
apps/aqhome-storage/u_static.c
Normal file
@@ -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 <config.h>
|
||||
#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 <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/i18n.h>
|
||||
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user