src/server/util/object.c

Wed, 27 Nov 2024 23:00:07 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Wed, 27 Nov 2024 23:00:07 +0100
changeset 563
6ca97c99173e
parent 490
d218607f5a7e
permissions
-rw-r--r--

add TODO to use a future ucx feature

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2013 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 <cx/string.h>
#include <cx/linked_list.h>
#include <cx/array_list.h>
#include <cx/compare.h>

#include "../public/nsapi.h"

#include "object.h"
#include "util.h"
#include "pool.h"
#include "../daemon/func.h"



httpd_object* object_new(pool_handle_t *pool, char *name) {
    httpd_object *obj = pool_malloc(pool, sizeof(httpd_object));
    obj->pool = pool;
    obj->name = name;
    obj->path = NULL;

    // create directive table
    obj->dt = pool_calloc(pool, NUM_NSAPI_TYPES - 1, sizeof(struct dtable));
    obj->nd = NUM_NSAPI_TYPES - 1;

    return obj;
}

void object_free(httpd_object *obj) {
    //free(obj->name);
    //free(obj->dt);
}


int object_add_directive(httpd_object *obj, directive *dir, int dt) {
    dtable *l = object_get_dtable(obj, dt);
    // allocate space for the new directive
    if(l->ndir >= l->alloc) {
        l->alloc += 8;
        directive **drs = pool_realloc(obj->pool, l->dirs, (l->alloc)*sizeof(void*));
        if(!drs) {
            l->alloc -= 8;
            return -1;
        }
        l->dirs = drs;
    }
    
    // add directive
    l->dirs[l->ndir++] = dir;
    return 0;
}


/* objset functions */
httpd_objset* objset_create(pool_handle_t *pool) {
    httpd_objset *os = pool_malloc(pool, sizeof(httpd_objset));

    os->obj = pool_calloc(pool, 2, sizeof(void*));
    os->pos = 0;

    return os;
}

void objset_add_object(pool_handle_t *p, httpd_objset *os, httpd_object *obj) {
    if(os->pos != 0 && os->pos % 2 == 0) {
        os->obj = pool_realloc(p, os->obj, (os->pos + 2) * sizeof(void*));
    }
    os->obj[os->pos] = obj;
    os->pos++;
}

void httpobjconf_add_object(HTTPObjectConfig *conf, httpd_object *obj) {
    conf->nobj++;
    conf->objects = realloc(conf->objects, conf->nobj * sizeof(void*));
    conf->objects[conf->nobj - 1] = obj;
}


void nsapi_context_next_stage(NSAPIContext *context) {
    context->dtable_index  = 0;
    context->objset_index  = -1;
    context->last_req_code = REQ_NOACTION;
}


/* ------------------------------ Expression ------------------------------ */

Expression* condition_create(pool_handle_t *pool, CxList *tokens) {
    size_t pos = 0;
    NSAPIExpression *expression = expr_parse_logical_expr(pool, tokens, &pos);
    if(!expression || pos != tokens->size) {
        return NULL;
    }
    
    return NULL;
}


typedef struct {
  pool_handle_t *pool;
  CxList *op_stack;
  CxList *ex_stack;
  CxList *tokens;
  size_t *pos;
  WSBool expect_value;
  WSBool expect_arg;
} ExprParser;

typedef struct {
    NSAPIExpressionOperator operator;
    cxstring identifier;
    int expect_value;
    int open_parenthesis;
} ExprOpStackItem;

static void expr_free(pool_handle_t *pool, NSAPIExpression *expr) {
    if(expr->left) {
        expr_free(pool, expr->left);
    }
    if(expr->right) {
        expr_free(pool, expr->right);
    }
    if(expr->type == NSAPI_EXPRESSION_STRING && expr->value.str.ptr) {
        pool_free(pool, (char*)expr->value.str.ptr);
    } else if(expr->type == NSAPI_EXPRESSION_VARIABLE && expr->value.var.ptr) {
        pool_free(pool, (char*)expr->value.var.ptr);
    }
    pool_free(pool, expr);
}

