aqhome: more work on http server.

This commit is contained in:
Martin Preuss
2023-08-08 23:49:28 +02:00
parent 3378908c93
commit aafecfa704
50 changed files with 2988 additions and 497 deletions

View File

@@ -14,6 +14,7 @@
#include "aqhome/http/httpservice_http.h"
#include "aqhome/http/httpservice_conf.h"
#include "aqhome/http/httpservice_p.h"
#include "aqhome/http/urlhandler.h"
#include <gwenhywfar/db.h>
#include <gwenhywfar/buffer.h>
@@ -37,7 +38,7 @@
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);
static AQH_HTTP_URLHANDLER *_findMatchingUrlHandler(AQH_SERVICE *sv, const char *path);
@@ -52,10 +53,12 @@ GWEN_MSG *AQH_HttpService_HandleHttpRequest(AQH_SERVICE *sv, GWEN_MSG_ENDPOINT *
AQH_HTTP_SERVICE *xsv;
AQH_HTTP_REQUEST *rq;
const char *s;
AQH_MODULE *m=NULL;
const char *cmd;
const char *protocol;
AQH_SESSION *session=NULL;
GWEN_MSG *msgResponse;
int rv;
AQH_HTTP_URLHANDLER *uh;
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv);
if (xsv==NULL) {
@@ -63,17 +66,16 @@ GWEN_MSG *AQH_HttpService_HandleHttpRequest(AQH_SERVICE *sv, GWEN_MSG_ENDPOINT *
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");
return AQH_HttpService_CreateResponseMsg(sv, 500, "Internal server error", "HTTP/1.1", NULL);
}
cmd=AQH_HttpRequest_GetCommand(rq);
protocol=AQH_HttpRequest_GetProtocol(rq);
#if 0
s=AQH_HttpRequest_GetModuleName(rq);
if (s && *s) {
m=AQH_HttpService_GetModule(sv, s);
@@ -83,6 +85,7 @@ GWEN_MSG *AQH_HttpService_HandleHttpRequest(AQH_SERVICE *sv, GWEN_MSG_ENDPOINT *
else
AQH_HttpRequest_SetModule(rq, m);
}
#endif
s=AQH_HttpRequest_GetSessionId(rq);
if (s && *s) {
@@ -91,17 +94,25 @@ GWEN_MSG *AQH_HttpService_HandleHttpRequest(AQH_SERVICE *sv, GWEN_MSG_ENDPOINT *
DBG_INFO(AQH_LOGDOMAIN, "Session \"%s\" not found", s);
}
else {
DBG_INFO(AQH_LOGDOMAIN, "Found session \"%s\"", s);
AQH_HttpRequest_SetSession(rq, session);
}
}
_setRequestPerms(sv, rq);
s=AQH_HttpRequest_GetUrlPath(rq);
DBG_INFO(AQH_LOGDOMAIN, "Received \"%s\" request for url \"%s\"", cmd?cmd:"<no cmd>", s);
uh=_findMatchingUrlHandler(sv, s);
if (uh==NULL) {
DBG_INFO(AQH_LOGDOMAIN, "No matching handler found for url \"%s\"", s);
AQH_HttpRequest_free(rq);
return AQH_HttpService_CreateResponseMsg(sv, 404, "Not found", protocol?protocol:"http/1.1", NULL);
}
rv=xsv->handleRequestFn(sv, rq);
rv=AQH_HttpUrlHandler_HandleMessage(uh, 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");
return AQH_HttpService_CreateResponseMsg(sv, 500, "Internal server error", protocol?protocol:"http/1.1", NULL);
}
msgResponse=AQH_HttpRequest_TakeResponseMsg(rq);
AQH_HttpRequest_free(rq);
@@ -110,6 +121,68 @@ GWEN_MSG *AQH_HttpService_HandleHttpRequest(AQH_SERVICE *sv, GWEN_MSG_ENDPOINT *
void AQH_HttpService_AddUrlHandler(AQH_SERVICE *sv, AQH_HTTP_URLHANDLER *urlHandler)
{
AQH_HTTP_SERVICE *xsv;
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv);
if (xsv==NULL) {
DBG_ERROR(AQH_LOGDOMAIN, "Not a AQH_HttpService object");
}
else {
AQH_HttpUrlHandler_List_Add(urlHandler, xsv->urlHandlerList);
}
}
void AQH_HttpService_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) {
DBG_INFO(AQH_LOGDOMAIN, "Presetting module's guest perms");
AQH_HttpRequest_SetModulePerms(rq, AQH_Module_GetGuestPerms(m));
if (session) {
AQH_USER * user;
user=AQH_Session_GetUser(session);
if (user) {
AQH_MODULE_PERMS_LIST *permsList;
permsList=AQH_User_GetModulePermList(user);
if (permsList) {
AQH_MODULE_PERMS *userPerms;
userPerms=AQH_ModulePerms_List_GetByModuleId(AQH_User_GetModulePermList(user), AQH_Module_GetId(m));
if (userPerms) {
DBG_INFO(AQH_LOGDOMAIN, "Using user perms for module");
AQH_HttpRequest_SetModulePerms(rq, AQH_ModulePerms_GetPerms(userPerms));
}
}
else {
DBG_INFO(AQH_LOGDOMAIN, "No module perms list in user, using module's guest perms");
}
}
else {
DBG_INFO(AQH_LOGDOMAIN, "Session but no user, SNH!");
}
}
else {
DBG_INFO(AQH_LOGDOMAIN, "No session, using module's guest perms");
}
}
else {
DBG_INFO(AQH_LOGDOMAIN, "No module, no perms");
}
}
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:"");
@@ -163,14 +236,40 @@ void AQH_HttpService_AddHeader(AQH_SERVICE *sv, GWEN_DB_NODE *dbHeader, GWEN_BUF
GWEN_MSG *AQH_HttpService_CreateResponseMsg(AQH_SERVICE *sv, int code, const char *text, const char *protocol)
GWEN_MSG *AQH_HttpService_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, 0, 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;
}
GWEN_MSG *AQH_HttpService_CreateRedirectingResponseMsg(AQH_SERVICE *sv, const char *protocol, const char *newPage)
{
GWEN_BUFFER *buf;
GWEN_MSG *msg;
GWEN_DB_NODE *db;
buf=GWEN_Buffer_new(0, 256, 0, 1);
AQH_HttpService_AddStatusLine(sv, 303, "OK, redirecting to content", 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", "text/html; charset=utf-8");
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Location", newPage);
GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Content-Length", 0);
AQH_HttpService_AddHeader(sv, db, buf);
GWEN_DB_Group_free(db);
msg=GWEN_Msg_fromBytes((const uint8_t*)GWEN_Buffer_GetStart(buf), GWEN_Buffer_GetUsedBytes(buf));
GWEN_Buffer_free(buf);
@@ -201,6 +300,39 @@ int AQH_HttpService_AddFile(AQH_SERVICE *sv, GWEN_UNUSED AQH_SESSION *session, c
void AQH_HttpService_SetupModuleAndPerms(AQH_SERVICE *sv, AQH_HTTP_REQUEST *rq, const char *modulName)
{
AQH_SESSION *session;
AQH_MODULE *m;
AQH_HttpRequest_SetModuleName(rq, modulName);
m=AQH_HttpService_GetModule(sv, modulName);
if (m==NULL) {
DBG_ERROR(NULL, "Module \"%s\" not found", modulName);
AQH_HttpRequest_SetModulePerms(rq, 0);
}
else {
AQH_HttpRequest_SetModule(rq, m);
}
session=AQH_HttpRequest_GetSession(rq);
if (session) {
AQH_USER *u;
u=AQH_Session_GetUser(session);
if (u) {
if (strcasecmp(AQH_User_GetAlias(u), AQH_HTTP_SERVICE_ADMINUSER)==0) {
DBG_ERROR(NULL, "special admin user, full access granted");
AQH_HttpRequest_SetModulePerms(rq, 0xffffffff);
return;
}
}
}
AQH_HttpService_SetRequestPerms(sv, rq);
}
GWEN_BUFFER *_getPageFilePath(const AQH_SERVICE *sv, const char *langFolder, const char *fileName)
{
const char *sourceFolder;
@@ -220,7 +352,7 @@ GWEN_BUFFER *_getPageFilePath(const AQH_SERVICE *sv, const char *langFolder, con
GWEN_Buffer_AppendString(nameBuf, langFolder);
GWEN_Buffer_AppendString(nameBuf, GWEN_DIR_SEPARATOR_S);
}
GWEN_Text_EscapeToBuffer(fileName, nameBuf);
GWEN_Text_EscapeToBufferTolerant(fileName, nameBuf);
return nameBuf;
}
}
@@ -245,37 +377,28 @@ void _writeDefaultResponseHeaderToBuffer(AQH_SERVICE *sv, int contentLength, GWE
void _setRequestPerms(AQH_SERVICE *sv, AQH_HTTP_REQUEST *rq)
AQH_HTTP_URLHANDLER *_findMatchingUrlHandler(AQH_SERVICE *sv, const char *path)
{
AQH_MODULE *m;
AQH_SESSION *session;
AQH_HTTP_SERVICE *xsv;
AQH_HTTP_URLHANDLER *uh;
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");
}
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv);
if (xsv==NULL) {
DBG_ERROR(AQH_LOGDOMAIN, "Not a AQH_HttpService object");
return NULL;
}
else {
DBG_INFO(AQH_LOGDOMAIN, "No module");
uh=AQH_HttpUrlHandler_List_First(xsv->urlHandlerList);
while(uh) {
if (AQH_HttpUrlHandler_UrlMatches(uh, path)) {
DBG_INFO(AQH_LOGDOMAIN, "Found matching url handler for \"%s\"", path);
return uh;
}
uh=AQH_HttpUrlHandler_List_Next(uh);
}
DBG_INFO(AQH_LOGDOMAIN, "No matching url handler for \"%s\"", path);
return NULL;
}