aqhome: added service definitions, started implementing HTTP service.
This commit is contained in:
@@ -47,12 +47,18 @@
|
||||
<headers dist="true" install="$(pkgincludedir)/http" >
|
||||
endpoint_http.h
|
||||
urlhandler.h
|
||||
content.h
|
||||
content_files.h
|
||||
httpservice.h
|
||||
</headers>
|
||||
|
||||
|
||||
<headers dist="true" >
|
||||
endpoint_http_p.h
|
||||
urlhandler_p.h
|
||||
content_p.h
|
||||
content_files_p.h
|
||||
httpservice_p.h
|
||||
</headers>
|
||||
|
||||
|
||||
@@ -61,6 +67,9 @@
|
||||
|
||||
endpoint_http.c
|
||||
urlhandler.c
|
||||
content.c
|
||||
content_files.c
|
||||
httpservice.c
|
||||
</sources>
|
||||
|
||||
|
||||
|
||||
84
aqhome/http/content.c
Normal file
84
aqhome/http/content.c
Normal file
@@ -0,0 +1,84 @@
|
||||
/****************************************************************************
|
||||
* 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/content_p.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
|
||||
GWEN_INHERIT_FUNCTIONS(AQH_HTTP_CONTENT)
|
||||
GWEN_TREE2_FUNCTIONS(AQH_HTTP_CONTENT, AQH_HttpContent)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
AQH_HTTP_CONTENT *AQH_HttpContent_new(void)
|
||||
{
|
||||
AQH_HTTP_CONTENT *cp;
|
||||
|
||||
GWEN_NEW_OBJECT(AQH_HTTP_CONTENT, cp);
|
||||
GWEN_INHERIT_INIT(AQH_HTTP_CONTENT, cp);
|
||||
GWEN_TREE2_INIT(AQH_HTTP_CONTENT, cp, AQH_HttpContent);
|
||||
|
||||
return cp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_HttpContent_free(AQH_HTTP_CONTENT *cp)
|
||||
{
|
||||
if (cp) {
|
||||
GWEN_TREE2_FINI(AQH_HTTP_CONTENT, cp, AQH_HttpContent);
|
||||
GWEN_INHERIT_FINI(AQH_HTTP_CONTENT, cp);
|
||||
GWEN_FREE_OBJECT(cp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AQH_HttpContent_AddOpeningContent(AQH_HTTP_CONTENT *cp, int mode, GWEN_BUFFER *buffer)
|
||||
{
|
||||
return (cp && cp->addOpeningContentFn)?(cp->addOpeningContentFn(cp, mode, buffer)):0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AQH_HttpContent_AddClosingContent(AQH_HTTP_CONTENT *cp, int mode, GWEN_BUFFER *buffer)
|
||||
{
|
||||
return (cp && cp->addClosingContentFn)?(cp->addClosingContentFn(cp, mode, buffer)):0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_HttpContent_SetAddOpeningContentFn(AQH_HTTP_CONTENT *cp, AQH_HTTP_CONTENT_ADD_OPENING_CONTENT_FN f)
|
||||
{
|
||||
if (cp)
|
||||
cp->addOpeningContentFn=f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_HttpContent_SetAddClosingContentFn(AQH_HTTP_CONTENT *cp, AQH_HTTP_CONTENT_ADD_CLOSING_CONTENT_FN f)
|
||||
{
|
||||
if (cp)
|
||||
cp->addClosingContentFn=f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
58
aqhome/http/content.h
Normal file
58
aqhome/http/content.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/****************************************************************************
|
||||
* 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_CONTENT_H
|
||||
#define AQHOME_CONTENT_H
|
||||
|
||||
|
||||
#include <aqhome/api.h>
|
||||
|
||||
#include <gwenhywfar/buffer.h>
|
||||
#include <gwenhywfar/inherit.h>
|
||||
#include <gwenhywfar/tree2.h>
|
||||
|
||||
|
||||
#define AQH_HTTP_CONTENT_MODE_DESKTOP 0
|
||||
#define AQH_HTTP_CONTENT_MODE_MOBILE 1
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
typedef struct AQH_HTTP_CONTENT AQH_HTTP_CONTENT;
|
||||
GWEN_INHERIT_FUNCTION_LIB_DEFS(AQH_HTTP_CONTENT, AQHOME_API)
|
||||
GWEN_TREE2_FUNCTION_LIB_DEFS(AQH_HTTP_CONTENT, AQH_HttpContent, AQHOME_API)
|
||||
|
||||
|
||||
typedef int (*AQH_HTTP_CONTENT_ADD_OPENING_CONTENT_FN)(AQH_HTTP_CONTENT *cp, int mode, GWEN_BUFFER *buffer);
|
||||
typedef int (*AQH_HTTP_CONTENT_ADD_CLOSING_CONTENT_FN)(AQH_HTTP_CONTENT *cp, int mode, GWEN_BUFFER *buffer);
|
||||
|
||||
|
||||
AQHOME_API AQH_HTTP_CONTENT *AQH_HttpContent_new(void);
|
||||
AQHOME_API void AQH_HttpContent_free(AQH_HTTP_CONTENT *cp);
|
||||
|
||||
AQHOME_API int AQH_HttpContent_AddOpeningContent(AQH_HTTP_CONTENT *cp, int mode, GWEN_BUFFER *buffer);
|
||||
AQHOME_API int AQH_HttpContent_AddClosingContent(AQH_HTTP_CONTENT *cp, int mode, GWEN_BUFFER *buffer);
|
||||
|
||||
|
||||
AQHOME_API void AQH_HttpContent_SetAddOpeningContentFn(AQH_HTTP_CONTENT *cp, AQH_HTTP_CONTENT_ADD_OPENING_CONTENT_FN f);
|
||||
AQHOME_API void AQH_HttpContent_SetAddClosingContentFn(AQH_HTTP_CONTENT *cp, AQH_HTTP_CONTENT_ADD_CLOSING_CONTENT_FN f);
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
145
aqhome/http/content_files.c
Normal file
145
aqhome/http/content_files.c
Normal file
@@ -0,0 +1,145 @@
|
||||
/****************************************************************************
|
||||
* 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/content_files_p.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/syncio.h>
|
||||
|
||||
|
||||
|
||||
GWEN_INHERIT(AQH_HTTP_CONTENT, AQH_HTTP_CONTENT_FILES)
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _freeData(void *bp, void *p);
|
||||
static int _addOpeningContent(AQH_HTTP_CONTENT *cp, int mode, GWEN_BUFFER *buffer);
|
||||
static int _addClosingContent(AQH_HTTP_CONTENT *cp, int mode, GWEN_BUFFER *buffer);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
AQH_HTTP_CONTENT *AQH_HttpContentFiles_new(const char *headerFilename, const char *footerFilename)
|
||||
{
|
||||
AQH_HTTP_CONTENT *cp;
|
||||
AQH_HTTP_CONTENT_FILES *xcp;
|
||||
|
||||
cp=AQH_HttpContent_new();
|
||||
GWEN_NEW_OBJECT(AQH_HTTP_CONTENT_FILES, xcp);
|
||||
GWEN_INHERIT_SETDATA(AQH_HTTP_CONTENT, AQH_HTTP_CONTENT_FILES, cp, xcp, _freeData);
|
||||
|
||||
xcp->headerFilename=(headerFilename && *headerFilename)?strdup(headerFilename):NULL;
|
||||
xcp->footerFilename=(footerFilename && *footerFilename)?strdup(footerFilename):NULL;
|
||||
|
||||
AQH_HttpContent_SetAddOpeningContentFn(cp, _addOpeningContent);
|
||||
AQH_HttpContent_SetAddClosingContentFn(cp, _addClosingContent);
|
||||
|
||||
return cp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _freeData(void *bp, void *p)
|
||||
{
|
||||
AQH_HTTP_CONTENT_FILES *xcp;
|
||||
|
||||
xcp=(AQH_HTTP_CONTENT_FILES*) p;
|
||||
|
||||
free(xcp->footerData);
|
||||
free(xcp->headerData);
|
||||
|
||||
free(xcp->footerFilename);
|
||||
free(xcp->headerFilename);
|
||||
GWEN_FREE_OBJECT(xcp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _addOpeningContent(AQH_HTTP_CONTENT *cp, int mode, GWEN_BUFFER *buffer)
|
||||
{
|
||||
if (cp) {
|
||||
AQH_HTTP_CONTENT_FILES *xcp;
|
||||
|
||||
xcp=GWEN_INHERIT_GETDATA(AQH_HTTP_CONTENT, AQH_HTTP_CONTENT_FILES, cp);
|
||||
if (xcp) {
|
||||
if (xcp->headerData==NULL) {
|
||||
if (xcp->headerFilename) {
|
||||
int rv;
|
||||
GWEN_BUFFER *fileBuffer;
|
||||
|
||||
fileBuffer=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
rv=GWEN_SyncIo_Helper_ReadFile(xcp->headerFilename, fileBuffer);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error reading header file \"%s\": %d", xcp->headerFilename, rv);
|
||||
GWEN_Buffer_free(fileBuffer);
|
||||
return rv;
|
||||
}
|
||||
xcp->headerData=strdup(GWEN_Buffer_GetStart(fileBuffer));
|
||||
GWEN_Buffer_free(fileBuffer);
|
||||
}
|
||||
}
|
||||
if (xcp->headerData)
|
||||
GWEN_Buffer_AppendString(buffer, xcp->headerData);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _addClosingContent(AQH_HTTP_CONTENT *cp, int mode, GWEN_BUFFER *buffer)
|
||||
{
|
||||
if (cp) {
|
||||
AQH_HTTP_CONTENT_FILES *xcp;
|
||||
|
||||
xcp=GWEN_INHERIT_GETDATA(AQH_HTTP_CONTENT, AQH_HTTP_CONTENT_FILES, cp);
|
||||
if (xcp) {
|
||||
if (xcp->footerData==NULL) {
|
||||
if (xcp->footerFilename) {
|
||||
int rv;
|
||||
GWEN_BUFFER *fileBuffer;
|
||||
|
||||
fileBuffer=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
rv=GWEN_SyncIo_Helper_ReadFile(xcp->footerFilename, fileBuffer);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error reading footer file \"%s\": %d", xcp->footerFilename, rv);
|
||||
GWEN_Buffer_free(fileBuffer);
|
||||
return rv;
|
||||
}
|
||||
xcp->footerData=strdup(GWEN_Buffer_GetStart(fileBuffer));
|
||||
GWEN_Buffer_free(fileBuffer);
|
||||
}
|
||||
if (xcp->footerData)
|
||||
GWEN_Buffer_AppendString(buffer, xcp->footerData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
34
aqhome/http/content_files.h
Normal file
34
aqhome/http/content_files.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/****************************************************************************
|
||||
* 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_CONTENT_FILES_H
|
||||
#define AQHOME_CONTENT_FILES_H
|
||||
|
||||
|
||||
#include <aqhome/api.h>
|
||||
#include <aqhome/http/content.h>
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
AQHOME_API AQH_HTTP_CONTENT *AQH_HttpContentFiles_new(const char *headerFilename, const char *footerFilename);
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
28
aqhome/http/content_files_p.h
Normal file
28
aqhome/http/content_files_p.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/****************************************************************************
|
||||
* 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_CONTENT_FILES_P_H
|
||||
#define AQHOME_CONTENT_FILES_P_H
|
||||
|
||||
|
||||
#include "aqhome/http/content_files.h"
|
||||
|
||||
|
||||
|
||||
typedef struct AQH_HTTP_CONTENT_FILES AQH_HTTP_CONTENT_FILES;
|
||||
struct AQH_HTTP_CONTENT_FILES {
|
||||
char *headerFilename;
|
||||
char *footerFilename;
|
||||
|
||||
char *headerData;
|
||||
char *footerData;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
27
aqhome/http/content_p.h
Normal file
27
aqhome/http/content_p.h
Normal file
@@ -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_CONTENT_P_H
|
||||
#define AQHOME_CONTENT_P_H
|
||||
|
||||
|
||||
#include "aqhome/http/content.h"
|
||||
|
||||
|
||||
struct AQH_HTTP_CONTENT {
|
||||
GWEN_INHERIT_ELEMENT(AQH_HTTP_CONTENT);
|
||||
GWEN_TREE2_ELEMENT(AQH_HTTP_CONTENT);
|
||||
|
||||
AQH_HTTP_CONTENT_ADD_OPENING_CONTENT_FN addOpeningContentFn;
|
||||
AQH_HTTP_CONTENT_ADD_CLOSING_CONTENT_FN addClosingContentFn;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -395,7 +395,8 @@ int _distributeBufferInHeaderMode(GWEN_MSG_ENDPOINT *ep, const uint8_t *bufferPt
|
||||
}
|
||||
else {
|
||||
xep->currentBodyPos=GWEN_Buffer_GetPos(xep->currentReadBuffer);
|
||||
xep->currentBodySize=contentLength;
|
||||
xep->currentBodySize=contentLength;
|
||||
xep->remainingBodySize=contentLength;
|
||||
xep->readMode=AQH_EndpointHttpd_ReadMode_Body;
|
||||
}
|
||||
}
|
||||
@@ -411,16 +412,16 @@ int _distributeBufferInBodyMode(GWEN_MSG_ENDPOINT *ep, const uint8_t *bufferPtr,
|
||||
AQH_ENDPOINT_HTTP *xep;
|
||||
|
||||
xep=GWEN_INHERIT_GETDATA(GWEN_MSG_ENDPOINT, AQH_ENDPOINT_HTTP, ep);
|
||||
if (xep->currentBodySize>0) {
|
||||
if (xep->remainingBodySize>0) {
|
||||
int len;
|
||||
|
||||
len=bufferLen;
|
||||
if (len>xep->currentBodySize)
|
||||
len=xep->currentBodySize;
|
||||
if (len>xep->remainingBodySize)
|
||||
len=xep->remainingBodySize;
|
||||
if (len) {
|
||||
GWEN_Buffer_AppendBytes(xep->currentReadBuffer, (const char*) bufferPtr, len);
|
||||
xep->currentBodySize-=len;
|
||||
if (xep->currentBodySize==0) {
|
||||
xep->remainingBodySize-=len;
|
||||
if (xep->remainingBodySize==0) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Body completely received");
|
||||
_finishMessageAndStartNext(ep);
|
||||
}
|
||||
@@ -475,6 +476,10 @@ void _finishMessageAndStartNext(GWEN_MSG_ENDPOINT *ep)
|
||||
xep=GWEN_INHERIT_GETDATA(GWEN_MSG_ENDPOINT, AQH_ENDPOINT_HTTP, ep);
|
||||
|
||||
msg=GWEN_Msg_fromBytes((const uint8_t*)GWEN_Buffer_GetStart(xep->currentReadBuffer), GWEN_Buffer_GetUsedBytes(xep->currentReadBuffer));
|
||||
if (xep->currentBodySize) {
|
||||
GWEN_Msg_SetParsedPayloadOffset(msg, xep->currentBodyPos);
|
||||
GWEN_Msg_SetParsedPayloadSize(msg, xep->currentBodySize);
|
||||
}
|
||||
dbParsedData=GWEN_DB_Group_new("parsedData");
|
||||
if (xep->dbCurrentReadCommand)
|
||||
GWEN_DB_AddGroup(dbParsedData, xep->dbCurrentReadCommand);
|
||||
@@ -488,6 +493,7 @@ void _finishMessageAndStartNext(GWEN_MSG_ENDPOINT *ep)
|
||||
xep->currentHeaderPos=0;
|
||||
xep->currentBodyPos=0;
|
||||
xep->currentBodySize=0;
|
||||
xep->remainingBodySize=0;
|
||||
xep->lastLineStartPos=0;
|
||||
xep->dbCurrentReadCommand=NULL;
|
||||
xep->dbCurrentReadHeader=NULL;
|
||||
@@ -511,6 +517,7 @@ void _abortMessage(GWEN_MSG_ENDPOINT *ep)
|
||||
xep->currentHeaderPos=0;
|
||||
xep->currentBodyPos=0;
|
||||
xep->currentBodySize=0;
|
||||
xep->remainingBodySize=0;
|
||||
xep->lastLineStartPos=0;
|
||||
if (xep->dbCurrentReadCommand)
|
||||
GWEN_DB_Group_free(xep->dbCurrentReadCommand);
|
||||
|
||||
@@ -43,6 +43,7 @@ struct AQH_ENDPOINT_HTTP {
|
||||
int currentHeaderPos;
|
||||
int currentBodyPos;
|
||||
int currentBodySize;
|
||||
int remainingBodySize;
|
||||
int lastLineStartPos;
|
||||
};
|
||||
|
||||
|
||||
328
aqhome/http/httpservice.c
Normal file
328
aqhome/http/httpservice.c
Normal file
@@ -0,0 +1,328 @@
|
||||
/****************************************************************************
|
||||
* 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_p.h"
|
||||
|
||||
#include <gwenhywfar/db.h>
|
||||
#include <gwenhywfar/buffer.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
GWEN_INHERIT(AQH_SERVICE, AQH_HTTP_SERVICE)
|
||||
|
||||
|
||||
static void GWENHYWFAR_CB _freeData(void *bp, void *p);
|
||||
|
||||
static int _checkHeaderGetBodySize(const GWEN_MSG *msgReceived);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void AQH_HttpService_Extend(AQH_SERVICE *sv)
|
||||
{
|
||||
AQH_HTTP_SERVICE *xsv;
|
||||
|
||||
GWEN_NEW_OBJECT(AQH_HTTP_SERVICE, xsv);
|
||||
GWEN_INHERIT_SETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv, xsv, _freeData);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _freeData(void *bp, void *p)
|
||||
{
|
||||
AQH_HTTP_SERVICE *xsv;
|
||||
|
||||
xsv=(AQH_HTTP_SERVICE*) p;
|
||||
free(xsv->sourceFolder);
|
||||
free(xsv->siteHeader);
|
||||
free(xsv->siteFooter);
|
||||
GWEN_FREE_OBJECT(xsv);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *AQH_HttpService_GetSourceFolder(const AQH_SERVICE *sv)
|
||||
{
|
||||
if (sv) {
|
||||
AQH_HTTP_SERVICE *xsv;
|
||||
|
||||
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv);
|
||||
if (xsv)
|
||||
return xsv->sourceFolder;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_HttpService_SetSourceFolder(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->sourceFolder);
|
||||
xsv->sourceFolder=s?strdup(s):NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *AQH_HttpService_GetSiteHeader(const AQH_SERVICE *sv)
|
||||
{
|
||||
if (sv) {
|
||||
AQH_HTTP_SERVICE *xsv;
|
||||
|
||||
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv);
|
||||
if (xsv)
|
||||
return xsv->siteHeader;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_HttpService_SetSiteHeader(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->siteHeader);
|
||||
xsv->siteHeader=s?strdup(s):NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *AQH_HttpService_GetSiteFooter(const AQH_SERVICE *sv)
|
||||
{
|
||||
if (sv) {
|
||||
AQH_HTTP_SERVICE *xsv;
|
||||
|
||||
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv);
|
||||
if (xsv)
|
||||
return xsv->siteFooter;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_HttpService_SetSiteFooter(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->siteFooter);
|
||||
xsv->siteFooter=s?strdup(s):NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
int contentLength;
|
||||
const char *s;
|
||||
|
||||
contentLength=_checkHeaderGetBodySize(msgReceived);
|
||||
if (contentLength<1) {
|
||||
DBG_ERROR(NULL, "Empty message body");
|
||||
return 0;
|
||||
}
|
||||
s=(const char*)(GWEN_Msg_GetConstBuffer(msgReceived)+GWEN_Msg_GetParsedPayloadOffset(msgReceived));
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _checkHeaderGetBodySize(const GWEN_MSG *msgReceived)
|
||||
{
|
||||
GWEN_DB_NODE *dbParsedInfo;
|
||||
GWEN_DB_NODE *dbHeader;
|
||||
const char *contentType;
|
||||
int contentLength;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return contentLength;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
48
aqhome/http/httpservice.h
Normal file
48
aqhome/http/httpservice.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_H
|
||||
#define AQH_HTTP_SERVICE_H
|
||||
|
||||
|
||||
|
||||
#include "aqhome/service/service.h"
|
||||
|
||||
#include <gwenhywfar/db.h>
|
||||
#include <gwenhywfar/buffer.h>
|
||||
#include <gwenhywfar/msg.h>
|
||||
|
||||
|
||||
|
||||
void AQH_HttpService_Extend(AQH_SERVICE *sv);
|
||||
|
||||
|
||||
const char *AQH_HttpService_GetSourceFolder(const 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);
|
||||
void AQH_HttpService_SetSiteFooter(AQH_SERVICE *sv, const char *s);
|
||||
|
||||
|
||||
int AQH_HttpService_AddFile(AQH_SERVICE *sv, const char *fname, GWEN_BUFFER *buf);
|
||||
void AQH_HttpService_AddStatusLine(AQH_SERVICE *sv, int code, const char *msg, const char *proto, GWEN_BUFFER *buf);
|
||||
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);
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
31
aqhome/http/httpservice_p.h
Normal file
31
aqhome/http/httpservice_p.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/****************************************************************************
|
||||
* 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_P_H
|
||||
#define AQH_HTTP_SERVICE_P_H
|
||||
|
||||
|
||||
#include "aqhome/http/httpservice.h"
|
||||
|
||||
|
||||
|
||||
typedef struct AQH_HTTP_SERVICE AQH_HTTP_SERVICE;
|
||||
struct AQH_HTTP_SERVICE {
|
||||
char *sourceFolder;
|
||||
|
||||
char *siteHeader;
|
||||
char *siteFooter;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -51,6 +51,21 @@ void AQH_UrlHandler_free(AQH_URLHANDLER *uh)
|
||||
|
||||
|
||||
|
||||
AQH_HTTP_CONTENT *AQH_UrlHandler_GetContentProvider(const AQH_URLHANDLER *uh)
|
||||
{
|
||||
return uh?uh->httpContentProvider:NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_UrlHandler_SetContentProvider(AQH_URLHANDLER *uh, AQH_HTTP_CONTENT *cp)
|
||||
{
|
||||
if (uh)
|
||||
uh->httpContentProvider=cp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_UrlHandler_AddUrlPattern(AQH_URLHANDLER *uh, const char *s)
|
||||
{
|
||||
if (uh && s && *s)
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
#include <aqhome/api.h>
|
||||
|
||||
#include "aqhome/http/content.h"
|
||||
|
||||
#include <gwenhywfar/inherit.h>
|
||||
#include <gwenhywfar/stringlist.h>
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
@@ -30,6 +32,9 @@ typedef GWEN_MSG*(*AQH_URLHANDLER_HANDLE_FN)(AQH_URLHANDLER *uh, GWEN_MSG_ENDPOI
|
||||
AQHOME_API AQH_URLHANDLER *AQH_UrlHandler_new(void);
|
||||
AQHOME_API void AQH_UrlHandler_free(AQH_URLHANDLER *uh);
|
||||
|
||||
AQHOME_API AQH_HTTP_CONTENT *AQH_UrlHandler_GetContentProvider(const AQH_URLHANDLER *uh);
|
||||
AQHOME_API void AQH_UrlHandler_SetContentProvider(AQH_URLHANDLER *uh, AQH_HTTP_CONTENT *cp);
|
||||
|
||||
AQHOME_API void AQH_UrlHandler_AddUrlPattern(AQH_URLHANDLER *uh, const char *s);
|
||||
AQHOME_API int AQH_UrlHandler_UrlMatches(const AQH_URLHANDLER *uh, const char *s);
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ struct AQH_URLHANDLER {
|
||||
|
||||
GWEN_STRINGLIST *urlPatternList;
|
||||
AQH_URLHANDLER_HANDLE_FN handleFn;
|
||||
|
||||
AQH_HTTP_CONTENT *httpContentProvider;
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user