Sun, 06 Nov 2022 17:41:39 +0100
prepare serverconfig parser to be also used for obj.conf and init.conf
src/server/config/serverconfig.c | file | annotate | diff | comparison | revisions | |
src/server/config/serverconfig.h | file | annotate | diff | comparison | revisions |
--- a/src/server/config/serverconfig.c Sun Nov 06 16:59:39 2022 +0100 +++ b/src/server/config/serverconfig.c Sun Nov 06 17:41:39 2022 +0100 @@ -44,8 +44,18 @@ return NULL; } + CxMempool *mp = cxBasicMempoolCreate(512); + if(!mp) { + fclose(in); + return NULL; + } + CxBuffer buf; - cxBufferInit(&buf, NULL, 16384, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND|CX_BUFFER_FREE_CONTENTS); + if(cxBufferInit(&buf, NULL, 16384, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND|CX_BUFFER_FREE_CONTENTS)) { + fclose(in); + cxMempoolDestroy(mp); + return NULL; + } //ucx_stream_copy(in, buf, (read_func)fread, (write_func)ucx_buffer_write); char readbuf[2048]; @@ -55,7 +65,11 @@ } fclose(in); - ServerConfig *scfg = serverconfig_parse(cx_strn(buf.space, buf.size)); + ConfigParser2 parser; + ZERO(&parser, sizeof(ConfigParser2)); + parser.mp = mp; + parser.allow_hierarchy = true; + ServerConfig *scfg = serverconfig_parse(&parser, cx_strn(buf.space, buf.size)); cxBufferDestroy(&buf); return scfg; @@ -190,9 +204,8 @@ return 0; } -ServerConfig* serverconfig_parse(cxstring content) { - CxMempool *mp = cxBasicMempoolCreate(512); - if(!mp) return NULL; +ServerConfig* serverconfig_parse(ConfigParser2 *parser, cxstring content) { + CxMempool *mp = parser->mp; CxAllocator *a = (CxAllocator*)mp->allocator; ServerConfig *config = cxMalloc(a, sizeof(ServerConfig)); @@ -248,6 +261,12 @@ // this is a newline after a object is closed with '}' // the line containing "}\n" should be added to the object parent->text_end = line_cp; + // validate + if(parser->validateObjEnd && parser->validateObjEnd(parser, parent)) { + // validation failed + err = 1; + break; + } // done with this object, remove it from the stack ConfigNodeStack *remove_item = node_stack; node_stack = node_stack->next; @@ -261,6 +280,10 @@ obj->text_begin = new_textbegin; } else { // normal line containing a directive, space or comment + if(parser->validateDirective && parser->validateDirective(parser, current)) { + err = 1; + break; + } // add it to parent node current->text_begin = line_cp; CFG_NODE_ADD(&parent->children_begin, &parent->children_end, current); @@ -270,7 +293,14 @@ // the type is set to CONFIG_NODE_OBECT if it was followed by // a '{' character if(obj && obj->type == CONFIG_NODE_OBJECT) { - // new object started, add it to the stack + // new object started + if(parser->validateObjBegin && parser->validateObjBegin(parser, obj)) { + // validation callback failed + err = 1; + break; + } + + // add it to the stack nodestack_prepend(a, &node_stack, obj); obj = NULL; } @@ -286,6 +316,13 @@ // either a directive/obj name, parameter or { } if(!cx_strcmp(token.content, cx_str("{"))) { + // check if the parser allows an object hierarchy + if(!parser->allow_hierarchy) { + parser->error = CONFIG_PARSER_SYNTAX_ERROR; + err = 1; + break; + } + // obj is pointing to the previous node that started // a directive if(!obj) { @@ -297,6 +334,13 @@ current->type = CONFIG_NODE_OPEN_OBJECT; } } else if(!cx_strcmp(token.content, cx_str("}"))) { + // check if the parser allows an object hierarchy + if(!parser->allow_hierarchy) { + parser->error = CONFIG_PARSER_SYNTAX_ERROR; + err = 1; + break; + } + obj_closed = 1; // force newline before next directive obj = NULL; current->type = CONFIG_NODE_CLOSE_OBJECT;
--- a/src/server/config/serverconfig.h Sun Nov 06 16:59:39 2022 +0100 +++ b/src/server/config/serverconfig.h Sun Nov 06 17:41:39 2022 +0100 @@ -34,6 +34,8 @@ #include <cx/mempool.h> #include <cx/string.h> +#include <stdbool.h> + #include "conf.h" #ifdef __cplusplus @@ -46,6 +48,7 @@ typedef struct ServerConfig ServerConfig; typedef struct ConfigNode ConfigNode; typedef struct CFGToken CFGToken; +typedef struct ConfigParser2 ConfigParser2; // TODO: rename to ConfigParser after old ConfigParser is removed typedef enum ConfigNodeType ConfigNodeType; typedef enum CFGTokenType CFGTokenType; @@ -98,9 +101,50 @@ CFGTokenType type; }; +enum ConfigParserError { + CONFIG_PARSER_OOM = 0, + CONFIG_PARSER_SYNTAX_ERROR +}; + +/* + * CfgValidateNodeFunc functions are called by the parser to validate + * objects and directives. + * + * The function must return 0 if the validation was successful. If the + * functions returns a value != 0, the parser aborts. + */ +typedef int(*CfgValidateNodeFunc)(ConfigParser2 *parser, ConfigNode *node); + +struct ConfigParser2 { + CxMempool *mp; + + int error; + + /* + * called when an object is started + */ + CfgValidateNodeFunc validateObjBegin; + + /* + * called when an object is closed + */ + CfgValidateNodeFunc validateObjEnd; + + /* + * called before a directive is added + */ + CfgValidateNodeFunc validateDirective; + + /* + * true: store result in a tree + * false: flat list of directives, don't allow '{' and '}' + */ + bool allow_hierarchy; +}; + ServerConfig* serverconfig_load(const char *file); -ServerConfig* serverconfig_parse(cxstring content); +ServerConfig* serverconfig_parse(ConfigParser2 *parser, cxstring content); void serverconfig_free(ServerConfig *cfg);