Sun, 23 Nov 2025 12:44:59 +0100
add location config parser
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2025 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "location.h" #include "config.h" #include "../util/util.h" #include <cx/linked_list.h> #define DIR_CHECK_ARGC(n) if(argc != n) { \ log_ereport(LOG_FAILURE, "%s directive argc != %d", name.ptr, n); \ return 1; \ } static void location_list_add(WSLocation *location, WSLocation *sub) { void **begin = (void**)&location->children_begin; void **end = (void**)&location->children_end; cx_linked_list_add(begin, end, offsetof(WSLocation, prev), offsetof(WSLocation, next), sub); } static int add_location_config(const CxAllocator *a, WSLocation *location, ConfigNode *dir) { cxmutstr name = dir->name; int argc = serverconfig_directive_count_args(dir); if(!cx_strcasecmp(name, "DirectoryIndex")) { DIR_CHECK_ARGC(1); location->config.set_dirindex = TRUE; location->config.dirindex = util_getboolean_s(cx_strcast(dir->args->value), FALSE); } else if(!cx_strcasecmp(name, "DocumentRoot")) { DIR_CHECK_ARGC(1); location->config.docroot = cx_strdup_a(a, dir->args->value); } else if(!cx_strcasecmp(name, "Location")) { WSLocation *sub_location = cfg_location_get(a, dir); if(!sub_location) { return 1; } location_list_add(location, sub_location); } return 0; } WSLocation* cfg_location_get(const CxAllocator *a, ConfigNode *obj) { WSLocationMatch match = WS_LOCATION_MATCH_EXACT; cxmutstr match_str; int regex_flags = REG_EXTENDED; int argc = serverconfig_directive_count_args(obj); if(argc == 2) { // arg0: match type cxmutstr type_str = obj->args->value; if(!cx_strcmp(type_str, "=")) { // noop } else if(!cx_strcmp(type_str, "^~")) { match = WS_LOCATION_MATCH_PREFIX; } else if(!cx_strcmp(type_str, "~")) { match = WS_LOCATION_MATCH_CS_REGEX; } else if(!cx_strcmp(type_str, "~*")) { match = WS_LOCATION_MATCH_CI_REGEX; regex_flags |= REG_ICASE; } else { log_ereport(LOG_FAILURE, "Location: unknown operator %.*s", (int)type_str.length, type_str.ptr); return NULL; } // arg1: match_string match_str = obj->args->next->value; } else if(argc == 1) { // arg0: match_string match_str = obj->args->value; } else if(argc > 2) { log_ereport(LOG_FAILURE, "Location directive must have 0-2 args"); return NULL; } WSLocation *location = cxZalloc(a, sizeof(WSLocation)); location->match_string = cx_strdup_a((a), match_str); if(match == WS_LOCATION_MATCH_CS_REGEX || match == WS_LOCATION_MATCH_CI_REGEX) { if(regcomp(&location->regex, match_str.ptr, regex_flags)) { log_ereport(LOG_FAILURE, "Location: cannot compile regex pattern %s", match_str.ptr); return NULL; } } ConfigNode *dir = obj->children_begin; while(dir) { if(dir->type == CONFIG_NODE_OBJECT || dir->type == CONFIG_NODE_DIRECTIVE) { if(add_location_config(a, location, dir)) { log_ereport(LOG_FAILURE, "Location %s: abort", match_str.ptr); return NULL; } } dir = dir->next; } return location; }