2
0
Fork 0

[core] Add support for regex conditionals

personal/stbuehler/wip
Thomas Porzelt 2009-06-05 19:07:48 +02:00
parent d984853790
commit ff39991ed0
4 changed files with 54 additions and 28 deletions

View File

@ -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;
};

View File

@ -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;

View File

@ -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);
}

View File

@ -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: