diff -r b7dcc9c4f270 -r f1d29785ad2d src/server/config/objconf.c --- a/src/server/config/objconf.c Mon Nov 07 17:59:44 2022 +0100 +++ b/src/server/config/objconf.c Mon Nov 07 22:30:12 2022 +0100 @@ -65,6 +65,152 @@ return conf; } +ObjectConfig2* objectconf_load(const char *file) { + CxMempool *mp = cxBasicMempoolCreate(512); + if(!mp) { + return NULL; + } + + // setup parser + ConfigParser2 parser; + memset(&parser, 0, sizeof(ConfigParser2)); + parser.mp = mp; + parser.validateDirective = objectconf_validate_directive; + parser.validateObjBegin = objectconf_validate_objbegin; + parser.validateObjEnd = objectconf_validate_objend; + parser.allow_hierarchy = 1; + + ConfigNode *obj_config = serverconfig_load_file(&parser, file); + if(!obj_config) { + cxMempoolDestroy(mp); + return NULL; + } + + ObjectConfig2 *conf = cxMalloc(mp->allocator, sizeof(ObjectConfig2)); + if(!conf) { + cxMempoolDestroy(mp); + return NULL; + } + + conf->mp = mp; + conf->root = obj_config; + + return conf; +} + +void objectconf_free(ObjectConfig2 *objconf) { + cxMempoolDestroy(objconf->mp); +} + +int objectconf_validate_directive(ConfigParser2 *parser, ConfigNode *node) { + // It is possible that this function is called for Objects + // if { is on the next line + // It may be possible to fix the parser to not do that, but it is fine + // to just deal with that here + + // ignore if node->name is an Object name like + // Object, Client, If, Else IfElse + const char *objnames[] = { "Object", "Client", "If", "ElseIf", "Else" }; + size_t typeindex; + if(!serverconfig_validate_directive_name(node, objnames, 5, &typeindex)) { + return 0; + } + + // now check directive type + const char *dirtypes[] = { "AuthTrans", "NameTrans", "PathCheck", "ObjectType", "Service", "AddLog", "Error" }; + if(serverconfig_validate_directive_name(node, dirtypes, 7, &typeindex)) { + return 1; + } + + // directives must have parameter names + ConfigParam *param_err; + if(serverconfig_check_param_names(node, ¶m_err)) { + return 1; + } + + // check if the fn parameter exists + cxstring fn = serverconfig_directive_get_arg(node, cx_str("fn")); + if(fn.length == 0) { + return 1; + } + + return 0; +} + +static int validate_else_node(ConfigNode *node) { + // previous node must be "If" or "ElseIf" + ConfigNode *prev = serverconfig_previous_dir_or_obj(node); + const char *allowed_prev_types[] = { "If", "ElseIf" }; + size_t typeindex; + if(serverconfig_validate_directive_name(prev, allowed_prev_types, 2, &typeindex)) { + return 1; // prevous node (not counting space, comments) is not "If" or "Else" + } + + // "Else" must have no args + return node->args ? 1 : 0; +} + +static int validate_elseif_node(ConfigNode *node) { + // the previous node must be "If" or "IfElse" + // in case if "IfElse", we also have to check all previous nodes, until + // we find the starting "If" node + const char *allowed_prev_types[] = { "If", "ElseIf" }; + size_t typeindex; + ConfigNode *prev = serverconfig_previous_dir_or_obj(node); + while(prev) { + if(serverconfig_validate_directive_name(prev, allowed_prev_types, 2, &typeindex)) { + return 1; // previous node was not "If" or "ElseIf" + } + // we found a valid "If" node, the whole construct is valid + if(typeindex == 0) { + return 0; + } + + prev = serverconfig_previous_dir_or_obj(node); + } + // at this point we found only "IfElse" nodes, but no "If" node + return 1; +} + +int objectconf_validate_objbegin(ConfigParser2 *parser, ConfigNode *node) { + // get object type + const char *objnames[] = { "Object", "Client", "If", "ElseIf", "Else" }; + size_t typeindex; + if(serverconfig_validate_directive_name(node, objnames, 5, &typeindex)) { + return 1; // unknown object type + } + + // some special requirements for "Else" node + if(typeindex == 4) { + // type is "Else" + return validate_else_node(node); + } + + // check "ElseIf" was used after "If" or "IfElse" + if(typeindex == 3 && validate_elseif_node(node)) { + return 1; + } + + // only Object must have a name/value arg, other types can have more + // complex parameters + if(typeindex == 0) { + // type is "Object" + ConfigParam *err; + if(serverconfig_check_param_names(node, &err)) { + return 1; + } + return 0; + } + + // all remaining object types must have arguments, but don't check more + return node->args ? 0 : 1; +} + +int objectconf_validate_objend(ConfigParser2 *parser, ConfigNode *node) { + return 0; +} + + void free_object_config(ObjectConfig *conf) { // free other lists if(conf->levels) {