static NSAPIExpressionOperator expr_operator(cxstring token) {
    if(!cx_strcmp(token, cx_str(","))) {
       return NSAPI_EXPRESSION_ARG; 
    } else if(!cx_strcmp(token, cx_str("+"))) {
        return NSAPI_EXPRESSION_ADD;
    } else if(!cx_strcmp(token, cx_str("-"))) {
        return NSAPI_EXPRESSION_SUB;
    } else if(!cx_strcmp(token, cx_str("*"))) {
        return NSAPI_EXPRESSION_MUL;
    } else if(!cx_strcmp(token, cx_str("/"))) {
        return NSAPI_EXPRESSION_DIV;
    } else if(!cx_strcmp(token, cx_str("%"))) {
        return NSAPI_EXPRESSION_MOD;
    } else if(!cx_strcmp(token, cx_str("."))) {
        return NSAPI_EXPRESSION_STRCAT;
    } else if(!cx_strcmp(token, cx_str("not")) || !cx_strcmp(token, cx_str("!"))) {
        return NSAPI_EXPRESSION_NOT;
    } else if(!cx_strcmp(token, cx_str("and")) || !cx_strcmp(token, cx_str("&&"))) {
        return NSAPI_EXPRESSION_AND;
    } else if(!cx_strcmp(token, cx_str("or")) || !cx_strcmp(token, cx_str("||"))) {
        return NSAPI_EXPRESSION_OR;
    } else if(!cx_strcmp(token, cx_str("xor")) || !cx_strcmp(token, cx_str("^"))) {
        return NSAPI_EXPRESSION_XOR;
    } else if(!cx_strcmp(token, cx_str("=="))) {
        return NSAPI_EXPRESSION_EQ;
    } else if(!cx_strcmp(token, cx_str("!="))) {
        return NSAPI_EXPRESSION_NEQ;
    } else if(!cx_strcmp(token, cx_str(">"))) {
        return NSAPI_EXPRESSION_GT;
    } else if(!cx_strcmp(token, cx_str("<"))) {
        return NSAPI_EXPRESSION_LT;
    } else if(!cx_strcmp(token, cx_str(">="))) {
        return NSAPI_EXPRESSION_GE;
    } else if(!cx_strcmp(token, cx_str("<="))) {
        return NSAPI_EXPRESSION_LE;
    } else if(!cx_strcmp(token, cx_str("="))) {
        return NSAPI_EXPRESSION_WILDCARD_MATCH;
    } else if(!cx_strcmp(token, cx_str("=~"))) {
        return NSAPI_EXPRESSION_REGEX_MATCH;
    } else if(!cx_strcmp(token, cx_str("!~"))) {
        return NSAPI_EXPRESSION_REGEX_MISMATCH;
    } else if(!cx_strcmp(token, cx_str("defined"))) {
        return NSAPI_EXPRESSION_VALUE_DEFINED;
    } else if(!cx_strcmp(token, cx_str("-d"))) {
        return NSAPI_EXPRESSION_DIR_EXISTS;
    } else if(!cx_strcmp(token, cx_str("-e"))) {
        return NSAPI_EXPRESSION_FILE_DIR_EXISTS;
    } else if(!cx_strcmp(token, cx_str("-f"))) {
        return NSAPI_EXPRESSION_FILE_EXISTS;
    } else if(!cx_strcmp(token, cx_str("-l"))) {
        return NSAPI_EXPRESSION_SYMLINK_EXISTS;
    } else if(!cx_strcmp(token, cx_str("-r"))) {
        return NSAPI_EXPRESSION_FILE_READABLE;
    } else if(!cx_strcmp(token, cx_str("-s"))) {
        return NSAPI_EXPRESSION_FILE_SIZE;
    }
    return NSAPI_EXPRESSION_NOOP;
}

