]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MAJOR] merged the 'setbe' actions to switch the backend on a regex
authorWilly Tarreau <w@1wt.eu>
Sun, 17 Dec 2006 22:15:24 +0000 (23:15 +0100)
committerWilly Tarreau <w@1wt.eu>
Sun, 17 Dec 2006 22:15:24 +0000 (23:15 +0100)
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.

include/common/regex.h
src/cfgparse.c
src/proto_http.c

index bf51a0dcd7c941f0b18b427efe82836350f5f0cd..bc86bbdf315d9a1ccb2ffedef019028dea65e214 100644 (file)
@@ -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;
index b3747c4e6c9fd48c4f6f13aa73d26f9702ea8a02..0034bdab0bca8941664518d2c4c3f7f49e8ba97e 100644 (file)
@@ -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"
index 8ee2cf86419e3725839c2f6cd179b1e68f3e637d..9cce59ba769ff93d50671dcc3d35c933e2980843 100644 (file)
@@ -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;