added minimal nsapi conditions

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 82
740cfd9dd443
child 84
afd57ce39ec9

added minimal nsapi conditions

src/server/config/conf.c file | annotate | diff | comparison | revisions
src/server/config/conf.h file | annotate | diff | comparison | revisions
src/server/config/objconf.c file | annotate | diff | comparison | revisions
src/server/config/objconf.h file | annotate | diff | comparison | revisions
src/server/daemon/config.c file | annotate | diff | comparison | revisions
src/server/daemon/httprequest.c file | annotate | diff | comparison | revisions
src/server/util/object.c file | annotate | diff | comparison | revisions
src/server/util/object.h file | annotate | diff | comparison | revisions
--- a/src/server/config/conf.c	Sun Jun 30 15:11:48 2013 +0200
+++ b/src/server/config/conf.c	Mon Jul 01 18:05:13 2013 +0200
@@ -509,15 +509,16 @@
     param_str.ptr = line.ptr + i;
     param_str.length = line.length - name.length - 2;
     param_str = sstrtrim(param_str);
-    if(param_str.length <= 0) {
+    if(param_str.length == 0) {
         return tag; // no parameters
     }
+    tag->param_str = sstrdup_mp(mp, param_str);
 
     sstr_t pname;
     sstr_t pvalue;
     for(;;) {
         param_str = cfg_param(param_str, &pname, &pvalue);
-        if(pname.length <= 0) {
+        if(pname.length == 0) {
             break;
         }
 
@@ -532,12 +533,7 @@
         }
 
         // add param to list
-        if(tag->param) {
-            tag->param = ucx_list_append(tag->param, param);
-        } else {
-            tag->param = ucx_list_append(tag->param, param);
-            cfg_list_destr(mp, tag->param);
-        }
+        tag->param = cfg_list_append(mp, tag->param, param);
     }
 
     return tag;
--- a/src/server/config/conf.h	Sun Jun 30 15:11:48 2013 +0200
+++ b/src/server/config/conf.h	Mon Jul 01 18:05:13 2013 +0200
@@ -89,6 +89,7 @@
 
     sstr_t     name;
     UcxList    *param;
+    sstr_t     param_str;
     ConfigTag  *parent;
     ConfigTag  *iftag; // only used by <ElseIf> and <Else>
     int        type_num;
--- a/src/server/config/objconf.c	Sun Jun 30 15:11:48 2013 +0200
+++ b/src/server/config/objconf.c	Mon Jul 01 18:05:13 2013 +0200
@@ -133,7 +133,7 @@
 
     switch(tag->type_num) {
         case TAG_OBJECT: {
-            ConfigObject *obj = OBJ_NEW_N(conf->parser.mp, ConfigObject);
+            ConfigObject *obj = OBJ_NEW_N(mp, ConfigObject);
             obj->begin = tag->begin;
             obj->end = tag->end;
             
@@ -144,7 +144,7 @@
             conf->objects = cfg_dlist_append(mp, conf->objects, obj);
 
             // create tree level object
-            ConfigParserLevel *lvl = OBJ_NEW(conf->parser.mp, ConfigParserLevel);
+            ConfigParserLevel *lvl = OBJ_NEW(mp, ConfigParserLevel);
             lvl->iftag = NULL;
             lvl->levelnum = 1;
             lvl->tag = tag;
@@ -156,9 +156,7 @@
             // create tree level object
             ConfigParserLevel *last_lvl = conf->levels->data;
 
-            ConfigParserLevel *lvl = OBJ_NEW(
-                    conf->parser.mp,
-                    ConfigParserLevel);
+            ConfigParserLevel *lvl = OBJ_NEW(mp, ConfigParserLevel);
             
             lvl->iftag = NULL;
             lvl->levelnum = last_lvl->levelnum + 1;
--- a/src/server/config/objconf.h	Sun Jun 30 15:11:48 2013 +0200
+++ b/src/server/config/objconf.h	Mon Jul 01 18:05:13 2013 +0200
@@ -61,8 +61,9 @@
     UcxDlist     *conditions;
     UcxDlist     *objects;
 
-    // private parser temp vars
+    // private parser temp var
     ConfigObject *obj;     // add directives to this object
+    // private parser temp var
     UcxList      *levels;  // tree levels (stack)
     
 } ObjectConfig;
--- a/src/server/daemon/config.c	Sun Jun 30 15:11:48 2013 +0200
+++ b/src/server/daemon/config.c	Mon Jul 01 18:05:13 2013 +0200
@@ -706,7 +706,7 @@
 
     // add objects
     conf->nobj = ucx_dlist_size(cfg->objects);
-    conf->objects = pool_calloc(pool, 1, sizeof(httpd_object*));
+    conf->objects = pool_calloc(pool, conf->nobj, sizeof(httpd_object*));
     
     UcxDlist *objlist = cfg->objects;
     int i = 0;
@@ -727,16 +727,21 @@
         httpd_object *obj = object_new(pool, name);
         obj->path = NULL;
 
-        conf->objects[i] = obj; // TODO: beyond array bounds write
+        conf->objects[i] = obj;
 
         // add directives
         for(int i=0;i<6;i++) {
             UcxDlist *dirs = cob->directives[i];
             while(dirs != NULL) {
                 ConfigDirective *cfgdir = dirs->data;
-
+                
                 directive *d = pool_malloc(pool, sizeof(directive));
-                d->cond = NULL;
+                if(cfgdir->condition) {
+                    sstr_t expr = cfgdir->condition->param_str;
+                    d->cond = condition_from_str(pool, expr.ptr, expr.length);
+                } else {
+                    d->cond = NULL;
+                }
                 d->param = pblock_create_pool(pool, 8);
 
                 // add params
--- a/src/server/daemon/httprequest.c	Sun Jun 30 15:11:48 2013 +0200
+++ b/src/server/daemon/httprequest.c	Mon Jul 01 18:05:13 2013 +0200
@@ -753,6 +753,11 @@
 
 int nsapi_exec(directive *d, NSAPISession *sn, NSAPIRequest *rq) {
     // TODO: condition
+    if(d->cond) {
+        if(!condition_evaluate(d->cond, (Session*)sn, (Request*)rq)) {
+            return REQ_NOACTION;
+        }
+    }
     
     char *poolname = pblock_findkeyval(pb_key_pool, d->param);
     if(poolname) {
--- a/src/server/util/object.c	Sun Jun 30 15:11:48 2013 +0200
+++ b/src/server/util/object.c	Mon Jul 01 18:05:13 2013 +0200
@@ -32,6 +32,7 @@
 
 #include "pool.h"
 #include "../daemon/func.h"
+#include "../ucx/string.h"
 
 
 
@@ -107,3 +108,365 @@
     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;
+}
+
--- a/src/server/util/object.h	Sun Jun 30 15:11:48 2013 +0200
+++ b/src/server/util/object.h	Mon Jul 01 18:05:13 2013 +0200
@@ -51,6 +51,10 @@
 
 typedef struct Condition          Condition;
 typedef int8_t                    ConditionResult;
+typedef struct Expression         Expression;
+typedef enum OperandType          OperandType;
+typedef enum Operator             Operator;
+typedef enum VarType              VarType;
 
 typedef struct NSAPIContext       NSAPIContext;
 typedef struct HTTPObjectConfig   HTTPObjectConfig;
@@ -81,8 +85,71 @@
 
 struct Condition {
     Condition  *parent;
-    int        expression;
-    int        index; /* used by NSAPIContext to link expression with result */
+    Expression *expression;
+    int        index; // used by NSAPIContext to link expression with result
+};
+
+enum OperandType {
+    EXPR_OP_NULL = 0,   // no operand
+    EXPR_OP_STRING,     // string literal
+    EXPR_OP_INTEGER,    // integer literal
+    EXPR_OP_VAR,        // variable
+    EXPR_OP_FUNC,       // function,
+    EXPR_OP_EXPRESSION  // operand is an expression
+};
+
+enum Operator {
+    OP_NOOP = 0,
+    OP_NOT,          // not, !
+    OP_AND,          // and, &&
+    OP_OR,           // or, ||
+    OP_XOR,          // xor, ^
+    OP_WILDCARD,     // =
+    OP_REGEX,        // =~
+    OP_NREGEX,       // !~
+    OP_ADD,          // +
+    OP_SUB,          // -
+    OP_CAT,          // .
+    OP_DEF,          // defined
+    OP_DEXISTS,      // -d
+    OP_FDEXISTS,     // -e
+    OP_FEXISTS,      // -f
+    OP_LEXISTS,      // -l
+    OP_READABLE,     // -r
+    OP_FSIZE,        // -s
+    OP_UMAP,         // -U
+    OP_LESS,         // <
+    OP_LESSEQ,       // <=
+    OP_GREATER,      // >
+    OP_GREATEREQ,    // >=
+    OP_STRLESS,      // lt
+    OP_STRLESSEQ,    // le
+    OP_STRGREATER,   // gt
+    OP_STRGREATEREQ, // ge
+    OP_EQUAL,        // ==
+    OP_NOTEQUAL,     // !=
+    OP_STREQUAL,     // eq
+    OP_STRNOTEQUAL,  // ne
+};
+
+enum VarType {
+    VAR_NULL = 0,
+    VAR_STRING,
+    VAR_INTEGER,
+    VAR_BOOL
+};
+
+struct Expression {
+    // type of the operands
+    OperandType optype[2];
+    // operand data
+    void *opdata[2];
+    // operator
+    Operator expr_operator;
+    // logical connective to next expression
+    Operator next_operator;
+    // next expression
+    Expression *next;
 };
 
 
@@ -91,6 +158,7 @@
 
     ConditionResult   **results;
     int               nres;
+    int               nmaxres;
 
     //httpd_objset      *objset;
     int last_req_code;
@@ -156,6 +224,24 @@
  */
 void nsapi_context_next_stage(NSAPIContext *context);
 
+Condition* condition_from_str(pool_handle_t *pool, char *expr, size_t len);
+Expression* expression_from_str(pool_handle_t *pool, char *expr, size_t len);
+Operator expr_operator(char *token, size_t len);
+
+/*
+ * get the type of the token
+ * 
+ * returns
+ *   0: operand
+ *   1: operator
+ */
+int expr_token_type(char *token, size_t len);
+void expr_set_op(pool_handle_t *pool, OperandType *type, void **val, char *token, size_t len);
+
+
+int condition_evaluate(Condition *condition, Session *sn, Request *rq);
+int expression_evaluate(Expression *ex, Session *sn, Request *rq);
+int expr_get_var(char *var, Session *sn, Request *rq, void **val, VarType *t);
 
 #ifdef	__cplusplus
 }

mercurial