capture cookie X X X X
capture request header X X X X
capture response header X X X X
-clitimeout X X X -
-contimeout X X X X
+clitimeout X X X - (deprecated)
+contimeout X X X X (deprecated)
cookie X - X X
default_backend - X X -
disabled - X X X
rsprep - X X X
server - - X X
source X - X X
-srvtimeout X - X X
+srvtimeout X - X X (deprecated)
stats auth X - X X
stats enable X - X X
stats realm X - X X
stats scope X - X X
stats uri X - X X
stats hide-version X - X X
+timeout appsession X - X X
+timeout client X X X -
+timeout clitimeout X X X - (deprecated)
+timeout connect X - X X
+timeout contimeout X - X X (deprecated)
+timeout queue X - X X
+timeout server X - X X
+timeout srvtimeout X - X X (deprecated)
+timeout tarpit X X X -
transparent X X X -
use_backend - X X -
usesrc X - X X
const char *proxy_cap_str(int cap);
const char *proxy_mode_str(int mode);
struct proxy *findproxy(const char *name, int mode, int cap);
+int proxy_parse_timeout(const char **args, struct proxy *proxy,
+ struct proxy *defpx, char *err, int errlen);
/*
* This function returns a string containing the type of the proxy in a format
return -1;
}
}
- else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
- if (!__tv_iseq(&curproxy->contimeout, &defproxy.contimeout)) {
- Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
- return 0;
- }
- else if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
- return 0;
+ else if (!strcmp(args[0], "contimeout") || !strcmp(args[0], "clitimeout") ||
+ !strcmp(args[0], "srvtimeout") || !strcmp(args[0], "timeout")) {
- if (*(args[1]) == 0) {
- Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
- file, linenum, args[0]);
- return -1;
- }
- err = parse_time_err(args[1], &val, TIME_UNIT_MS);
- if (err) {
- Alert("parsing [%s:%d] : unexpected character '%c' in %s.\n",
- file, linenum, *err, args[0]);
- return -1;
- }
- if (val > 0)
- __tv_from_ms(&curproxy->contimeout, val);
- else
- tv_eternity(&curproxy->contimeout);
- }
- else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
- if (!__tv_iseq(&curproxy->clitimeout, &defproxy.clitimeout)) {
- Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
- file, linenum, args[0]);
- return 0;
- }
- else if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
- return 0;
+ /* either we have {con|srv|cli}timeout <value> or we have the
+ * new form: timeout <type> <value>. The parser needs the word
+ * preceeding the value.
+ */
+ const char **start_arg = (const char **)args;
- if (*(args[1]) == 0) {
- Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
- file, linenum, args[0]);
- return -1;
- }
- err = parse_time_err(args[1], &val, TIME_UNIT_MS);
- if (err) {
- Alert("parsing [%s:%d] : unexpected character '%c' in %s.\n",
- file, linenum, *err, args[0]);
- return -1;
- }
- if (val > 0)
- __tv_from_ms(&curproxy->clitimeout, val);
- else
- tv_eternity(&curproxy->clitimeout);
- }
- else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
- if (!__tv_iseq(&curproxy->srvtimeout, &defproxy.srvtimeout)) {
- Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
- return 0;
- }
- else if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
- return 0;
+ if (strcmp(args[0], "timeout") == 0)
+ start_arg++;
- if (*(args[1]) == 0) {
- Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
- file, linenum, args[0]);
- return -1;
- }
- err = parse_time_err(args[1], &val, TIME_UNIT_MS);
- if (err) {
- Alert("parsing [%s:%d] : unexpected character '%c' in %s.\n",
- file, linenum, *err, args[0]);
+ snprintf(trash, sizeof(trash), "error near '%s'", args[0]);
+ rc = proxy_parse_timeout(start_arg, curproxy, &defproxy, trash, sizeof(trash));
+ if (rc < 0) {
+ Alert("parsing [%s:%d] : %s\n", file, linenum, trash);
return -1;
}
- if (val > 0)
- __tv_from_ms(&curproxy->srvtimeout, val);
- else
- tv_eternity(&curproxy->srvtimeout);
+ if (rc > 0)
+ Warning("parsing [%s:%d] : %s\n", file, linenum, trash);
}
else if (!strcmp(args[0], "retries")) { /* connection retries */
if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
return "unknown";
}
+/* This function parses a "timeout" statement in a proxy section. It returns
+ * -1 if there is any error, 1 for a warning, otherwise zero. If it does not
+ * return zero, it may write an error message into the <err> buffer, for at
+ * most <errlen> bytes, trailing zero included. The trailing '\n' must not
+ * be written. The function must be called with <args> pointing to the first
+ * word after "timeout", with <proxy> pointing to the proxy being parsed, and
+ * <defpx> to the default proxy or NULL. As a special case for compatibility
+ * with older configs, it also accepts "{cli|srv|con}timeout" in args[0].
+ */
+int proxy_parse_timeout(const char **args, struct proxy *proxy,
+ struct proxy *defpx, char *err, int errlen)
+{
+ unsigned timeout;
+ int retval, cap;
+ const char *res, *name;
+ struct timeval *tv = NULL;
+ struct timeval *td = NULL;
+
+ retval = 0;
+ name = args[0];
+ if (!strcmp(args[0], "client") || !strcmp(args[0], "clitimeout")) {
+ name = "client";
+ tv = &proxy->clitimeout;
+ td = &defpx->clitimeout;
+ cap = PR_CAP_FE;
+ } else if (!strcmp(args[0], "tarpit")) {
+ tv = &proxy->timeout.tarpit;
+ td = &defpx->timeout.tarpit;
+ cap = PR_CAP_FE;
+ } else if (!strcmp(args[0], "server") || !strcmp(args[0], "srvtimeout")) {
+ name = "server";
+ tv = &proxy->srvtimeout;
+ td = &defpx->srvtimeout;
+ cap = PR_CAP_BE;
+ } else if (!strcmp(args[0], "connect") || !strcmp(args[0], "contimeout")) {
+ name = "connect";
+ tv = &proxy->contimeout;
+ td = &defpx->contimeout;
+ cap = PR_CAP_BE;
+ } else if (!strcmp(args[0], "appsession")) {
+ tv = &proxy->appsession_timeout;
+ td = &defpx->appsession_timeout;
+ cap = PR_CAP_BE;
+ } else if (!strcmp(args[0], "queue")) {
+ tv = &proxy->timeout.queue;
+ td = &defpx->timeout.queue;
+ cap = PR_CAP_BE;
+ } else {
+ snprintf(err, errlen, "timeout '%s': must be 'client', 'server', 'connect', 'appsession', 'queue', or 'tarpit'",
+ args[0]);
+ return -1;
+ }
+
+ if (*args[1] == 0) {
+ snprintf(err, errlen, "%s timeout expects an integer value (in milliseconds)", name);
+ return -1;
+ }
+
+ res = parse_time_err(args[1], &timeout, TIME_UNIT_MS);
+ if (res) {
+ snprintf(err, errlen, "unexpected character '%c' in %s timeout", *err, name);
+ return -1;
+ }
+
+ if (!(proxy->cap & cap)) {
+ snprintf(err, errlen, "%s timeout will be ignored because %s '%s' has no %s capability",
+ name, proxy_type_str(proxy), proxy->id,
+ (cap & PR_CAP_BE) ? "backend" : "frontend");
+ retval = 1;
+ }
+ else if (defpx && !__tv_iseq(tv, td)) {
+ snprintf(err, errlen, "overwriting %s timeout which was already specified", name);
+ retval = 1;
+ }
+
+ if (timeout)
+ __tv_from_ms(tv, timeout);
+ else
+ tv_eternity(tv);
+
+ return retval;
+}
+
/*
* This function finds a proxy with matching name, mode and with satisfying
* capabilities. It also checks if there are more matching proxies with
--- /dev/null
+# This is a test configuration.
+# It is used to check that time units are correctly parsed.
+
+global
+ maxconn 1000
+ stats timeout 3s
+
+listen sample1
+ mode http
+ retries 1
+ redispatch
+ timeout client 15m
+ timeout tarpit 20s
+ timeout queue 60s
+ timeout connect 5s
+ timeout server 15m
+ maxconn 40000
+ bind :8000
+ balance roundrobin
+ option allbackups
+ server act1 127.0.0.1:80 weight 10 check port 81 inter 500ms fall 1
+ server act2 127.0.0.2:80 weight 20 check port 81 inter 500ms fall 1
+ server act3 127.0.0.3:80 weight 30 check port 81 inter 500ms fall 1
+ option httpclose
+ stats uri /stats
+ stats refresh 5000ms