From 47fdd8e993830ba1bc9cd9a9624379563f744b49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cyril=20Bont=C3=A9?= Date: Sun, 25 Apr 2010 00:00:51 +0200 Subject: [PATCH] [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. --- include/types/proto_http.h | 7 +++++++ include/types/proxy.h | 5 +++-- include/types/session.h | 2 ++ src/cfgparse.c | 20 +++++++++++++------- src/proto_http.c | 22 +++++++++++++--------- src/session.c | 12 ++++++++---- 6 files changed, 46 insertions(+), 22 deletions(-) diff --git a/include/types/proto_http.h b/include/types/proto_http.h index f5410fac42..7890cb2e68 100644 --- a/include/types/proto_http.h +++ b/include/types/proto_http.h @@ -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, diff --git a/include/types/proxy.h b/include/types/proxy.h index fb34513821..3ac80d81ea 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -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 { diff --git a/include/types/session.h b/include/types/session.h index 94bb5d5d83..daf2619261 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 f25cc76ee4..ebba4dfb3b 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -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; diff --git a/src/proto_http.c b/src/proto_http.c index ce8448b052..0f6f77bb7b 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -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; diff --git a/src/session.c b/src/session.c index 34ffb11706..3f08a6a3d7 100644 --- a/src/session.c +++ b/src/session.c @@ -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; } }