]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MINOR] add the "ignore-persist" option to conditionally ignore persistence
authorCyril Bonté <cyril.bonte@free.fr>
Sat, 24 Apr 2010 22:00:51 +0000 (00:00 +0200)
committerWilly Tarreau <w@1wt.eu>
Sun, 25 Apr 2010 20:37:14 +0000 (22:37 +0200)
This is used to disable persistence depending on some conditions (for
example using an ACL matching static files or a specific User-Agent).
You can see it as a complement to "force-persist".

In the configuration file, the force-persist/ignore-persist declaration
order define the rules priority.

Used with the "appsesion" keyword, it can also help reducing memory usage,
as the session won't be hashed the persistence is ignored.

include/types/proto_http.h
include/types/proxy.h
include/types/session.h
src/cfgparse.c
src/proto_http.c
src/session.c

index f5410fac426f3ffda5a43d3854082a7ae5073b1d..7890cb2e68048765029cde71a56348deff959e88 100644 (file)
@@ -221,6 +221,13 @@ enum {
        REDIRECT_TYPE_PREFIX,           /* prefix redirect */
 };
 
+/* Perist types (force-persist, ignore-persist) */
+enum {
+       PERSIST_TYPE_NONE = 0,          /* no persistence */
+       PERSIST_TYPE_FORCE,             /* force-persist */
+       PERSIST_TYPE_IGNORE,            /* ignore-persist */
+};
+
 /* Known HTTP methods */
 typedef enum {
        HTTP_METH_NONE = 0,
index fb34513821f685e70dab1bb13f9064a60301babe..3ac80d81ea1b05ee793ac4594eaf8007b684017b 100644 (file)
@@ -176,7 +176,7 @@ struct proxy {
        struct list block_cond;                 /* early blocking conditions (chained) */
        struct list redirect_rules;             /* content redirecting rules (chained) */
        struct list switching_rules;            /* content switching rules (chained) */
-       struct list force_persist_rules;        /* 'force-persist' rules (chained) */
+       struct list persist_rules;              /* 'force-persist' and 'ignore-persist' rules (chained) */
        struct list sticking_rules;             /* content sticking rules (chained) */
        struct list storersp_rules;             /* content store response rules (chained) */
        struct {                                /* TCP request processing */
@@ -307,9 +307,10 @@ struct switching_rule {
        } be;
 };
 
-struct force_persist_rule {
+struct persist_rule {
        struct list list;                       /* list linked to from the proxy */
        struct acl_cond *cond;                  /* acl condition to meet */
+       int type;
 };
 
 struct sticking_rule {
index 94bb5d5d83a5b53c1a48ffccb121938f1b97966d..daf2619261af9b545f8080c0ea1667d299a5cd2e 100644 (file)
@@ -81,6 +81,8 @@
 #define        SN_FINST_SHIFT  16              /* bit shift */
 /* unused:              0x00080000 */
 
+#define SN_IGNORE_PRST 0x00100000      /* ignore persistence */
+
 /* WARNING: if new fields are added, they must be initialized in event_accept()
  * and freed in session_free() !
  */
index f25cc76ee4c1b965fdf3c0f82fa89b5a0a2d005d..ebba4dfb3b0b67a4ff9a96fcbc4b45d4f3a90e4e 100644 (file)
@@ -903,7 +903,7 @@ static void init_new_proxy(struct proxy *p)
        LIST_INIT(&p->redirect_rules);
        LIST_INIT(&p->mon_fail_cond);
        LIST_INIT(&p->switching_rules);
-       LIST_INIT(&p->force_persist_rules);
+       LIST_INIT(&p->persist_rules);
        LIST_INIT(&p->sticking_rules);
        LIST_INIT(&p->storersp_rules);
        LIST_INIT(&p->tcp_req.inspect_rules);
@@ -2178,8 +2178,9 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                LIST_INIT(&rule->list);
                LIST_ADDQ(&curproxy->switching_rules, &rule->list);
        }
-       else if (!strcmp(args[0], "force-persist")) {
-               struct force_persist_rule *rule;
+       else if ((!strcmp(args[0], "force-persist")) ||
+                (!strcmp(args[0], "ignore-persist"))) {
+               struct persist_rule *rule;
 
                if (curproxy == &defproxy) {
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
@@ -2198,18 +2199,23 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                }
 
                if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 1)) == NULL) {
-                       Alert("parsing [%s:%d] : error detected while parsing a 'force-persist' rule.\n",
-                             file, linenum);
+                       Alert("parsing [%s:%d] : error detected while parsing a '%s' rule.\n",
+                             file, linenum, args[0]);
                        err_code |= ERR_ALERT | ERR_FATAL;
                        goto out;
                }
 
                err_code |= warnif_cond_requires_resp(cond, file, linenum);
 
-               rule = (struct force_persist_rule *)calloc(1, sizeof(*rule));
+               rule = (struct persist_rule *)calloc(1, sizeof(*rule));
                rule->cond = cond;
+               if (!strcmp(args[0], "force-persist")) {
+                       rule->type = PERSIST_TYPE_FORCE;
+               } else {
+                       rule->type = PERSIST_TYPE_IGNORE;
+               }
                LIST_INIT(&rule->list);
-               LIST_ADDQ(&curproxy->force_persist_rules, &rule->list);
+               LIST_ADDQ(&curproxy->persist_rules, &rule->list);
        }
        else if (!strcmp(args[0], "stick-table")) {
                int myidx = 1;
index ce8448b052019996c8729287c736bbb2f22eb9fe..0f6f77bb7b946a0e3278379bebd9c796f1abb530 100644 (file)
@@ -3282,8 +3282,8 @@ int http_process_request(struct session *s, struct buffer *req, int an_bit)
         * so let's do the same now.
         */
 
-       /* It needs to look into the URI */
-       if ((txn->sessid == NULL) && s->be->appsession_name) {
+       /* It needs to look into the URI unless persistence must be ignored */
+       if ((txn->sessid == NULL) && s->be->appsession_name && !(s->flags & SN_IGNORE_PRST)) {
                get_srv_from_appsession(s, msg->sol + msg->sl.rq.u, msg->sl.rq.u_l);
        }
 
@@ -3730,7 +3730,7 @@ void http_end_txn_clean_session(struct session *s)
        s->req->cons->flags     = SI_FL_NONE;
        s->req->flags &= ~(BF_SHUTW|BF_SHUTW_NOW|BF_AUTO_CONNECT|BF_WRITE_ERROR|BF_STREAMER|BF_STREAMER_FAST);
        s->rep->flags &= ~(BF_SHUTR|BF_SHUTR_NOW|BF_READ_ATTACHED|BF_READ_ERROR|BF_READ_NOEXP|BF_STREAMER|BF_STREAMER_FAST|BF_WRITE_PARTIAL);
-       s->flags &= ~(SN_DIRECT|SN_ASSIGNED|SN_ADDR_SET|SN_BE_ASSIGNED|SN_FORCE_PRST);
+       s->flags &= ~(SN_DIRECT|SN_ASSIGNED|SN_ADDR_SET|SN_BE_ASSIGNED|SN_FORCE_PRST|SN_IGNORE_PRST);
        s->flags &= ~(SN_CURR_SESS|SN_REDIRECTABLE);
        s->txn.meth = 0;
        http_reset_txn(s);
@@ -4856,7 +4856,8 @@ int http_process_res_common(struct session *t, struct buffer *rep, int an_bit, s
                 * 6: add server cookie in the response if needed
                 */
                if ((t->srv) && !(t->flags & SN_DIRECT) && (t->be->options & PR_O_COOK_INS) &&
-                   (!(t->be->options & PR_O_COOK_POST) || (txn->meth == HTTP_METH_POST))) {
+                   (!(t->be->options & PR_O_COOK_POST) || (txn->meth == HTTP_METH_POST)) &&
+                   !(t->flags & SN_IGNORE_PRST)) {
                        int len;
 
                        /* the server is known, it's not the one the client requested, we have to
@@ -5493,6 +5494,7 @@ void manage_client_side_appsession(struct session *t, const char *buf, int len)
 
                if (asession->serverid != NULL) {
                        struct server *srv = t->be->srv;
+
                        while (srv) {
                                if (strcmp(srv->id, asession->serverid) == 0) {
                                        if ((srv->state & SRV_RUNNING) ||
@@ -5686,8 +5688,9 @@ void manage_client_side_cookies(struct session *t, struct buffer *req)
                                         * However, to prevent clients from sticking to cookie-less backup server
                                         * when they have incidentely learned an empty cookie, we simply ignore
                                         * empty cookies and mark them as invalid.
+                                        * The same behaviour is applied when persistence must be ignored.
                                         */
-                                       if (delim == p3)
+                                       if ((delim == p3) || (t->flags & SN_IGNORE_PRST))
                                                srv = NULL;
 
                                        while (srv) {
@@ -5765,7 +5768,8 @@ void manage_client_side_cookies(struct session *t, struct buffer *req)
                                        }
                                }
 
-                               if (t->be->appsession_name != NULL) {
+                               /* Look for the appsession cookie unless persistence must be ignored */
+                               if (!(t->flags & SN_IGNORE_PRST) && (t->be->appsession_name != NULL)) {
                                        int cmp_len, value_len;
                                        char *value_begin;
 
@@ -6161,7 +6165,7 @@ void manage_server_side_cookies(struct session *t, struct buffer *rtr)
                        }
 
                        /* now check if we need to process it for persistence */
-                       if ((p2 - p1 == t->be->cookie_len) && (t->be->cookie_name != NULL) &&
+                       if (!(t->flags & SN_IGNORE_PRST) && (p2 - p1 == t->be->cookie_len) && (t->be->cookie_name != NULL) &&
                            (memcmp(p1, t->be->cookie_name, p2 - p1) == 0)) {
                                /* Cool... it's the right one */
                                txn->flags |= TX_SCK_SEEN;
@@ -6208,8 +6212,8 @@ void manage_server_side_cookies(struct session *t, struct buffer *rtr)
                                        txn->flags |= TX_SCK_INSERTED | TX_SCK_DELETED;
                                }
                        }
-                       /* next, let's see if the cookie is our appcookie */
-                       else if (t->be->appsession_name != NULL) {
+                       /* next, let's see if the cookie is our appcookie, unless persistence must be ignored */
+                       else if (!(t->flags & SN_IGNORE_PRST) && (t->be->appsession_name != NULL)) {
                                int cmp_len, value_len;
                                char *value_begin;
 
index 34ffb1170653a871fc3f526bbb0a4994dc199184..3f08a6a3d78e1fc62ab379dd376f99de91cf5380 100644 (file)
@@ -551,7 +551,7 @@ static void sess_prepare_conn_req(struct session *s, struct stream_interface *si
  */
 int process_switching_rules(struct session *s, struct buffer *req, int an_bit)
 {
-       struct force_persist_rule *prst_rule;
+       struct persist_rule *prst_rule;
 
        req->analysers &= ~an_bit;
        req->analyse_exp = TICK_ETERNITY;
@@ -598,10 +598,10 @@ int process_switching_rules(struct session *s, struct buffer *req, int an_bit)
        if (s->fe == s->be)
                s->req->analysers &= ~AN_REQ_HTTP_PROCESS_BE;
 
-       /* as soon as we know the backend, we must check if we have a matching forced
+       /* as soon as we know the backend, we must check if we have a matching forced or ignored
         * persistence rule, and report that in the session.
         */
-       list_for_each_entry(prst_rule, &s->be->force_persist_rules, list) {
+       list_for_each_entry(prst_rule, &s->be->persist_rules, list) {
                int ret = 1;
 
                if (prst_rule->cond) {
@@ -613,7 +613,11 @@ int process_switching_rules(struct session *s, struct buffer *req, int an_bit)
 
                if (ret) {
                        /* no rule, or the rule matches */
-                       s->flags |= SN_FORCE_PRST;
+                       if (prst_rule->type == PERSIST_TYPE_FORCE) {
+                               s->flags |= SN_FORCE_PRST;
+                       } else {
+                               s->flags |= SN_IGNORE_PRST;
+                       }
                        break;
                }
        }