From ff39991ed0a418f88a71cba20dc274402271d4f7 Mon Sep 17 00:00:00 2001 From: Thomas Porzelt Date: Fri, 5 Jun 2009 19:07:48 +0200 Subject: [PATCH] [core] Add support for regex conditionals --- include/lighttpd/actions.h | 7 +++++ include/lighttpd/condition.h | 7 +---- src/actions.c | 18 ++++++++++++- src/condition.c | 50 +++++++++++++++++++++--------------- 4 files changed, 54 insertions(+), 28 deletions(-) diff --git a/include/lighttpd/actions.h b/include/lighttpd/actions.h index 6aecb62..1022303 100644 --- a/include/lighttpd/actions.h +++ b/include/lighttpd/actions.h @@ -19,8 +19,15 @@ typedef enum { BACKEND_DEAD } backend_error; +struct action_regex_stack_element { + GString *string; + GMatchInfo *match_info; +}; +typedef struct action_regex_stack_element action_regex_stack_element; + struct action_stack { GArray* stack; + GArray* regex_stack; gboolean backend_failed; backend_error backend_error; }; diff --git a/include/lighttpd/condition.h b/include/lighttpd/condition.h index f5b1d8b..7f036bd 100644 --- a/include/lighttpd/condition.h +++ b/include/lighttpd/condition.h @@ -83,12 +83,7 @@ struct condition_rvalue { gboolean b; GString *string; -#ifdef HAVE_PCRE_H - struct { - pcre *regex; - pcre_extra *regex_study; - } pcre; -#endif + GRegex *regex; gint64 i; struct { guint32 addr; diff --git a/src/actions.c b/src/actions.c index 5ebd119..f86603b 100644 --- a/src/actions.c +++ b/src/actions.c @@ -119,7 +119,9 @@ action *action_new_balancer(BackendSelect bselect, BackendFallback bfallback, Ba static void action_stack_element_release(server *srv, vrequest *vr, action_stack_element *ase) { action *a = ase->act; + if (!ase || !a) return; + switch (a->type) { case ACTION_TSETTING: break; @@ -129,12 +131,23 @@ static void action_stack_element_release(server *srv, vrequest *vr, action_stack } break; case ACTION_TCONDITION: + if (a->data.condition.cond->rvalue.type == COND_VALUE_REGEXP) { + /* pop regex stack */ + GArray *rs = vr->action_stack.regex_stack; + action_regex_stack_element *arse = &g_array_index(rs, action_regex_stack_element, rs->len - 1); + if (arse->string) + g_string_free(arse->string, TRUE); + g_match_info_free(arse->match_info); + g_array_set_size(rs, rs->len - 1); + } + break; case ACTION_TLIST: break; case ACTION_TBALANCER: a->data.balancer.finished(vr, a->data.balancer.param, ase->data.context); break; } + action_release(srv, ase->act); ase->act = NULL; ase->data.context = NULL; @@ -142,6 +155,8 @@ static void action_stack_element_release(server *srv, vrequest *vr, action_stack void action_stack_init(action_stack *as) { as->stack = g_array_sized_new(FALSE, TRUE, sizeof(action_stack_element), 15); + as->regex_stack = g_array_sized_new(FALSE, FALSE, sizeof(action_regex_stack_element), 15); + g_array_set_size(as->regex_stack, 0); } void action_stack_reset(vrequest *vr, action_stack *as) { @@ -161,6 +176,7 @@ void action_stack_clear(vrequest *vr, action_stack *as) { action_stack_element_release(srv, vr, &g_array_index(as->stack, action_stack_element, i)); } g_array_free(as->stack, TRUE); + g_array_free(as->regex_stack, TRUE); as->stack = NULL; } @@ -262,7 +278,7 @@ handler_t action_execute(vrequest *vr) { res = condition_check(vr, a->data.condition.cond, &condres); switch (res) { case HANDLER_GO_ON: - action_stack_pop(srv, vr, as); + ase->finished = TRUE; if (condres) { if (a->data.condition.target) action_enter(vr, a->data.condition.target); } diff --git a/src/condition.c b/src/condition.c index 429631a..d9c5d6e 100644 --- a/src/condition.c +++ b/src/condition.c @@ -87,10 +87,24 @@ static condition* cond_new_string(comp_operator_t op, condition_lvalue *lvalue, #ifdef HAVE_PCRE_H /* only MATCH and NOMATCH */ static condition* cond_new_match(server *srv, comp_operator_t op, condition_lvalue *lvalue, GString *str) { - UNUSED(op); UNUSED(lvalue); UNUSED(str); - ERROR(srv, "%s", "pcre not supported for now"); - /* TODO: pcre */ - return NULL; + condition *c; + GRegex *regex; + GError *err = NULL; + + regex = g_regex_new(str->str, G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, &err); + + if (!regex || err) { + ERROR(srv, "failed to compile regex \"%s\": %s", str->str, err->message); + g_error_free(err); + return NULL; + } + + c = condition_new(op, lvalue); + c->rvalue.type = COND_VALUE_REGEXP; + c->rvalue.regex = regex; + + + return c; } #endif @@ -126,12 +140,7 @@ condition* condition_new_string(server *srv, comp_operator_t op, condition_lvalu return cond_new_string(op, lvalue, str); case CONFIG_COND_MATCH: case CONFIG_COND_NOMATCH: -#ifdef HAVE_PCRE_H return cond_new_match(srv, op, lvalue, str); -#else - ERROR(srv, "compiled without pcre, cannot use '%s'", comp_op_to_string(op)); - return NULL; -#endif case CONFIG_COND_IP: case CONFIG_COND_NOTIP: return cond_new_ip(srv, op, lvalue, str); @@ -189,11 +198,8 @@ static void condition_free(condition *c) { case COND_VALUE_STRING: g_string_free(c->rvalue.string, TRUE); break; -#ifdef HAVE_PCRE_H case COND_VALUE_REGEXP: - if (c->rvalue.pcre.regex) pcre_free(c->rvalue.pcre.regex); - if (c->rvalue.pcre.regex_study) pcre_free(c->rvalue.pcre.regex_study); -#endif + g_regex_unref(c->rvalue.regex); break; case COND_VALUE_SOCKET_IPV4: case COND_VALUE_SOCKET_IPV6: @@ -265,6 +271,7 @@ cond_lvalue_t cond_lvalue_from_string(const gchar *str, guint len) { if (g_str_has_prefix(c, "request.")) { c += sizeof("request.")-1; + len -= sizeof("request.")-1; if (strncmp(c, "localip", len) == 0) return COMP_REQUEST_LOCALIP; @@ -286,6 +293,7 @@ cond_lvalue_t cond_lvalue_from_string(const gchar *str, guint len) { return COMP_REQUEST_HEADER; } else if (strncmp(c, "physical.", sizeof("physical.")-1) == 0) { c += sizeof("physical.")-1; + len -= sizeof("physical.")-1; if (strncmp(c, "path", len) == 0) return COMP_PHYSICAL_PATH; @@ -343,6 +351,7 @@ static handler_t condition_check_eval_bool(vrequest *vr, condition *cond, gboole /* COND_VALUE_STRING and COND_VALUE_REGEXP only */ static handler_t condition_check_eval_string(vrequest *vr, condition *cond, gboolean *res) { + action_regex_stack_element arse; connection *con = vr->con; const char *val = ""; *res = FALSE; @@ -407,15 +416,14 @@ static handler_t condition_check_eval_string(vrequest *vr, condition *cond, gboo *res = !g_str_has_suffix(val, cond->rvalue.string->str); break; case CONFIG_COND_MATCH: + *res = g_regex_match(cond->rvalue.regex, val, 0, &arse.match_info); + arse.string = (*res) ? g_string_new(val) : NULL; + g_array_append_val(vr->action_stack.regex_stack, arse); + break; case CONFIG_COND_NOMATCH: -#ifdef HAVE_PCRE_H - /* TODO: pcre */ - VR_ERROR(vr, "%s", "regexp match not supported yet"); - return HANDLER_ERROR; -#else - VR_ERROR(vr, "compiled without pcre, cannot use '%s'", comp_op_to_string(cond->op)); - return HANDLER_ERROR; -#endif + *res = !g_regex_match(cond->rvalue.regex, val, 0, &arse.match_info); + arse.string = NULL; + g_array_append_val(vr->action_stack.regex_stack, arse); break; case CONFIG_COND_IP: case CONFIG_COND_NOTIP: