src/server/util/object.c

Mon, 01 Jul 2013 18:05:13 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Mon, 01 Jul 2013 18:05:13 +0200
changeset 83
28433f06d5ee
parent 61
c858850f3d3a
child 91
fac51f87def0
permissions
-rw-r--r--

added minimal nsapi conditions

/*
 * 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 "../public/nsapi.h"

#include "object.h"

#include "pool.h"
#include "../daemon/func.h"
#include "../ucx/string.h"



httpd_object* object_new(pool_handle_t *pool, char *name) {
    // TODO: Speicherverwaltung
    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);
}


void object_add_directive(httpd_object *obj, directive *dir, int dt) {
    dtable *l = object_get_dtable(obj, dt);
    // allocate space for the new directive

    //l->dirs = realloc(l->dirs, (l->ndir+1)*sizeof(void*));
    // TODO: use realloc
    
    directive **drs = pool_malloc(obj->pool, (l->ndir+1)*sizeof(void*));
    for(int i=0;i<l->ndir;i++) {
        drs[i] = l->dirs[i];
    }
    if(l->dirs != NULL) {
        pool_free(obj->pool, l->dirs);
    }
    l->dirs = drs;

    // add directive
    l->dirs[l->ndir] = dir;
    l->ndir++;
}


/* 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;
}


Condition* condition_from_str(pool_handle_t *pool, char *expr, size_t len) {
    Condition *cond = pool_malloc(pool, sizeof(Condition));
    cond->expression = NULL;
    cond->parent = NULL;
    cond->index = 0;
    
    printf("Expression: {");
    fwrite(expr, len, 1, stdout);
    printf("}\n");
    
    cond->expression = expression_from_str(pool, expr, len);
    
    return cond;
}

Expression* expression_from_str(pool_handle_t *pool, char *expr, size_t len) {
    char str_qc = 0; // 0 or the quote char
    char c_brace = 0;
    int brace_count = 0; 
    
    Expression *expression = pool_malloc(pool, sizeof(Expression));
    ZERO(expression, sizeof(Expression));
    
    Expression *ex = expression;
    /*
     * 0: first operand
     * 1: second operand
     * 2: next expression
     */
    int optoken = 0;
    int token_start = 0; // index of token begin
    int i;
    for(i=0;i<=len;i++) {
        char c = i == len ? ' ' : expr[i];
        
        if(brace_count > 0) {
            if(c == c_brace) {
                char *token = expr + token_start;
                int token_len = i - token_start;
                printf("Token {");
                fwrite(token, token_len, 1, stdout);
                printf("}\n");
                
                
                
                // reset token_start
                token_start = -1;
            }
        } else {
            if((c == '(' || c == '[') && !str_qc) {
                brace_count++;
                if(brace_count == 1) {
                    if(c == '(') {
                        c_brace = ')'; 
                    } else {
                        c_brace = ']';
                    }
                    token_start = i+1;
                }
            } else if(c == str_qc) {
                str_qc = 0;
            } else if(c == '\'' || c == '\"') {
                if(token_start != -1) {
                    // error
                    printf("error: token_start != -1");
                    return NULL;
                }
                token_start = i;
                str_qc = c;
            } else if(c < 33 && token_start != -1 && !str_qc) {
                char *token = expr + token_start;
                int token_len = i - token_start;
                //printf("Token {");
                //fwrite(token, token_len, 1, stdout);
                //printf("}[%u]\n", token_len);
                
                int token_type = expr_token_type(token, token_len);
                switch(optoken) {
                    case 0: {
                        // first operand
                        if(token_type == 1) {
                            ex->optype[1] = EXPR_OP_NULL;
                            ex->opdata[1] = NULL;
                            ex->expr_operator = expr_operator(
                                    token,
                                    token_len);
                            break;
                        } else {
                            expr_set_op(pool, &ex->optype[0], &ex->opdata[0], token, token_len);
                        }
                        optoken++;
                        break;
                    }
                    case 1: {
                        // second operand
                        if(token_type == 1) {
                            Operator op = expr_operator(
                                    token,
                                    token_len);
                            if(op != OP_AND && op != OP_OR && op != OP_XOR) {
                                ex->expr_operator = op;
                                break;
                            } // else: jump to case 2
                        } else if(ex->expr_operator != 0) {
                            expr_set_op(pool, &ex->optype[1], &ex->opdata[1], token, token_len);
                            optoken++;
                            break;
                        } else {
                            // syntax error
                            fprintf(stderr, "expr: missing operator(1)\n");
                            return NULL;
                        }
                    }
                    case 2: {
                        // next
                        if(token_type == 1) {
                            ex->next_operator = expr_operator(
                                    token,
                                    token_len);
                            optoken = 0;
                            Expression *next_expr = pool_malloc(
                                    pool,
                                    sizeof(Expression));
                            ZERO(next_expr, sizeof(Expression));
                            ex->next = next_expr;
                            ex = next_expr;
                            break;
                        } else {
                            // syntax error
                            fprintf(stderr, "expr: missing operator(2)\n");
                            return NULL;
                        }
                    }
                }

                // reset token_start
                token_start = -1;
            } else if(c > 32 && token_start == -1) {
                token_start = i;
            }
        }
    }
    
    return expression;
}

Operator expr_operator(char *token, size_t len) {  
    if(!strncmp(token, "not", len) || !strncmp(token, "!", len)) {
        return OP_NOT;
    } else if(!strncmp(token, "and", len) || !strncmp(token, "&&", len)) {
        return OP_AND;
    } else if(!strncmp(token, "or", len) || !strncmp(token, "||", len)) {
        return OP_OR;
    } else if(!strncmp(token, "xor", len) || !strncmp(token, "^", len)) {
        return OP_XOR;
    } else if(!strncmp(token, "=", len)) {
        return OP_WILDCARD;
    } else if(!strncmp(token, "=~", len)) {
        return OP_REGEX;
    } else if(!strncmp(token, "!~", len)) {
        return OP_NREGEX;
    } else if(!strncmp(token, "+", len)) {
        return OP_ADD;
    } else if(!strncmp(token, "-", len)) {
        return OP_SUB;
    } else if(!strncmp(token, ".", len)) {
        return OP_CAT;
    } else if(!strncmp(token, "defined", len)) {
        return OP_DEF;
    } else if(!strncmp(token, "-d", len)) {
        return OP_DEXISTS;
    } else if(!strncmp(token, "-e", len)) {
        return OP_FDEXISTS;
    } else if(!strncmp(token, "-f", len)) {
        return OP_FEXISTS;
    } else if(!strncmp(token, "-l", len)) {
        return OP_LEXISTS;
    } else if(!strncmp(token, "-r", len)) {
        return OP_READABLE;
    } else if(!strncmp(token, "-s", len)) {
        return OP_FSIZE;
    } else if(!strncmp(token, "-U", len)) {
        return OP_UMAP;
    } else if(!strncmp(token, "<", len)) {
        return OP_LESS;
    } else if(!strncmp(token, "<=", len)) {
        return OP_LESSEQ;
    } else if(!strncmp(token, ">", len)) {
        return OP_GREATER;
    } else if(!strncmp(token, ">=", len)) {
        return OP_GREATEREQ;
    } else if(!strncmp(token, "lt", len)) {
        return OP_STRLESS;
    } else if(!strncmp(token, "le", len)) {
        return OP_STRLESSEQ;
    } else if(!strncmp(token, "gt", len)) {
        return OP_GREATER;
    } else if(!strncmp(token, "ge", len)) {
        return OP_STRGREATEREQ;
    } else if(!strncmp(token, "==", len)) {
        return OP_EQUAL;
    } else if(!strncmp(token, "!=", len)) {
        return OP_NOTEQUAL;
    } else if(!strncmp(token, "eq", len)) {
        return OP_STREQUAL;
    } else if(!strncmp(token, "ne", len)) {
        return OP_STRNOTEQUAL;
    }
    return OP_NOOP;
}