static int token_is_int(cxstring token) {
    if(token.length == 0) {
        return 0;
    }
    
    size_t start = 0;
    if(token.ptr[0] == '-' || token.ptr[0] == '+') {
        if(token.length < 2) {
            return 0;
        }
        start++;
    }
    
    for(size_t i=start;i<token.length;i++) {
        if(!isdigit(token.ptr[i])) {
            return 0;
        }
    }
    return 1;
}

static int expr_set_value(pool_handle_t *pool, NSAPIExpression *expr, cxstring token) {
    if(token.length >= 2 && token.ptr[0] == '\"' && token.ptr[token.length-1] == '\"') {
        expr->value.str = cx_strcast(cx_strdup_a(pool_allocator(pool), cx_strsubsl(token, 1, token.length-2)));
        expr->type = NSAPI_EXPRESSION_STRING;
    } else if(token.length >= 2 && token.ptr[0] == '$' && isalpha(token.ptr[1])) {
        expr->value.var = cx_strcast(cx_strdup_a(pool_allocator(pool), cx_strsubs(token, 1)));
        expr->type = NSAPI_EXPRESSION_VARIABLE;
    } else if(token_is_int(token)) {
        if(!util_strtoint(token.ptr, &expr->value.i)) {
            return 1;
        }
        expr->type = NSAPI_EXPRESSION_INT;
    } else if(!strcmp(token.ptr, "true")) {
        expr->type = NSAPI_EXPRESSION_BOOL;
        expr->value.b = 1;
    } else if(!strcmp(token.ptr, "false")) {
        expr->type = NSAPI_EXPRESSION_BOOL;
        expr->value.b = 0;
    } else {
        return 1;
    }
    // TODO: double
    return 0;
}

cxstring expr_next_token(CxList *tokens, size_t *pos) {
    cxstring *token = cxListAt(tokens, *pos);
    if(token) {
        (*pos)++;
        return *token;
    }
    return (cxstring){NULL, 0};
}

NSAPIExpression* expr_parser_pop(ExprParser *parser) {
    CxList *stack = parser->ex_stack;
    if(stack->size == 0) {
        return NULL;
    }
    NSAPIExpression *ret = *((NSAPIExpression**)cxListAt(stack, stack->size-1));
    cxListRemove(stack, stack->size-1);
    return ret;
}

// takes items from ex_stack and adds a new operator expression to ex_stack
static int expr_add_operator(ExprParser *parser, ExprOpStackItem *op) {
    NSAPIExpression *exp = pool_malloc(parser->pool, sizeof(NSAPIExpression));
    exp->operator = op->operator;
    // op->expect_value == TRUE means, that the operator was found in a case
    // a value was expected.
    // For example: 1 + - 2
    // After + a value is expected, but there is the - operator
    // in that case, the - operator is a unary expression
    if(op->expect_value) {
        // We expected a value but got an operator? This must be an unary operator
        
        if(op->operator == NSAPI_EXPRESSION_ARG && !parser->expect_arg) {
            // simplify unary arg
            pool_free(parser->pool, exp);
            parser->expect_value = TRUE;
            parser->expect_arg = FALSE;
            return 0;
        }
        
        exp->type = NSAPI_EXPRESSION_UNARY;
        exp->left = expr_parser_pop(parser);
        exp->right = NULL; 
    } else if(exp->operator == NSAPI_EXPRESSION_CALL) {
        // identifiers are added as call, but if they land here, it is
        // actually just an identifier
        exp->operator = NSAPI_EXPRESSION_NOOP;
        exp->left = NULL;
        exp->right = NULL;
        exp->type = NSAPI_EXPRESSION_IDENTIFIER;
        exp->value.identifier = op->identifier;
    } else {
        // binary operator
        exp->type = NSAPI_EXPRESSION_BINARY;
        exp->right = expr_parser_pop(parser);
        exp->left = expr_parser_pop(parser);
    }
    
    if(!exp->left && !exp->right && exp->operator != NSAPI_EXPRESSION_NOOP) {
        return 1; // error
    }
    
    cxListAdd(parser->ex_stack, &exp);
    
    parser->expect_value = TRUE;
    parser->expect_arg = FALSE;
    return 0;
}

