[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.
This commit is contained in:
parent
b94af61901
commit
47fdd8e993
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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() !
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue