[MAJOR] merged the 'setbe' actions to switch the backend on a regex
Sin Yu's patch to permit to change the proxy from a regex was merged with little changes : - req_cap/rsp_cap are not reassigned to the new proxy, they stay attached to the frontend - the actions have been renamed "reqsetbe" and "reqisetbe" for "set BackEnd". - the buffer is not reset after the switch, instead, the headers are parsed again by the backend - in Sin's patch, it was theorically possible to switch multiple times, but the switching track was lost, making it impossible to apply server responsesin the reverse order. Now switching is limited to 1 action (separation between frontend and backend) but the filters remain. Now it will be extremely easy to add other switching conditions, such as host matching, URI matching, etc... There's still a hard work to be done on the logs and stats.
This commit is contained in:
parent
ddb358d932
commit
a496b6042b
|
@ -38,6 +38,7 @@
|
|||
#define ACT_DENY 3 /* deny the request */
|
||||
#define ACT_PASS 4 /* pass this header without allowing or denying the request */
|
||||
#define ACT_TARPIT 5 /* tarpit the connection matching this request */
|
||||
#define ACT_SETBE 6 /* switch the backend */
|
||||
|
||||
struct hdr_exp {
|
||||
struct hdr_exp *next;
|
||||
|
|
|
@ -1416,6 +1416,46 @@ int cfg_parse_listen(const char *file, int linenum, char **args)
|
|||
|
||||
chain_regex(&curproxy->req_exp, preg, ACT_TARPIT, NULL);
|
||||
}
|
||||
else if (!strcmp(args[0], "reqsetbe")) { /* switch the backend from a regex, respecting case */
|
||||
regex_t *preg;
|
||||
if(curproxy == &defproxy) {
|
||||
Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(*(args[1]) == 0 || *(args[2]) == 0) {
|
||||
Alert("parsing [%s:%d] : '%s' expects <search> and <target> as arguments.\n",
|
||||
file, linenum, args[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
preg = calloc(1, sizeof(regex_t));
|
||||
if(regcomp(preg, args[1], REG_EXTENDED) != 0) {
|
||||
Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
|
||||
}
|
||||
|
||||
chain_regex(&curproxy->req_exp, preg, ACT_SETBE, strdup(args[2]));
|
||||
}
|
||||
else if (!strcmp(args[0], "reqisetbe")) { /* switch the backend from a regex, ignoring case */
|
||||
regex_t *preg;
|
||||
if(curproxy == &defproxy) {
|
||||
Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(*(args[1]) == 0 || *(args[2]) == 0) {
|
||||
Alert("parsing [%s:%d] : '%s' expects <search> and <target> as arguments.\n",
|
||||
file, linenum, args[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
preg = calloc(1, sizeof(regex_t));
|
||||
if(regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
|
||||
Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
|
||||
}
|
||||
|
||||
chain_regex(&curproxy->req_exp, preg, ACT_SETBE, strdup(args[2]));
|
||||
}
|
||||
else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
|
||||
regex_t *preg;
|
||||
if (curproxy == &defproxy) {
|
||||
|
@ -1945,8 +1985,6 @@ int readcfgfile(const char *file)
|
|||
Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
|
@ -2030,6 +2068,30 @@ int readcfgfile(const char *file)
|
|||
}
|
||||
}
|
||||
|
||||
if (curproxy->mode == PR_MODE_HTTP && curproxy->req_exp != NULL) {
|
||||
/* map jump target for ACT_SETBE in req_rep chain */
|
||||
struct hdr_exp *exp;
|
||||
struct proxy *target;
|
||||
for (exp = curproxy->req_exp; exp != NULL; exp = exp->next) {
|
||||
if (exp->action != ACT_SETBE)
|
||||
continue;
|
||||
for (target = proxy; target != NULL; target = target->next) {
|
||||
if (strcmp(target->id, exp->replace) == 0)
|
||||
break;
|
||||
}
|
||||
if (target == NULL) {
|
||||
Alert("parsing %s : backend '%s' in HTTP proxy %s was not found !\n",
|
||||
file, exp->replace, curproxy->id);
|
||||
cfgerr++;
|
||||
} else if (target == curproxy) {
|
||||
Alert("parsing %s : loop detected for backend %s !\n", file, exp->replace);
|
||||
cfgerr++;
|
||||
} else {
|
||||
free((void *)exp->replace);
|
||||
exp->replace = (const char *)target;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HTTP) &&
|
||||
(!curproxy->clitimeout || !curproxy->contimeout || !curproxy->srvtimeout)) {
|
||||
Warning("parsing %s : missing timeouts for listener '%s'.\n"
|
||||
|
|
|
@ -3041,6 +3041,36 @@ void apply_filters_to_session(struct session *t, struct buffer *req, struct hdr_
|
|||
|
||||
if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
|
||||
switch (exp->action) {
|
||||
case ACT_SETBE:
|
||||
/* It is not possible to jump a second time.
|
||||
* FIXME: should we return an HTTP/500 here so that
|
||||
* the admin knows there's a problem ?
|
||||
*/
|
||||
if (t->be != t->fe)
|
||||
break;
|
||||
|
||||
if (!(t->flags & (SN_CLDENY | SN_CLTARPIT))) {
|
||||
struct proxy *target = (struct proxy *) exp->replace;
|
||||
|
||||
/* Swithing Proxy */
|
||||
*cur_end = term;
|
||||
cur_end = NULL;
|
||||
|
||||
/* right now, the backend switch is not too much complicated
|
||||
* because we have associated req_cap and rsp_cap to the
|
||||
* frontend, and the beconn will be updated later.
|
||||
*/
|
||||
|
||||
t->rep->rto = t->req->wto = target->beprm->srvtimeout;
|
||||
t->req->cto = target->beprm->contimeout;
|
||||
|
||||
t->be = target;
|
||||
|
||||
//t->logs.logwait |= LW_REQ | (target->to_log & (LW_REQHDR | LW_COOKIE));
|
||||
t->logs.logwait |= (target->to_log | target->beprm->to_log);
|
||||
abort_filt = 1;
|
||||
}
|
||||
break;
|
||||
case ACT_ALLOW:
|
||||
if (!(t->flags & (SN_CLDENY | SN_CLTARPIT))) {
|
||||
t->flags |= SN_CLALLOW;
|
||||
|
|
Loading…
Reference in New Issue