static int expr_add_func(ExprParser *parser, ExprOpStackItem *func) {
    NSAPIExpression *exp = pool_malloc(parser->pool, sizeof(NSAPIExpression));
    if(!exp) {
        return 1;
    }
    exp->type = NSAPI_EXPRESSION_IDENTIFIER;
    exp->operator = NSAPI_EXPRESSION_CALL;
    exp->left = NULL;
    exp->right = NULL;
    exp->value.str = func->identifier;
    
    if(parser->ex_stack->size > 0) {
        NSAPIExpression *top = *((NSAPIExpression**)cxListAt(parser->ex_stack, parser->ex_stack->size - 1));
        if(top && top->operator == NSAPI_EXPRESSION_ARG) {
            exp->left = top;
            cxListRemove(parser->ex_stack, parser->ex_stack->size - 1);
        }
    }
    
    if(cxListAdd(parser->ex_stack, &exp)) {
        return 1;
    }
    parser->expect_value = FALSE;
    return 0;
}

// converts the token to a value expression (int, bool, str, ...)
// and adds it to parser->ex_stack
// sets parser->expect_value to false
static int expr_add_value(ExprParser *parser, cxstring token) {
    NSAPIExpression *exp = pool_malloc(parser->pool, sizeof(NSAPIExpression));
    ZERO(exp, sizeof(NSAPIExpression));
    if(expr_set_value(parser->pool, exp, token)) {
        return 1;
    }
    
    cxListAdd(parser->ex_stack, &exp);
    if(parser->expect_arg) {
        ExprOpStackItem argList;
        argList.expect_value = TRUE;
        argList.identifier = (cxstring){NULL, 0};
        argList.open_parenthesis = FALSE;
        argList.operator = NSAPI_EXPRESSION_ARG;
        if(expr_add_operator(parser, &argList)) {
            return 1;
        }
    }
    
    parser->expect_value = FALSE;
    parser->expect_arg = FALSE;
    return 0;
}

static int token_is_identifier(cxstring token) {
    if(token.length == 0) {
        return 0;
    }
    
    if(!isalpha(token.ptr[0])) {
        return 0;
    }
    
    for(int i=1;i<token.length;i++) {
        if(!isalnum(token.ptr[i])) {
            return 0;
        }
    }
    
    if(!cx_strcmp(token, cx_str("true")) || !cx_strcmp(token, cx_str("false"))) {
        return 0;
    }
    
    return 1;
}


