mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-01-30 10:06:43 +00:00
MEDIUM: http: add the ability to redefine http-err-codes and http-fail-codes
The new global keywords "http-err-codes" and "http-fail-codes" allow to redefine which HTTP status codes indicate a client-induced error or a server error, as tracked by stick-table counters. This is only done globally, though everything was done so that it could easily be extended to a per-proxy mechanism if there was a real need for this (but it would eat quite more RAM then). A simple reg-test was added (http-err-fail.vtc).
This commit is contained in:
parent
9d827e1049
commit
4cc25f26f9
@ -1919,6 +1919,40 @@ hard-stop-after <time>
|
|||||||
|
|
||||||
See also: grace
|
See also: grace
|
||||||
|
|
||||||
|
http-err-codes [+-]<range>[,...] [...]
|
||||||
|
Replace, reduce or extend the list of status codes that define an error as
|
||||||
|
considered by the termination codes and the "http_err_cnt" counter in stick
|
||||||
|
tables. The default range for errors is 400 to 499, but in certain contexts
|
||||||
|
some users prefer to exclude specific codes, especially when tracking client
|
||||||
|
errors (e.g. 404 on systems with dynamically generated contents). See also
|
||||||
|
"http-fail-codes" and "http_err_cnt".
|
||||||
|
|
||||||
|
A range specified without '+' nor '-' redefines the existing range to the new
|
||||||
|
one. A range starting with '+' extends the existing range to also include the
|
||||||
|
specified one, which may or may not overlap with the existing one. A range
|
||||||
|
starting with '-' removes the specified range from the existing one. A range
|
||||||
|
consists in a number from 100 to 599, optionally followed by "-" followed by
|
||||||
|
another number greater than or equal to the first one to indicate the high
|
||||||
|
boundary of the range. Multiple ranges may be delimited by commas for a same
|
||||||
|
add/del/ replace operation.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
http-err-codes 400,402-444,446-480,490 # sets exactly these codes
|
||||||
|
http-err-codes 400-499 -450 +500 # sets 400 to 500 except 450
|
||||||
|
http-err-codes -450-459 # removes 450 to 459 from range
|
||||||
|
http-err-codes +501,505 # adds 501 and 505 to range
|
||||||
|
|
||||||
|
http-fail-codes [+-]<range>[,...] [...]
|
||||||
|
Replace, reduce or extend the list of status codes that define a failure as
|
||||||
|
considered by the termination codes and the "http_fail_cnt" counter in stick
|
||||||
|
tables. The default range for failures is 500 to 599 except 501 and 505 which
|
||||||
|
can be triggered by clients, and normally indicate a failure from the server
|
||||||
|
to process the request. Some users prefer to exclude certain codes in certain
|
||||||
|
contexts where it is known they're not relevant, such as 500 in certain SOAP
|
||||||
|
environments as it doesn't translate a server fault there. The syntax is
|
||||||
|
exactly the same as for http-err-codes above. See also "http-err-codes" and
|
||||||
|
"http_fail_cnt".
|
||||||
|
|
||||||
httpclient.resolvers.disabled <on|off>
|
httpclient.resolvers.disabled <on|off>
|
||||||
Disable the DNS resolution of the httpclient. Prevent the creation of the
|
Disable the DNS resolution of the httpclient. Prevent the creation of the
|
||||||
"default" resolvers section.
|
"default" resolvers section.
|
||||||
|
84
reg-tests/http-rules/http-err-fail.vtc
Normal file
84
reg-tests/http-rules/http-err-fail.vtc
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
varnishtest "test for http-err-codes/http-fail-codes redefinitions"
|
||||||
|
|
||||||
|
feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(3.0-dev1)'"
|
||||||
|
feature ignore_unknown_macro
|
||||||
|
|
||||||
|
server s2 {
|
||||||
|
rxreq
|
||||||
|
txresp -status 220
|
||||||
|
} -start
|
||||||
|
|
||||||
|
server s3 {
|
||||||
|
rxreq
|
||||||
|
txresp -status 300
|
||||||
|
} -start
|
||||||
|
|
||||||
|
server s4 {
|
||||||
|
rxreq
|
||||||
|
txresp -status 400
|
||||||
|
} -start
|
||||||
|
|
||||||
|
server s5 {
|
||||||
|
rxreq
|
||||||
|
txresp -status 555
|
||||||
|
} -start
|
||||||
|
|
||||||
|
|
||||||
|
haproxy h1 -conf {
|
||||||
|
global
|
||||||
|
http-err-codes 220 +300-499 -300-399 # only 220, 400-499 remain
|
||||||
|
http-fail-codes -550-580 +555,599,556-566
|
||||||
|
|
||||||
|
defaults
|
||||||
|
mode http
|
||||||
|
timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
|
||||||
|
timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
|
||||||
|
timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
|
||||||
|
option socket-stats
|
||||||
|
|
||||||
|
frontend fe
|
||||||
|
bind "fd@${fe}"
|
||||||
|
http-request track-sc0 path
|
||||||
|
http-after-response add-header x-table err=%[sc0_http_err_cnt],fail=%[sc0_http_fail_cnt]
|
||||||
|
stick-table type string size 100 store http_err_cnt,http_fail_cnt
|
||||||
|
default_backend be
|
||||||
|
|
||||||
|
backend be
|
||||||
|
use-server s2 if { path -m beg /2 }
|
||||||
|
use-server s3 if { path -m beg /3 }
|
||||||
|
use-server s4 if { path -m beg /4 }
|
||||||
|
use-server s5 if { path -m beg /5 }
|
||||||
|
|
||||||
|
server s2 ${s2_addr}:${s2_port}
|
||||||
|
server s3 ${s3_addr}:${s3_port}
|
||||||
|
server s4 ${s4_addr}:${s4_port}
|
||||||
|
server s5 ${s5_addr}:${s5_port}
|
||||||
|
} -start
|
||||||
|
|
||||||
|
client c2 -connect ${h1_fe_sock} {
|
||||||
|
txreq -url "/2"
|
||||||
|
rxresp
|
||||||
|
expect resp.status == 220
|
||||||
|
expect resp.http.x-table ~ "err=1,fail=0"
|
||||||
|
} -run
|
||||||
|
|
||||||
|
client c3 -connect ${h1_fe_sock} {
|
||||||
|
txreq -url "/3"
|
||||||
|
rxresp
|
||||||
|
expect resp.status == 300
|
||||||
|
expect resp.http.x-table ~ "err=0,fail=0"
|
||||||
|
} -run
|
||||||
|
|
||||||
|
client c4 -connect ${h1_fe_sock} {
|
||||||
|
txreq -url "/4"
|
||||||
|
rxresp
|
||||||
|
expect resp.status == 400
|
||||||
|
expect resp.http.x-table ~ "err=1,fail=0"
|
||||||
|
} -run
|
||||||
|
|
||||||
|
client c5 -connect ${h1_fe_sock} {
|
||||||
|
txreq -url "/5"
|
||||||
|
rxresp
|
||||||
|
expect resp.status == 555
|
||||||
|
expect resp.http.x-table ~ "err=0,fail=1"
|
||||||
|
} -run
|
98
src/http.c
98
src/http.c
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <haproxy/api.h>
|
#include <haproxy/api.h>
|
||||||
|
#include <haproxy/cfgparse.h>
|
||||||
#include <haproxy/http.h>
|
#include <haproxy/http.h>
|
||||||
#include <haproxy/tools.h>
|
#include <haproxy/tools.h>
|
||||||
|
|
||||||
@ -1483,3 +1484,100 @@ static void _http_init()
|
|||||||
http_status_del_range(http_fail_status_codes, 505, 505);
|
http_status_del_range(http_fail_status_codes, 505, 505);
|
||||||
}
|
}
|
||||||
INITCALL0(STG_INIT, _http_init);
|
INITCALL0(STG_INIT, _http_init);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* registered keywords below
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* parses a global "http-err-codes" and "http-fail-codes" directive. */
|
||||||
|
static int http_parse_http_err_fail_codes(char **args, int section_type, struct proxy *curpx,
|
||||||
|
const struct proxy *defpx, const char *file, int line,
|
||||||
|
char **err)
|
||||||
|
{
|
||||||
|
const char *cmd = args[0];
|
||||||
|
const char *p, *b, *e;
|
||||||
|
int op, low, high;
|
||||||
|
long *bitfield;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if (strcmp(cmd, "http-err-codes") == 0)
|
||||||
|
bitfield = http_err_status_codes;
|
||||||
|
else if (strcmp(cmd, "http-fail-codes") == 0)
|
||||||
|
bitfield = http_fail_status_codes;
|
||||||
|
else
|
||||||
|
ABORT_NOW();
|
||||||
|
|
||||||
|
if (!*args[1]) {
|
||||||
|
memprintf(err, "Missing status codes range for '%s'.", cmd);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* operation: <0 = remove, 0 = replace, >0 = add. The operation is only
|
||||||
|
* reset for each new arg so that we can do +200,300,400 without
|
||||||
|
* changing the operation.
|
||||||
|
*/
|
||||||
|
for (; *(p = *(++args)); ) {
|
||||||
|
switch (*p) {
|
||||||
|
case '+': op = 1; p++; break;
|
||||||
|
case '-': op = -1; p++; break;
|
||||||
|
default: op = 0; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!*p)
|
||||||
|
goto inval;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
b = p;
|
||||||
|
e = p + strlen(p);
|
||||||
|
low = read_uint(&p, e);
|
||||||
|
if (b == e || p == b)
|
||||||
|
goto inval;
|
||||||
|
|
||||||
|
high = low;
|
||||||
|
if (*p == '-') {
|
||||||
|
p++;
|
||||||
|
b = p;
|
||||||
|
high = read_uint(&p, e);
|
||||||
|
if (b == e || p == b || (*p && *p != ','))
|
||||||
|
goto inval;
|
||||||
|
}
|
||||||
|
else if (*p && *p != ',')
|
||||||
|
goto inval;
|
||||||
|
|
||||||
|
if (high < low || low < 100 || high > 599) {
|
||||||
|
memprintf(err, "Invalid status codes range '%s' in '%s'.\n"
|
||||||
|
" Codes must be between 100 and 599 and ranges in ascending order.",
|
||||||
|
*args, cmd);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!op)
|
||||||
|
memset(bitfield, 0, sizeof(http_err_status_codes));
|
||||||
|
if (op >= 0)
|
||||||
|
http_status_add_range(bitfield, low, high);
|
||||||
|
if (op < 0)
|
||||||
|
http_status_del_range(bitfield, low, high);
|
||||||
|
|
||||||
|
if (!*p)
|
||||||
|
break;
|
||||||
|
/* skip ',' */
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
|
end:
|
||||||
|
return ret;
|
||||||
|
inval:
|
||||||
|
memprintf(err, "Invalid status codes range '%s' in '%s' at position %lu. Ranges must be in the form [+-]{low[-{high}]}[,...].",
|
||||||
|
*args, cmd, (ulong)(p - *args));
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct cfg_kw_list cfg_kws = {{ },{
|
||||||
|
{ CFG_GLOBAL, "http-err-codes", http_parse_http_err_fail_codes },
|
||||||
|
{ CFG_GLOBAL, "http-fail-codes", http_parse_http_err_fail_codes },
|
||||||
|
{ /* END */ }
|
||||||
|
}};
|
||||||
|
|
||||||
|
INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
|
||||||
|
Loading…
Reference in New Issue
Block a user