Since it's hard to get this value right, haproxy automatically sets it to
10% of the sum of the maxconns of all frontends that may branch to this
- backend. That way it's safe to leave it unset.
+ backend (based on "use_backend" and "default_backend" rules). That way it's
+ safe to leave it unset. However, "use_backend" involving dynamic names are
+ not counted since there is no way to know if they could match or not.
Example :
# The servers will accept between 100 and 1000 concurrent connections each
May be used in sections : defaults | frontend | listen | backend
no | yes | yes | no
Arguments :
- <backend> is the name of a valid backend or "listen" section.
+ <backend> is the name of a valid backend or "listen" section, or a
+ "log-format" string resolving to a backend name.
<condition> is a condition composed of ACLs, as described in section 7.
a complete HTTP request to get in. This feature is useful when a frontend
must decode several protocols on a unique port, one of them being HTTP.
- See also: "default_backend", "tcp-request", and section 7 about ACLs.
+ When <backend> is a simple name, it is resolved at configuration time, and an
+ error is reported if the specified backend does not exist. If <backend> is
+ a log-format string instead, no check may be done at configuration time, so
+ the backend name is resolved dynamically at run time. If the resulting
+ backend name does not correspond to any valid backend, no other rule is
+ evaluated, and the default_backend directive is applied instead. Note that
+ when using dynamic backend names, it is highly recommended to use a prefix
+ that no other backend uses in order to ensure that an unauthorized backend
+ cannot be forced from the request.
+
+ It is worth mentionning that "use_backend" rules with an explicit name are
+ used to detect the association between frontends and backends to compute the
+ backend's "fullconn" setting. This cannot be done for dynamic names.
+
+ See also: "default_backend", "tcp-request", "fullconn", "log-format", and
+ section 7 about ACLs.
use-server <server> if <condition>
struct switching_rule {
struct list list; /* list linked to from the proxy */
struct acl_cond *cond; /* acl condition to meet */
+ int dynamic; /* this is a dynamic rule using the logformat expression */
union {
struct proxy *backend; /* target backend */
char *name; /* target backend name during config parsing */
+ struct list expr; /* logformat expression to use for dynamic rules */
} be;
};
/* find the target proxy for 'use_backend' rules */
list_for_each_entry(rule, &curproxy->switching_rules, list) {
struct proxy *target;
+ struct logformat_node *node;
+ char *pxname;
+
+ /* Try to parse the string as a log format expression. If the result
+ * of the parsing is only one entry containing a simple string, then
+ * it's a standard string corresponding to a static rule, thus the
+ * parsing is cancelled and be.name is restored to be resolved.
+ */
+ pxname = rule->be.name;
+ LIST_INIT(&rule->be.expr);
+ parse_logformat_string(pxname, curproxy, &rule->be.expr, 0, SMP_VAL_FE_HRQ_HDR,
+ curproxy->conf.args.file, curproxy->conf.args.line);
+ node = LIST_NEXT(&rule->be.expr, struct logformat_node *, list);
+
+ if (!LIST_ISEMPTY(&rule->be.expr)) {
+ if (node->type != LOG_FMT_TEXT || node->list.n != &rule->be.expr) {
+ rule->dynamic = 1;
+ free(pxname);
+ continue;
+ }
+ /* simple string: free the expression and fall back to static rule */
+ free(node->arg);
+ free(node);
+ }
+
+ rule->dynamic = 0;
+ rule->be.name = pxname;
target = findproxy_mode(rule->be.name, curproxy->mode, PR_CAP_BE);
/* check if a "use_backend" rule matches */
if (!found) {
list_for_each_entry(rule, &fe->switching_rules, list) {
- if (rule->be.backend == curproxy) {
+ if (!rule->dynamic && rule->be.backend == curproxy) {
found = 1;
break;
}
ret = !ret;
if (ret) {
- if (!session_set_backend(s, rule->be.backend))
+ /* If the backend name is dynamic, try to resolve the name.
+ * If we can't resolve the name, or if any error occurs, break
+ * the loop and fallback to the default backend.
+ */
+ struct proxy *backend;
+
+ if (rule->dynamic) {
+ struct chunk *tmp = get_trash_chunk();
+ if (!build_logline(s, tmp->str, tmp->size, &rule->be.expr))
+ break;
+ backend = findproxy(tmp->str, PR_CAP_BE);
+ if (!backend)
+ break;
+ }
+ else
+ backend = rule->be.backend;
+
+ if (!session_set_backend(s, backend))
goto sw_failed;
break;
}