static NSAPIExpression* expr_parse_expr(ExprParser *parser) {
    CxList *op_stack = parser->op_stack;
    CxList *ex_stack = parser->ex_stack;
    
    // Shunting yard algorithm
    cxstring token = expr_next_token(parser->tokens, parser->pos);
    for(;token.ptr;token=expr_next_token(parser->tokens, parser->pos)) {
        NSAPIExpressionOperator op = expr_operator(token);
        if(op != NSAPI_EXPRESSION_NOOP) {
            ExprOpStackItem new_op;
            new_op.operator = op;
            new_op.identifier = (cxstring){NULL,0};
            new_op.expect_value = parser->expect_value;
            new_op.open_parenthesis = FALSE;
            while(op_stack->size > 0) {
                ExprOpStackItem *stack_item = cxListAt(op_stack, op_stack->size-1);
                if(stack_item->operator == NSAPI_EXPRESSION_NOOP) {
                    break;
                }
                // check presedence
                if(op >= stack_item->operator) {
                    break;
                }
                if(expr_add_operator(parser, stack_item)) {
                    return NULL;
                }
                cxListRemove(op_stack, op_stack->size-1);
            }
            cxListAdd(op_stack, &new_op);
            parser->expect_value = TRUE;
            parser->expect_arg = FALSE;
        } else if(token.length == 1 && token.ptr[0] == '(') {
            ExprOpStackItem *prev_op = NULL;
            if(op_stack->size > 0) {
                prev_op = cxListAt(op_stack, op_stack->size - 1);
            }
            
            if(prev_op && prev_op->operator == NSAPI_EXPRESSION_CALL) {
                // function call open parenthesis
                // we don't need to add a new op stack item, just mark function
                // call as open parenthesis
                prev_op->open_parenthesis = TRUE;
                parser->expect_arg = TRUE;
            } else {
                ExprOpStackItem new_op;
                new_op.operator = NSAPI_EXPRESSION_NOOP;
                new_op.identifier = (cxstring){NULL,0};
                new_op.expect_value = 0;
                new_op.open_parenthesis = TRUE;
                cxListAdd(op_stack, &new_op);
            }
            parser->expect_value = TRUE;
        } else if(token.length == 1 && token.ptr[0] == ')') {
            int found_open_bracket = FALSE;
            ExprOpStackItem stack_item;
            while(op_stack->size > 0) {
                ExprOpStackItem *stack_item_ptr = cxListAt(op_stack, op_stack->size-1);
                stack_item = *stack_item_ptr;
                cxListRemove(op_stack, op_stack->size-1);
                if(stack_item.open_parenthesis) {
                    found_open_bracket = TRUE;
                    break;
                } else {
                    if(expr_add_operator(parser, &stack_item)) {
                        return NULL;
                    }
                }
            }
            if(!found_open_bracket) {
                return NULL;
            }
            if(stack_item.operator == NSAPI_EXPRESSION_CALL) {
                if(expr_add_func(parser, &stack_item)) {
                    return NULL;
                }
            }
            parser->expect_value = FALSE;
            parser->expect_arg = FALSE;
        } else if(token_is_identifier(token)) {
            ExprOpStackItem new_op;
            new_op.operator = NSAPI_EXPRESSION_CALL;
            new_op.identifier = token;
            new_op.expect_value = 0;
            new_op.open_parenthesis = FALSE;
            cxListAdd(op_stack, &new_op);
            parser->expect_value = FALSE;
            parser->expect_arg = FALSE;
        } else {
            if(expr_add_value(parser, token)) {
                return NULL;
            }
        }
    }
    
    while(op_stack->size > 0) {
        ExprOpStackItem *stack_item = cxListAt(op_stack, op_stack->size-1);
        if(stack_item->open_parenthesis) {
            return NULL;
        }
        if(expr_add_operator(parser, stack_item)) {
            return NULL;
        }
        cxListRemove(op_stack, op_stack->size-1);
    }
    
    if(ex_stack->size != 1) {
        return NULL;
    }
    
    NSAPIExpression **ret = cxListAt(ex_stack, 0);
    return *ret;
}

NSAPIExpression* expr_parse_logical_expr(pool_handle_t *pool, CxList *tokens, size_t *pos) {  
    CxList *op_stack = cxArrayListCreate(pool_allocator(pool), NULL, sizeof(ExprOpStackItem), 32);
    CxList *ex_stack = cxArrayListCreate(pool_allocator(pool), NULL, sizeof(NSAPIExpression*), 32);
    
    ExprParser parser;
    parser.pool = pool;
    parser.op_stack = op_stack;
    parser.ex_stack = ex_stack;
    parser.tokens = tokens;
    parser.pos = pos;
    parser.expect_value = TRUE;
    parser.expect_arg = FALSE;
    
    NSAPIExpression *ret = expr_parse_expr(&parser);
    cxListDestroy(op_stack);
    cxListDestroy(ex_stack);
    
    return ret;
}



int condition_evaluate(Condition *condition, Session *sn, Request *rq) {
    return 1;
}

mercurial