added "if" to condition syntax (if req.path == "/foo" {})

added boolean conditions without operator or rvalue (if phys.is_dir {}, rvalue is always true)
added negated boolean conditions (if !phys.is_dir {}, rvalue is always false)
added physical.is_dir and .is_file conditionals
personal/stbuehler/wip
Thomas Porzelt 14 years ago
parent 01068d7f1d
commit 85a3a4d091
  1. 5
      include/lighttpd/condition.h
  2. 4
      include/lighttpd/config_parser.h
  3. 65
      src/condition.c
  4. 57
      src/config_parser.rl

@ -48,6 +48,8 @@ typedef enum {
COMP_PHYSICAL_PATH,
COMP_PHYSICAL_PATH_EXISTS,
COMP_PHYSICAL_SIZE,
COMP_PHYSICAL_ISDIR,
COMP_PHYSICAL_ISFILE,
/* needs a key */
COMP_REQUEST_HEADER /**< needs lowercase key, enforced by condition_lvalue_new */
@ -64,6 +66,7 @@ struct condition_lvalue {
};
typedef enum {
COND_VALUE_BOOL,
COND_VALUE_NUMBER,
COND_VALUE_STRING,
#ifdef HAVE_PCRE_H
@ -76,6 +79,7 @@ typedef enum {
struct condition_rvalue {
cond_rvalue_t type;
gboolean b;
GString *string;
#ifdef HAVE_PCRE_H
struct {
@ -109,6 +113,7 @@ LI_API condition_lvalue* condition_lvalue_new(cond_lvalue_t type, GString *key);
LI_API void condition_lvalue_acquire(condition_lvalue *lvalue);
LI_API void condition_lvalue_release(condition_lvalue *lvalue);
LI_API condition* condition_new_bool(server *srv, condition_lvalue *lvalue, gboolean b);
LI_API condition* condition_new_string(server *srv, comp_operator_t op, condition_lvalue *lvalue, GString *str);
LI_API condition* condition_new_int(server *srv, comp_operator_t op, condition_lvalue *lvalue, gint64 i);

@ -37,7 +37,11 @@ struct config_parser_context_t {
gchar *mark;
gboolean in_setup_block;
gboolean condition_with_key;
gboolean condition_nonbool;
gboolean condition_negated;
comp_operator_t op;
gchar value_op;

@ -106,6 +106,15 @@ static condition* cond_new_ip(server *srv, comp_operator_t op, condition_lvalue
return c;
}
condition* condition_new_bool(server *srv, condition_lvalue *lvalue, gboolean b) {
condition *c;
UNUSED(srv);
c = condition_new(CONFIG_COND_EQ, lvalue);
c->rvalue.type = COND_VALUE_BOOL;
c->rvalue.b = b;
return c;
}
condition* condition_new_string(server *srv, comp_operator_t op, condition_lvalue *lvalue, GString *str) {
switch (op) {
case CONFIG_COND_EQ:
@ -173,6 +182,7 @@ condition* condition_new_int(server *srv, comp_operator_t op, condition_lvalue *
static void condition_free(condition *c) {
condition_lvalue_release(c->lvalue);
switch (c->rvalue.type) {
case COND_VALUE_BOOL:
case COND_VALUE_NUMBER:
/* nothing to free */
break;
@ -241,12 +251,53 @@ const char* cond_lvalue_to_string(cond_lvalue_t t) {
case COMP_PHYSICAL_PATH: return "physical.path";
case COMP_PHYSICAL_PATH_EXISTS: return "physical.pathexist";
case COMP_PHYSICAL_SIZE: return "physical.size";
case COMP_PHYSICAL_ISDIR: return "physical.is_dir";
case COMP_PHYSICAL_ISFILE: return "physical.is_file";
case COMP_REQUEST_HEADER: return "request.header";
}
return "<unknown>";
}
static handler_t condition_check_eval_bool(vrequest *vr, condition *cond, gboolean *res) {
*res = FALSE;
if (cond->lvalue->type == COMP_PHYSICAL_ISDIR ||
cond->lvalue->type == COMP_PHYSICAL_ISFILE) {
if (!vr->physical.have_stat) {
if (!vrequest_stat(vr)) {
switch (errno) {
case EACCES: vr->response.http_status = 403; break;
case EBADF: vr->response.http_status = 500; break;
case EFAULT: vr->response.http_status = 500; break;
case ELOOP: vr->response.http_status = 500; break;
case ENAMETOOLONG: vr->response.http_status = 500; break;
case ENOENT: vr->response.http_status = 404; break;
case ENOMEM: vr->response.http_status = 500; break;
case ENOTDIR: vr->response.http_status = 404; break;
default: vr->response.http_status = 500;
}
vrequest_handle_direct(vr);
return HANDLER_GO_ON;
}
}
}
switch (cond->lvalue->type) {
case COMP_PHYSICAL_ISDIR:
*res = S_ISDIR(vr->physical.stat.st_mode);
break;
case COMP_PHYSICAL_ISFILE:
*res = S_ISREG(vr->physical.stat.st_mode);
break;
default:
VR_ERROR(vr, "invalid lvalue \"%s\" for boolean comparison", cond_lvalue_to_string(cond->lvalue->type));
return HANDLER_ERROR;
}
return HANDLER_GO_ON;
}
/* COND_VALUE_STRING and COND_VALUE_REGEXP only */
static handler_t condition_check_eval_string(vrequest *vr, condition *cond, gboolean *res) {
connection *con = vr->con;
@ -285,15 +336,12 @@ static handler_t condition_check_eval_string(vrequest *vr, condition *cond, gboo
http_header_get_fast(con->wrk->tmp_str, vr->request.headers, GSTR_LEN(cond->lvalue->key));
val = con->wrk->tmp_str->str;
break;
case COMP_PHYSICAL_SIZE:
/* TODO: physical size */
g_string_printf(con->wrk->tmp_str, "%"L_GOFFSET_FORMAT, (goffset) 0);
val = con->wrk->tmp_str->str;
break;
case COMP_REQUEST_CONTENT_LENGTH:
g_string_printf(con->wrk->tmp_str, "%"L_GOFFSET_FORMAT, vr->request.content_length);
val = con->wrk->tmp_str->str;
break;
default:
return HANDLER_ERROR;
}
switch (cond->op) {
@ -494,7 +542,10 @@ static handler_t condition_check_eval_ip(vrequest *vr, condition *cond, gboolean
case COMP_REQUEST_CONTENT_LENGTH:
VR_ERROR(vr, "%s", "Cannot parse integers as ip");
return HANDLER_ERROR;
break;
case COMP_PHYSICAL_ISDIR:
case COMP_PHYSICAL_ISFILE:
VR_ERROR(vr, "%s", "phys.is_dir and phys.is_file are boolean conditionals");
return HANDLER_ERROR;
}
if (ipval.type == COND_VALUE_NUMBER) {
@ -528,6 +579,8 @@ static handler_t condition_check_eval_ip(vrequest *vr, condition *cond, gboolean
handler_t condition_check(vrequest *vr, condition *cond, gboolean *res) {
switch (cond->rvalue.type) {
case COND_VALUE_BOOL:
return condition_check_eval_bool(vr, cond, res);
case COND_VALUE_STRING:
#ifdef HAVE_PCRE_H
case COND_VALUE_REGEXP:

@ -696,16 +696,23 @@
condition *cond;
condition_lvalue *lvalue;
v = g_queue_pop_head(ctx->option_stack);
if (ctx->condition_with_key)
k = g_queue_pop_head(ctx->option_stack);
else
/* if condition is nonbool, then it has a value and maybe a key too on the stack */
if (ctx->condition_nonbool) {
v = g_queue_pop_head(ctx->option_stack);
if (ctx->condition_with_key)
k = g_queue_pop_head(ctx->option_stack);
else
k = NULL;
} else {
v = NULL;
k = NULL;
}
n = g_queue_pop_head(ctx->option_stack);
assert(n->type == VALUE_STRING);
_printf("got condition: %s:%s %s %s in line %zd\n", n->data.string->str, ctx->condition_with_key ? k->data.string->str : "", comp_op_to_string(ctx->op), value_type_string(v->type), ctx->line);
/*_printf("got condition: %s:%s %s %s in line %zd\n", n->data.string->str, ctx->condition_with_key ? k->data.string->str : "", comp_op_to_string(ctx->op), value_type_string(v->type), ctx->line);*/
/* create condition lvalue */
str = n->data.string->str;
@ -760,6 +767,10 @@
lvalue = condition_lvalue_new(COMP_PHYSICAL_PATH_EXISTS, NULL);
else if (g_str_equal(str, "size"))
lvalue = condition_lvalue_new(COMP_PHYSICAL_SIZE, NULL);
else if (g_str_equal(str, "is_dir"))
lvalue = condition_lvalue_new(COMP_PHYSICAL_ISDIR, NULL);
else if (g_str_equal(str, "is_file"))
lvalue = condition_lvalue_new(COMP_PHYSICAL_ISFILE, NULL);
else {
WARNING(srv, "unkown lvalue for condition: %s", n->data.string->str);
return FALSE;
@ -770,16 +781,20 @@
return FALSE;
}
if (v->type == VALUE_STRING) {
cond = condition_new_string(srv, ctx->op, lvalue, value_extract(v).string);
}
else if (v->type == VALUE_NUMBER)
cond = condition_new_int(srv, ctx->op, lvalue, value_extract_number(v));
else {
cond = NULL;
if (ctx->condition_nonbool) {
if (v->type == VALUE_STRING) {
cond = condition_new_string(srv, ctx->op, lvalue, value_extract(v).string);
}
else if (v->type == VALUE_NUMBER)
cond = condition_new_int(srv, ctx->op, lvalue, value_extract_number(v));
else {
cond = NULL;
}
} else {
/* boolean condition */
cond = condition_new_bool(srv, lvalue, !ctx->condition_negated);
}
if (cond == NULL) {
WARNING(srv, "%s", "could not create condition");
return FALSE;
@ -789,11 +804,15 @@
g_queue_push_head(ctx->action_list_stack, action_new_list());
/* TODO: free stuff */
value_free(n);
value_free(k);
value_free(v);
if (ctx->condition_nonbool) {
value_free(k);
value_free(v);
}
ctx->condition_with_key = FALSE;
ctx->condition_nonbool = FALSE;
ctx->condition_negated = FALSE;
}
action condition_end {
@ -970,8 +989,10 @@
# casts
cast = ( 'cast(' ( 'int' %{ctx->cast = CFG_PARSER_CAST_INT;} | 'str' %{ctx->cast = CFG_PARSER_CAST_STR;} ) ')' ws* );
keywords = ( 'true' | 'false' | 'if' | 'else' );
# advanced types
varname = ( '__' ? (alpha ( alnum | [._] )*) - (boolean | 'else') ) >mark %varname;
varname = ( '__' ? (alpha ( alnum | [._] )*) - keywords ) >mark %varname;
actionref = ( varname ) %actionref;
list = ( '(' >list_start );
hash = ( '[' >hash_start );
@ -992,7 +1013,7 @@
function_param = ( varname ws+ value_statement ';') %function_param;
function = ( function_noparam | function_param );
condition = ( varname ('[' string >mark ']' %condition_key)? ws* operator ws* value_statement noise* block >condition_start ) %condition_end;
condition = ( 'if' noise+ ('!' %{ctx->condition_negated = TRUE;})? varname ('[' string >mark ']' %condition_key)? ws* (operator ws* value_statement %{ctx->condition_nonbool = TRUE;})? noise* block >condition_start ) %condition_end;
else_cond = ( 'else' noise+ condition ) %else_cond_end;
else_nocond = ( 'else' noise+ block >else_nocond_start ) %else_nocond_end;
condition_else = ( condition noise* (else_cond| noise)* else_nocond? );

Loading…
Cancel
Save