int expr_token_type(char *token, size_t len) {
    char c = token[0];
    if(c == '$' || c == '"' || c == '\'') {
        return 0;
    } else {
        if(expr_operator(token, len) == OP_NOOP) {
            return 0;
        } else {
            return 1;
        }
    }
}

void expr_set_op(pool_handle_t *pool, OperandType *type, void **val, char *token, size_t len) {
    char c = token[0];
    if(c == '$') {
        *type = EXPR_OP_VAR;
        sstr_t s = sstrn(token+1, len-1);
        s = sstrdup_pool(pool, s);
        *val = s.ptr;
    } else if(c == '"' || c == '\'') {
        *type = EXPR_OP_STRING;
        sstr_t s = sstrn(token+1, len-2);
        s = sstrdup_pool(pool, s);
        *val = s.ptr;
    }
}


int condition_evaluate(Condition *condition, Session *sn, Request *rq) {
    return expression_evaluate(condition->expression, sn, rq);
}

int expression_evaluate(Expression *ex, Session *sn, Request *rq) {
    int ret = 0;
    
    int last_eval = 0;
    Operator expr_lconn = OP_NOOP; // logical connective between 2 expressions
    while(ex) {
        int eval = 0;
        
        if(!ex->opdata[1]) {
            /*
             * Only one operand. Can be:
             *   boolean with or without not operator
             *   defined operator
             *   file/directory/link exists operator
             */
            int not_op = 0;
            switch(ex->expr_operator) {
                case OP_NOT: {
                    not_op = 1;
                }
                case OP_NOOP: {
                    // must be boolean
                    // TODO
                }
            }
            
        } else {
            void *ops[2];
            VarType types[2];
            for(int i=0;i<2;i++) {
                switch(ex->optype[i]) {
                    case EXPR_OP_STRING: {
                        ops[i] = ex->opdata[i];
                        types[i] = VAR_STRING;
                        break;
                    }
                    case EXPR_OP_VAR: {
                        if(!expr_get_var(ex->opdata[i], sn, rq, &ops[i], &types[i]));
                        break;
                    }
                }
            }
            
            if(types[0] != types[1]) {
                fprintf(stderr, "Condition: incompatible types\n");
                return 0;
            }
            
            if(types[0] == VAR_STRING) {
                switch(ex->expr_operator) {
                    case OP_WILDCARD: {
                        eval = !shexp_match(ops[0], ops[1]);
                        break;
                    }
                    case OP_STREQUAL: {
                        eval = !strcmp(ops[0], ops[1]);
                        break;
                    }
                }
            }
        }
        
        
        // evaluate logical connective between last 2 expressions
        switch(expr_lconn) {
            case OP_AND: {
                if(!last_eval || !eval) {
                    return 0;
                }
                break;
            }
            case OP_OR: {
                if(!last_eval && !eval) {
                    return 0;
                }
            }
            case OP_XOR: {
                if(last_eval == eval) {
                    return 0;
                }
            }
        }
        
        last_eval = eval;
        // switch to next expression
        if(ex->next) {
            expr_lconn = ex->next_operator;
        }
        ex = ex->next;
    }
    
    return last_eval;
}

int expr_get_var(char *var, Session *sn, Request *rq, void **val, VarType *t) {
    if(!strcmp(var, "path")) {
        char *ppath = pblock_findval("ppath", rq->vars);
        if(ppath) {
            *t = VAR_STRING;
            *val = ppath;
            return 1;
        }
    } else if(!strcmp(var, "uri")) {
        char *uri = pblock_findval("uri", rq->reqpb);
        if(uri) {
            *t = VAR_STRING;
            *val = uri;
            return 1;
        }
    }
    
    *val = NULL;
    *t = 0;
    return 0;
}

mercurial