731 lines
15 KiB
C
731 lines
15 KiB
C
/****************************************************************************
|
|
* 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
|
|
|
|
//#define DISABLE_DEBUGLOG
|
|
|
|
|
|
#include "./httprequest_p.h"
|
|
|
|
#include <gwenhywfar/debug.h>
|
|
#include <gwenhywfar/text.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
GWEN_TREE2_FUNCTIONS(AQH_HTTP_REQUEST, AQH_HttpRequest);
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* forward declarations
|
|
* ------------------------------------------------------------------------------------------------
|
|
*/
|
|
|
|
static int _getParsedDbInfo(AQH_HTTP_REQUEST *rq, const GWEN_MSG *msg);
|
|
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 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);
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* implementations
|
|
* ------------------------------------------------------------------------------------------------
|
|
*/
|
|
|
|
AQH_HTTP_REQUEST *AQH_HttpRequest_new(GWEN_MSG_ENDPOINT *endpoint, const GWEN_MSG *receivedMsg)
|
|
{
|
|
AQH_HTTP_REQUEST *rq;
|
|
int rv;
|
|
|
|
GWEN_NEW_OBJECT(AQH_HTTP_REQUEST, rq);
|
|
GWEN_TREE2_INIT(AQH_HTTP_REQUEST, rq, AQH_HttpRequest);
|
|
|
|
rq->endpoint=endpoint;
|
|
rq->receivedMsg=receivedMsg;
|
|
|
|
rv=_inspectReceivedMessage(rq, receivedMsg);
|
|
if (rv<0) {
|
|
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
|
AQH_HttpRequest_free(rq);
|
|
return NULL;
|
|
}
|
|
return rq;
|
|
}
|
|
|
|
|
|
|
|
void AQH_HttpRequest_free(AQH_HTTP_REQUEST *rq)
|
|
{
|
|
if (rq) {
|
|
GWEN_TREE2_FINI(AQH_HTTP_REQUEST, rq, AQH_HttpRequest);
|
|
free(rq->sessionId);
|
|
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);
|
|
|
|
GWEN_FREE_OBJECT(rq);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
GWEN_MSG_ENDPOINT *AQH_HttpRequest_GetEndpoint(const AQH_HTTP_REQUEST *rq)
|
|
{
|
|
return rq?(rq->endpoint):NULL;
|
|
}
|
|
|
|
|
|
|
|
const GWEN_MSG *AQH_HttpRequest_GetReceivedMsg(const AQH_HTTP_REQUEST *rq)
|
|
{
|
|
return rq?(rq->receivedMsg):NULL;
|
|
}
|
|
|
|
|
|
|
|
const char *AQH_HttpRequest_GetCommand(const AQH_HTTP_REQUEST *rq)
|
|
{
|
|
return rq?(rq->command):NULL;
|
|
}
|
|
|
|
|
|
|
|
const char *AQH_HttpRequest_GetProtocol(const AQH_HTTP_REQUEST *rq)
|
|
{
|
|
return rq?(rq->protocol):NULL;
|
|
}
|
|
|
|
|
|
|
|
GWEN_URL *AQH_HttpRequest_GetUrl(const AQH_HTTP_REQUEST *rq)
|
|
{
|
|
return rq?(rq->url):NULL;
|
|
}
|
|
|
|
|
|
|
|
void AQH_HttpRequest_SetUrl(AQH_HTTP_REQUEST *rq, GWEN_URL *url)
|
|
{
|
|
if (rq) {
|
|
GWEN_Url_free(rq->url);
|
|
rq->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;
|
|
}
|
|
|
|
|
|
|
|
GWEN_DB_NODE *AQH_HttpRequest_GetDbHeader(const AQH_HTTP_REQUEST *rq)
|
|
{
|
|
return rq?(rq->dbHeader):NULL;
|
|
}
|
|
|
|
|
|
|
|
GWEN_DB_NODE *AQH_HttpRequest_GetDbCookies(const AQH_HTTP_REQUEST *rq)
|
|
{
|
|
return rq?(rq->dbCookies):NULL;
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
|
|
void AQH_HttpRequest_SetSessionId(AQH_HTTP_REQUEST *rq, const char *s)
|
|
{
|
|
if (rq) {
|
|
free(rq->sessionId);
|
|
rq->sessionId=s?strdup(s):NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const char *AQH_HttpRequest_GetModuleName(const AQH_HTTP_REQUEST *rq)
|
|
{
|
|
return rq?(rq->moduleName):NULL;
|
|
}
|
|
|
|
|
|
|
|
void AQH_HttpRequest_SetModuleName(AQH_HTTP_REQUEST *rq, const char *s)
|
|
{
|
|
if (rq) {
|
|
free(rq->moduleName);
|
|
rq->moduleName=s?strdup(s):NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
AQH_SESSION *AQH_HttpRequest_GetSession(const AQH_HTTP_REQUEST *rq)
|
|
{
|
|
return rq?(rq->session):NULL;
|
|
}
|
|
|
|
|
|
|
|
void AQH_HttpRequest_SetSession(AQH_HTTP_REQUEST *rq, AQH_SESSION *session)
|
|
{
|
|
if (rq)
|
|
rq->session=session;
|
|
}
|
|
|
|
|
|
|
|
AQH_MODULE *AQH_HttpRequest_GetModule(const AQH_HTTP_REQUEST *rq)
|
|
{
|
|
return rq?(rq->module):NULL;
|
|
}
|
|
|
|
|
|
|
|
void AQH_HttpRequest_SetModule(AQH_HTTP_REQUEST *rq, AQH_MODULE *m)
|
|
{
|
|
if (rq)
|
|
rq->module=m;
|
|
}
|
|
|
|
|
|
|
|
uint32_t AQH_HttpRequest_GetModulePerms(const AQH_HTTP_REQUEST *rq)
|
|
{
|
|
return rq?(rq->modulePerms):0;
|
|
}
|
|
|
|
|
|
|
|
void AQH_HttpRequest_SetModulePerms(AQH_HTTP_REQUEST *rq, uint32_t i)
|
|
{
|
|
if (rq)
|
|
rq->modulePerms=i;
|
|
}
|
|
|
|
|
|
|
|
int AQH_HttpRequest_GetResponseCode(const AQH_HTTP_REQUEST *rq)
|
|
{
|
|
return rq?(rq->responseCode):0;
|
|
}
|
|
|
|
|
|
|
|
void AQH_HttpRequest_SetResponseCode(AQH_HTTP_REQUEST *rq, int i)
|
|
{
|
|
if (rq)
|
|
rq->responseCode=i;
|
|
}
|
|
|
|
|
|
|
|
const char *AQH_HttpRequest_GetResponseText(const AQH_HTTP_REQUEST *rq)
|
|
{
|
|
return rq?(rq->responseText):NULL;
|
|
}
|
|
|
|
|
|
|
|
void AQH_HttpRequest_SetResponseText(AQH_HTTP_REQUEST *rq, const char *s)
|
|
{
|
|
if (rq) {
|
|
free(rq->responseText);
|
|
rq->responseText=s?strdup(s):NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
GWEN_MSG *AQH_HttpRequest_GetResponseMsg(const AQH_HTTP_REQUEST *rq)
|
|
{
|
|
return rq?(rq->responseMsg):NULL;
|
|
}
|
|
|
|
|
|
|
|
GWEN_MSG *AQH_HttpRequest_TakeResponseMsg(AQH_HTTP_REQUEST *rq)
|
|
{
|
|
if (rq) {
|
|
GWEN_MSG *msg;
|
|
|
|
msg=rq->responseMsg;
|
|
rq->responseMsg=NULL;
|
|
return msg;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
void AQH_HttpRequest_SetResponseMsg(AQH_HTTP_REQUEST *rq, GWEN_MSG *msg)
|
|
{
|
|
if (rq && msg) {
|
|
GWEN_Msg_free(rq->responseMsg);
|
|
rq->responseMsg=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;
|
|
|
|
rv=_getParsedDbInfo(rq, msg);
|
|
if (rv<0) {
|
|
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
|
return rv;
|
|
}
|
|
|
|
rv=_inspectMsgCommand(rq, msg);
|
|
if (rv<0) {
|
|
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
|
return rv;
|
|
}
|
|
|
|
_inspectMsgHeader(rq, msg);
|
|
|
|
rv=_inspectMsgBody(rq, msg);
|
|
if (rv<0) {
|
|
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
|
return rv;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int _getParsedDbInfo(AQH_HTTP_REQUEST *rq, const GWEN_MSG *msg)
|
|
{
|
|
GWEN_DB_NODE *dbParsedInfo;
|
|
GWEN_DB_NODE *db;
|
|
|
|
dbParsedInfo=GWEN_Msg_GetDbParsedInfo(msg);
|
|
if (dbParsedInfo==NULL) {
|
|
DBG_INFO(AQH_LOGDOMAIN, "No parsed info db, msg probably not generated by HTTP endpoint module");
|
|
return GWEN_ERROR_GENERIC;
|
|
}
|
|
|
|
db=GWEN_DB_GetGroup(dbParsedInfo, GWEN_PATH_FLAGS_PATHMUSTEXIST, "command");
|
|
if (db==NULL) {
|
|
DBG_INFO(AQH_LOGDOMAIN, "No parsed command db, msg probably not generated by HTTP endpoint module");
|
|
return GWEN_ERROR_GENERIC;
|
|
}
|
|
rq->dbCommand=db;
|
|
|
|
db=GWEN_DB_GetGroup(dbParsedInfo, GWEN_PATH_FLAGS_PATHMUSTEXIST, "header");
|
|
if (db==NULL) {
|
|
DBG_INFO(AQH_LOGDOMAIN, "No parsed header db, msg probably not generated by HTTP endpoint module or no header recvd, ignoring");
|
|
}
|
|
rq->dbHeader=db;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int _inspectMsgCommand(AQH_HTTP_REQUEST *rq, const GWEN_MSG *msg)
|
|
{
|
|
const char *s;
|
|
|
|
s=GWEN_DB_GetCharValue(rq->dbCommand, "command", 0, NULL);
|
|
if (!(s && *s)) {
|
|
DBG_ERROR(AQH_LOGDOMAIN, "No command in request");
|
|
return GWEN_ERROR_GENERIC;
|
|
}
|
|
rq->command=s;
|
|
|
|
s=GWEN_DB_GetCharValue(rq->dbCommand, "protocol", 0, NULL);
|
|
if (!(s && *s)) {
|
|
DBG_ERROR(AQH_LOGDOMAIN, "No protocol in request");
|
|
return GWEN_ERROR_GENERIC;
|
|
}
|
|
rq->protocol=s;
|
|
|
|
s=GWEN_DB_GetCharValue(rq->dbCommand, "url", 0, NULL);
|
|
if (!(s && *s)) {
|
|
DBG_ERROR(AQH_LOGDOMAIN, "No url in request");
|
|
return GWEN_ERROR_GENERIC;
|
|
}
|
|
|
|
rq->url=GWEN_Url_fromCommandString(s);
|
|
if (rq->url==NULL) {
|
|
DBG_ERROR(AQH_LOGDOMAIN, "Invalid URL [%s]", s);
|
|
return GWEN_ERROR_GENERIC;
|
|
}
|
|
|
|
s=GWEN_Url_GetPath(rq->url);
|
|
if (!(s && *s)) {
|
|
DBG_ERROR(AQH_LOGDOMAIN, "Empty url in request, assuming \"/\"");
|
|
s="/";
|
|
}
|
|
rq->urlPath=s;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
void _inspectMsgHeader(AQH_HTTP_REQUEST *rq, const GWEN_MSG *msg)
|
|
{
|
|
if (rq->dbHeader)
|
|
rq->dbCookies=_extractCookies(rq->dbHeader);
|
|
if (rq->dbCookies) {
|
|
const char *s;
|
|
|
|
s=GWEN_DB_GetCharValue(rq->dbCookies, AQH_HTTP_REQUEST_SESSIONCOOKIE, 0, NULL);
|
|
if (s && *s) {
|
|
DBG_INFO(AQH_LOGDOMAIN, "Sessionid: %s", s);
|
|
AQH_HttpRequest_SetSessionId(rq, s);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int _inspectMsgBody(AQH_HTTP_REQUEST *rq, const GWEN_MSG *msg)
|
|
{
|
|
int rv;
|
|
|
|
rq->recvdBodySize=GWEN_Msg_GetParsedPayloadSize(msg);
|
|
if (rq->recvdBodySize>0)
|
|
rq->recvdBodyPtr=GWEN_Msg_GetConstBuffer(msg)+GWEN_Msg_GetParsedPayloadOffset(msg);
|
|
|
|
if (rq->dbHeader && rq->recvdBodySize>0 && strcasecmp(rq->command, "POST")==0) {
|
|
const char *s;
|
|
|
|
/* check whether we need to parse POST body */
|
|
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);
|
|
if (rv<0) {
|
|
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
|
return rv;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
GWEN_DB_NODE *_extractCookies(GWEN_DB_NODE *dbHeader)
|
|
{
|
|
int i;
|
|
GWEN_DB_NODE *dbCookies;
|
|
|
|
dbCookies=GWEN_DB_GetGroup(dbHeader, 0, "cookies");
|
|
for (i=0; ; i++) {
|
|
const char *sCookie;
|
|
|
|
sCookie=GWEN_DB_GetCharValue(dbHeader, "Cookie", i, NULL);
|
|
if (sCookie && *sCookie) {
|
|
const char *s;
|
|
|
|
s=sCookie;
|
|
while(*s) {
|
|
while(*s && *s<33)
|
|
s++;
|
|
|
|
if (*s) {
|
|
const char *nameStart;
|
|
int nameLen;
|
|
|
|
nameStart=s++;
|
|
while(*s && *s!='=')
|
|
s++;
|
|
if (*s=='=') {
|
|
nameLen=s-nameStart;
|
|
s++;
|
|
while(*s && *s<33)
|
|
s++;
|
|
if (*s) {
|
|
const char *valueStart;
|
|
int valueLen;
|
|
|
|
valueStart=s;
|
|
while(*s && *s!=';')
|
|
s++;
|
|
valueLen=s-valueStart;
|
|
|
|
_setCookieValue(dbCookies, nameStart, nameLen, valueStart, valueLen, 0);
|
|
|
|
if (*s)
|
|
s++;
|
|
}
|
|
}
|
|
}
|
|
} /* while(*s) */
|
|
} /* if (sCookie && *sCookie) */
|
|
else
|
|
break;
|
|
} /* for */
|
|
return dbCookies;
|
|
}
|
|
|
|
|
|
|
|
void _setCookieValue(GWEN_DB_NODE *dbCookies, const char *nameStart, int nameLen, const char *valueStart, int valueLen, uint32_t dbFlags)
|
|
{
|
|
if (nameLen && valueLen) {
|
|
int i;
|
|
char *sName;
|
|
char *sValue;
|
|
|
|
for (i=nameLen-1; i>0; i--) {
|
|
if (nameStart[i]>32)
|
|
break;
|
|
}
|
|
sName=GWEN_Text_strndup(nameStart, i+1);
|
|
|
|
for (i=valueLen-1; i>0; i--) {
|
|
if (valueStart[i]>32)
|
|
break;
|
|
}
|
|
sValue=GWEN_Text_strndup(valueStart, i+1);
|
|
|
|
DBG_INFO(AQH_LOGDOMAIN, "Received Cookie: [%s]=[%s]", sName, sValue);
|
|
GWEN_DB_SetCharValue(dbCookies, dbFlags, sName, sValue);
|
|
free(sValue);
|
|
free(sName);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int _parsePostBody(const char *s, int contentLength, GWEN_DB_NODE *dbBody)
|
|
{
|
|
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++;
|
|
contentLength--;
|
|
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 (_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=='&')) {
|
|
contentLength--;
|
|
s++;
|
|
}
|
|
}
|
|
} /* while */
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int _unescapeUrlEncoded(const char *src, unsigned int srclen, char *buffer, unsigned int maxsize)
|
|
{
|
|
unsigned int size;
|
|
|
|
size=0;
|
|
|
|
while (srclen>0 && *src) {
|
|
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=='+' ||
|
|
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;
|
|
}
|
|
|
|
|
|
|
|
|