# HG changeset patch # User Olaf Wintermann # Date 1372694713 -7200 # Node ID 28433f06d5ee0aaeac61c56eb64213734e8b2bf6 # Parent 740cfd9dd44358f0308fda92af4e3257a657139a added minimal nsapi conditions diff -r 740cfd9dd443 -r 28433f06d5ee src/server/config/conf.c --- 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; diff -r 740cfd9dd443 -r 28433f06d5ee src/server/config/conf.h --- 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 and int type_num; diff -r 740cfd9dd443 -r 28433f06d5ee src/server/config/objconf.c --- 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; diff -r 740cfd9dd443 -r 28433f06d5ee src/server/config/objconf.h --- 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; diff -r 740cfd9dd443 -r 28433f06d5ee src/server/daemon/config.c --- 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 diff -r 740cfd9dd443 -r 28433f06d5ee src/server/daemon/httprequest.c --- 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) { diff -r 740cfd9dd443 -r 28433f06d5ee src/server/util/object.c --- 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; +} + diff -r 740cfd9dd443 -r 28433f06d5ee src/server/util/object.h --- 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 }