Fri, 16 Aug 2024 18:09:05 +0200
add test for sending multiple events to an eventhandler
/* * 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; }