[MINOR] add the "ignore-persist" option to conditionally ignore persistence
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.
diff --git a/include/types/proto_http.h b/include/types/proto_http.h
index f5410fa..7890cb2 100644
--- a/include/types/proto_http.h
+++ b/include/types/proto_http.h
@@ -221,6 +221,13 @@
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,
diff --git a/include/types/proxy.h b/include/types/proxy.h
index fb34513..3ac80d8 100644
--- a/include/types/proxy.h
+++ b/include/types/proxy.h
@@ -176,7 +176,7 @@
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 @@
} 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 {
diff --git a/include/types/session.h b/include/types/session.h
index 94bb5d5..daf2619 100644
--- a/include/types/session.h
+++ b/include/types/session.h
@@ -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() !
*/
diff --git a/src/cfgparse.c b/src/cfgparse.c
index f25cc76..ebba4df 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -903,7 +903,7 @@
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 @@
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 @@
}
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;
diff --git a/src/proto_http.c b/src/proto_http.c
index ce8448b..0f6f77b 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -3282,8 +3282,8 @@
* 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 @@
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 @@
* 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 @@
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 @@
* 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 @@
}
}
- 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 @@
}
/* 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 @@
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;
diff --git a/src/session.c b/src/session.c
index 34ffb11..3f08a6a 100644
--- a/src/session.c
+++ b/src/session.c
@@ -551,7 +551,7 @@
*/
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 @@
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 @@
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;
}
}