/**************************************************************************** * 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 "./aqhomehttp_p.h" #include "aqhome/http/httpservice.h" #include "aqhome/http/httpservice_http.h" #include #include #include #include GWEN_INHERIT(AQH_SERVICE, AQHOME_HTTP) /* ------------------------------------------------------------------------------------------------ * forward declarations * ------------------------------------------------------------------------------------------------ */ static void GWENHYWFAR_CB _freeData(void *bp, void *p); static int _handleUrl(AQH_SERVICE *sv, AQH_HTTP_REQUEST *rq); static int _handleUrl_login(AQH_SERVICE *sv, AQH_HTTP_REQUEST *rq); static GWEN_MSG *_createResponseMsg(AQH_SERVICE *sv, int code, const char *text, const char *protocol, const char *page); static void _writeDefaultResponseHeaderToBuffer(AQH_SERVICE *sv, int contentLength, GWEN_BUFFER *buf); /* ------------------------------------------------------------------------------------------------ * implementations * ------------------------------------------------------------------------------------------------ */ void AqHomeHttpService_Extend(AQH_SERVICE *sv) { AQHOME_HTTP *xsv; GWEN_NEW_OBJECT(AQHOME_HTTP, xsv); GWEN_INHERIT_SETDATA(AQH_SERVICE, AQHOME_HTTP, sv, xsv, _freeData); AQH_HttpService_SetHandleRequestFn(sv, _handleUrl); } void _freeData(void *bp, void *p) { AQHOME_HTTP *xsv; xsv=(AQHOME_HTTP*) p; AQH_Storage_free(xsv->storage); xsv->storage=NULL; GWEN_MsgEndpoint_free(xsv->rootEndpoint); xsv->rootEndpoint=NULL; xsv->ipcdEndpoint=NULL; xsv->mqttEndpoint=NULL; xsv->httpdEndpoint=NULL; GWEN_DB_Group_free(xsv->dbArgs); xsv->dbArgs=NULL; free(xsv->pidFile); GWEN_FREE_OBJECT(xsv); } GWEN_DB_NODE *AqHomeHttpService_GetDbArgs(const AQH_SERVICE *sv) { if (sv) { AQHOME_HTTP *xsv; xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv); if (xsv) return xsv->dbArgs; } return NULL; } const char *AqHomeHttpService_GetPidFile(const AQH_SERVICE *sv) { if (sv) { AQHOME_HTTP *xsv; xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv); if (xsv) return xsv->pidFile; } return NULL; } void AqHomeHttpService_SetPidFile(AQH_SERVICE *sv, const char *s) { if (sv) { AQHOME_HTTP *xsv; xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv); if (xsv) { free(xsv->pidFile); xsv->pidFile=s?strdup(s):NULL; } } } GWEN_MSG_ENDPOINT *AqHomeHttpService_GetRootEndpoint(const AQH_SERVICE *sv) { if (sv) { AQHOME_HTTP *xsv; xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv); if (xsv) return xsv->rootEndpoint; } return NULL; } GWEN_MSG_ENDPOINT *AqHomeHttpService_GetIpcdEndpoint(const AQH_SERVICE *sv) { if (sv) { AQHOME_HTTP *xsv; xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv); if (xsv) return xsv->ipcdEndpoint; } return NULL; } GWEN_MSG_ENDPOINT *AqHomeHttpService_GetMqttEndpoint(const AQH_SERVICE *sv) { if (sv) { AQHOME_HTTP *xsv; xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv); if (xsv) return xsv->mqttEndpoint; } return NULL; } GWEN_MSG_ENDPOINT *AqHomeHttpService_GetHttpdEndpoint(const AQH_SERVICE *sv) { if (sv) { AQHOME_HTTP *xsv; xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv); if (xsv) return xsv->httpdEndpoint; } return NULL; } AQH_STORAGE *AqHomeHttpService_GetStorage(const AQH_SERVICE *sv) { if (sv) { AQHOME_HTTP *xsv; xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv); if (xsv) return xsv->storage; } return NULL; } int _handleUrl(AQH_SERVICE *sv, AQH_HTTP_REQUEST *rq) { const GWEN_URL *url; const char *sPath; url=AQH_HttpRequest_GetUrl(rq); sPath=GWEN_Url_GetPath(url); if (strcasecmp(sPath, "/login")==0) return _handleUrl_login(sv, rq); else { DBG_ERROR(NULL, "Invalid URL [%s]", sPath); return GWEN_ERROR_INVALID; } } int _handleUrl_login(AQH_SERVICE *sv, AQH_HTTP_REQUEST *rq) { const char *protocol; const char *cmd; AQH_SESSION *session; GWEN_MSG *msgOut=NULL; protocol=AQH_HttpRequest_GetProtocol(rq); session=AQH_HttpRequest_GetSession(rq); cmd=AQH_HttpRequest_GetCommand(rq); if (cmd && strcasecmp(cmd, "GET")==0) { GWEN_BUFFER *pageBuf; const char *s; int rv; pageBuf=GWEN_Buffer_new(0, 256, 0, 1); s=AQH_HttpService_GetSiteHeader(sv); if (s) GWEN_Buffer_AppendString(pageBuf, s); rv=AQH_HttpService_AddFile(sv, session, "login.html", pageBuf); if (rv<0) { DBG_ERROR(AQH_LOGDOMAIN, "Error reading file \"login.html\""); GWEN_Buffer_free(pageBuf); msgOut=_createResponseMsg(sv, 500, "Internal Error", protocol, NULL); AQH_HttpRequest_SetResponseMsg(rq, msgOut); return 0; } s=AQH_HttpService_GetSiteFooter(sv); if (s) GWEN_Buffer_AppendString(pageBuf, s); msgOut=_createResponseMsg(sv, 200, "OK", protocol, GWEN_Buffer_GetStart(pageBuf)); GWEN_Buffer_free(pageBuf); AQH_HttpRequest_SetResponseMsg(rq, msgOut); return 0; } else { msgOut=_createResponseMsg(sv, 501, "Not (yet) implemented", protocol, NULL); AQH_HttpRequest_SetResponseMsg(rq, msgOut); return 0; } } GWEN_MSG *_createResponseMsg(AQH_SERVICE *sv, int code, const char *text, const char *protocol, const char *page) { GWEN_BUFFER *buf; GWEN_MSG *msg; buf=GWEN_Buffer_new(0, 256, 0, 1); AQH_HttpService_AddStatusLine(sv, code, text, protocol, buf); _writeDefaultResponseHeaderToBuffer(sv, (page && *page)?strlen(page):0, buf); if (page && *page) GWEN_Buffer_AppendString(buf, page); msg=GWEN_Msg_fromBytes((const uint8_t*)GWEN_Buffer_GetStart(buf), GWEN_Buffer_GetUsedBytes(buf)); GWEN_Buffer_free(buf); return msg; } 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); }