aqhome: more work on http server.
This commit is contained in:
@@ -16,8 +16,7 @@
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
|
||||
|
||||
#define AQH_HTTP_REQUEST_SESSIONCOOKIE "sessionid"
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
GWEN_TREE2_FUNCTIONS(AQH_HTTP_REQUEST, AQH_HttpRequest);
|
||||
@@ -34,13 +33,13 @@ static int _inspectReceivedMessage(AQH_HTTP_REQUEST *rq, const GWEN_MSG *msg);
|
||||
static int _inspectMsgCommand(AQH_HTTP_REQUEST *rq, const GWEN_MSG *msg);
|
||||
static void _inspectMsgHeader(AQH_HTTP_REQUEST *rq, const GWEN_MSG *msg);
|
||||
static int _inspectMsgBody(AQH_HTTP_REQUEST *rq, const GWEN_MSG *msg);
|
||||
static void _setModuleNameFromUrl(AQH_HTTP_REQUEST *rq);
|
||||
static GWEN_DB_NODE *_extractCookies(GWEN_DB_NODE *dbHeader);
|
||||
static void _setCookieValue(GWEN_DB_NODE *dbCookies,
|
||||
const char *nameStart, int nameLen,
|
||||
const char *valueStart, int valueLen,
|
||||
uint32_t dbFlags);
|
||||
static int _parsePostBody(const char *s, int contentLength, GWEN_DB_NODE *dbBody);
|
||||
static int _unescapeUrlEncoded(const char *src, unsigned int srclen, char *buffer, unsigned int maxsize);
|
||||
|
||||
|
||||
|
||||
@@ -79,6 +78,7 @@ void AQH_HttpRequest_free(AQH_HTTP_REQUEST *rq)
|
||||
free(rq->moduleName);
|
||||
free(rq->responseText);
|
||||
GWEN_Msg_free(rq->responseMsg);
|
||||
GWEN_StringList_free(rq->urlPathMembers);
|
||||
GWEN_Url_free(rq->url);
|
||||
GWEN_DB_Group_free(rq->dbPostBody);
|
||||
|
||||
@@ -133,6 +133,30 @@ void AQH_HttpRequest_SetUrl(AQH_HTTP_REQUEST *rq, GWEN_URL *url)
|
||||
|
||||
|
||||
|
||||
const char *AQH_HttpRequest_GetUrlPath(const AQH_HTTP_REQUEST *rq)
|
||||
{
|
||||
return rq?(rq->urlPath):NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_STRINGLIST *AQH_HttpRequest_GetUrlPathMembers(const AQH_HTTP_REQUEST *rq)
|
||||
{
|
||||
return rq?(rq->urlPathMembers):NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_HttpRequest_SetUrlPathMembers(AQH_HTTP_REQUEST *rq, GWEN_STRINGLIST *sl)
|
||||
{
|
||||
if (rq) {
|
||||
GWEN_StringList_free(rq->urlPathMembers);
|
||||
rq->urlPathMembers=sl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_DB_NODE *AQH_HttpRequest_GetDbCommand(const AQH_HTTP_REQUEST *rq)
|
||||
{
|
||||
return rq?(rq->dbCommand):NULL;
|
||||
@@ -154,6 +178,13 @@ GWEN_DB_NODE *AQH_HttpRequest_GetDbCookies(const AQH_HTTP_REQUEST *rq)
|
||||
|
||||
|
||||
|
||||
GWEN_DB_NODE *AQH_HttpRequest_GetDbPostBody(const AQH_HTTP_REQUEST *rq)
|
||||
{
|
||||
return rq?(rq->dbPostBody):NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *AQH_HttpRequest_GetSessionId(const AQH_HTTP_REQUEST *rq)
|
||||
{
|
||||
return rq?(rq->sessionId):NULL;
|
||||
@@ -296,6 +327,27 @@ void AQH_HttpRequest_SetResponseMsg(AQH_HTTP_REQUEST *rq, GWEN_MSG *msg)
|
||||
|
||||
|
||||
|
||||
void AQH_HttpRequest_SetupUrlPathMembers(AQH_HTTP_REQUEST *rq)
|
||||
{
|
||||
const char *path;
|
||||
|
||||
path=AQH_HttpRequest_GetUrlPath(rq);
|
||||
if (path && *path) {
|
||||
GWEN_STRINGLIST *sl;
|
||||
|
||||
if (*path=='/') /* skip leading slash */
|
||||
path++;
|
||||
sl=GWEN_StringList_fromString(path, "/", 0);
|
||||
if (sl==NULL) {
|
||||
DBG_ERROR(NULL, "Empty url path member list");
|
||||
}
|
||||
else
|
||||
AQH_HttpRequest_SetUrlPathMembers(rq, sl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _inspectReceivedMessage(AQH_HTTP_REQUEST *rq, const GWEN_MSG *msg)
|
||||
{
|
||||
int rv;
|
||||
@@ -384,7 +436,12 @@ int _inspectMsgCommand(AQH_HTTP_REQUEST *rq, const GWEN_MSG *msg)
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
_setModuleNameFromUrl(rq);
|
||||
s=GWEN_Url_GetPath(rq->url);
|
||||
if (!(s && *s)) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Empty url in request, assuming \"/\"");
|
||||
s="/";
|
||||
}
|
||||
rq->urlPath=s;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -399,8 +456,10 @@ void _inspectMsgHeader(AQH_HTTP_REQUEST *rq, const GWEN_MSG *msg)
|
||||
const char *s;
|
||||
|
||||
s=GWEN_DB_GetCharValue(rq->dbCookies, AQH_HTTP_REQUEST_SESSIONCOOKIE, 0, NULL);
|
||||
if (s && *s)
|
||||
if (s && *s) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Sessionid: %s", s);
|
||||
AQH_HttpRequest_SetSessionId(rq, s);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -419,7 +478,7 @@ int _inspectMsgBody(AQH_HTTP_REQUEST *rq, const GWEN_MSG *msg)
|
||||
const char *s;
|
||||
|
||||
/* check whether we need to parse POST body */
|
||||
s=GWEN_DB_GetCharValue(rq->dbCommand, "content-type", 0, NULL);
|
||||
s=GWEN_DB_GetCharValue(rq->dbHeader, "content-type", 0, NULL);
|
||||
if (s && strcasecmp(s, "application/x-www-form-urlencoded")==0) {
|
||||
rq->dbPostBody=GWEN_DB_Group_new("post");
|
||||
rv=_parsePostBody((const char*) (rq->recvdBodyPtr), rq->recvdBodySize, rq->dbPostBody);
|
||||
@@ -519,34 +578,6 @@ void _setCookieValue(GWEN_DB_NODE *dbCookies, const char *nameStart, int nameLen
|
||||
|
||||
|
||||
|
||||
void _setModuleNameFromUrl(AQH_HTTP_REQUEST *rq)
|
||||
{
|
||||
if (rq->url) {
|
||||
const char *sPath;
|
||||
|
||||
sPath=GWEN_Url_GetPath(rq->url);
|
||||
if (sPath && *sPath) {
|
||||
if (*sPath=='/')
|
||||
sPath++;
|
||||
while(*sPath && *sPath<33)
|
||||
sPath++;
|
||||
if (*sPath) {
|
||||
const char *s;
|
||||
|
||||
s=sPath;
|
||||
while(*s && *s!='/')
|
||||
s++;
|
||||
if (s>sPath) {
|
||||
free(rq->moduleName);
|
||||
rq->moduleName=GWEN_Text_strndup(sPath, s-sPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _parsePostBody(const char *s, int contentLength, GWEN_DB_NODE *dbBody)
|
||||
{
|
||||
while(contentLength>0) {
|
||||
@@ -569,6 +600,7 @@ int _parsePostBody(const char *s, int contentLength, GWEN_DB_NODE *dbBody)
|
||||
int valueLen;
|
||||
|
||||
s++;
|
||||
contentLength--;
|
||||
while((contentLength>0) && (*s<33)) {
|
||||
s++;
|
||||
contentLength--;
|
||||
@@ -584,16 +616,18 @@ int _parsePostBody(const char *s, int contentLength, GWEN_DB_NODE *dbBody)
|
||||
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);
|
||||
if (_unescapeUrlEncoded(sNameStart, nameLen, sNameBuf, sizeof(sNameBuf))>=0 &&
|
||||
_unescapeUrlEncoded(sValueStart, valueLen, sValueBuf, sizeof(sValueBuf))>=0)
|
||||
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=='&'))
|
||||
if ((contentLength>0) && (*s=='&')) {
|
||||
contentLength--;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
} /* while */
|
||||
return 0;
|
||||
@@ -601,5 +635,92 @@ int _parsePostBody(const char *s, int contentLength, GWEN_DB_NODE *dbBody)
|
||||
|
||||
|
||||
|
||||
int _unescapeUrlEncoded(const char *src, unsigned int srclen, char *buffer, unsigned int maxsize)
|
||||
{
|
||||
unsigned int size;
|
||||
|
||||
size=0;
|
||||
|
||||
while (*src && srclen>0) {
|
||||
unsigned char x;
|
||||
|
||||
x=(unsigned char)*src;
|
||||
if (
|
||||
(x>='A' && x<='Z') ||
|
||||
(x>='a' && x<='z') ||
|
||||
(x>='0' && x<='9') ||
|
||||
x==' ' ||
|
||||
x=='.' ||
|
||||
x==',' ||
|
||||
x=='.' ||
|
||||
x=='*' ||
|
||||
x=='?' ||
|
||||
x=='+'
|
||||
) {
|
||||
if (size<(maxsize-1)) {
|
||||
buffer[size++]=(x=='+')?' ':x;
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(GWEN_LOGDOMAIN, "Buffer too small");
|
||||
return GWEN_ERROR_BUFFER_OVERFLOW;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (*src=='%') {
|
||||
unsigned char d1, d2;
|
||||
unsigned char c;
|
||||
|
||||
if (srclen<3) {
|
||||
DBG_ERROR(GWEN_LOGDOMAIN, "Incomplete escape sequence (EOLN met)");
|
||||
return GWEN_ERROR_BAD_DATA;
|
||||
}
|
||||
/* skip '%' */
|
||||
src++;
|
||||
if (!(*src) || !isxdigit((int)*src)) {
|
||||
DBG_ERROR(GWEN_LOGDOMAIN, "Incomplete escape sequence (no digits)");
|
||||
return GWEN_ERROR_BAD_DATA;
|
||||
}
|
||||
/* read first digit */
|
||||
d1=(unsigned char)(toupper(*src));
|
||||
|
||||
/* get second digit */
|
||||
src++;
|
||||
if (!(*src) || !isxdigit((int)*src)) {
|
||||
DBG_ERROR(GWEN_LOGDOMAIN, "Incomplete escape sequence (only 1 digit)");
|
||||
return GWEN_ERROR_BAD_DATA;
|
||||
}
|
||||
d2=(unsigned char)(toupper(*src));
|
||||
/* compute character */
|
||||
d1-='0';
|
||||
if (d1>9)
|
||||
d1-=7;
|
||||
c=(d1<<4)&0xf0;
|
||||
d2-='0';
|
||||
if (d2>9)
|
||||
d2-=7;
|
||||
c+=(d2&0xf);
|
||||
/* store character */
|
||||
if (size<(maxsize-1))
|
||||
buffer[size++]=(char)c;
|
||||
else {
|
||||
DBG_ERROR(GWEN_LOGDOMAIN, "Buffer too small");
|
||||
return GWEN_ERROR_BUFFER_OVERFLOW;
|
||||
}
|
||||
srclen-=2;
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(GWEN_LOGDOMAIN, "Found non-alphanum characters in escaped string (\"%s\")", src);
|
||||
return GWEN_ERROR_BAD_DATA;
|
||||
}
|
||||
}
|
||||
srclen--;
|
||||
src++;
|
||||
} /* while */
|
||||
|
||||
buffer[size]=0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user