MINOR: http-htx/proxy: Add http-error directive using http return syntax
The http-error directive can now be used instead of errorfile to define an error message in a proxy section (including default sections). This directive uses the same syntax that http return rules. The only real difference is the limitation on status code that may be specified. Only status codes supported by errorfile directives are supported for this new directive. Parsing of errorfile directive remains independent from http-error parsing. But functionally, it may be expressed in terms of http-errors : errorfile <status> <file> ==> http-errror status <status> errorfile <file>
This commit is contained in:
parent
97e466c9e3
commit
3b967c1210
|
@ -2659,6 +2659,7 @@ http-check expect X - X X
|
|||
http-check send-state X - X X
|
||||
http-check set-var X - X X
|
||||
http-check unset-var X - X X
|
||||
http-error X X X X
|
||||
http-request - X X X
|
||||
http-response - X X X
|
||||
http-reuse X - X X
|
||||
|
@ -3810,7 +3811,7 @@ errorfile <code> <file>
|
|||
simple method for developing those files consists in associating them to the
|
||||
403 status code and interrogating a blocked URL.
|
||||
|
||||
See also : "errorloc", "errorloc302", "errorloc303"
|
||||
See also : "http-error", "errorloc", "errorloc302", "errorloc303"
|
||||
|
||||
Example :
|
||||
errorfile 400 /etc/haproxy/errorfiles/400badreq.http
|
||||
|
@ -3839,8 +3840,8 @@ errorfiles <name> [<code> ...]
|
|||
ones. Fonctionnly, it is exactly the same than declaring all error files by
|
||||
hand using "errorfile" directives.
|
||||
|
||||
See also : "errorfile", "errorloc", "errorloc302" , "errorloc303" and section
|
||||
3.8 about http-errors.
|
||||
See also : "http-error", "errorfile", "errorloc", "errorloc302" ,
|
||||
"errorloc303" and section 3.8 about http-errors.
|
||||
|
||||
Example :
|
||||
errorfiles generic
|
||||
|
@ -3877,7 +3878,7 @@ errorloc302 <code> <url>
|
|||
status code, indicating to the client that the URL must be fetched with a GET
|
||||
request.
|
||||
|
||||
See also : "errorfile", "errorloc303"
|
||||
See also : "http-error", "errorfile", "errorloc303"
|
||||
|
||||
|
||||
errorloc303 <code> <url>
|
||||
|
@ -3907,7 +3908,7 @@ errorloc303 <code> <url>
|
|||
possible that some very old browsers designed before HTTP/1.1 do not support
|
||||
it, but no such problem has been reported till now.
|
||||
|
||||
See also : "errorfile", "errorloc", "errorloc302"
|
||||
See also : "http-error", "errorfile", "errorloc", "errorloc302"
|
||||
|
||||
|
||||
email-alert from <emailaddr>
|
||||
|
@ -4852,6 +4853,83 @@ http-check unset-var(<var-name>)
|
|||
http-check unset-var(check.port)
|
||||
|
||||
|
||||
http-error status <code> [content-type <type>]
|
||||
[ { default-errorfiles | errorfile <file> | errorfiles <name> |
|
||||
file <file> | lf-file <file> | string <str> | lf-string <fmt> } ]
|
||||
[ hdr <name> <fmt> ]*
|
||||
Defines a custom error message to use instead of errors generated by HAProxy.
|
||||
May be used in sections : defaults | frontend | listen | backend
|
||||
yes | yes | yes | yes
|
||||
Arguments :
|
||||
staus <code> is the HTTP status code. It must be specified.
|
||||
Currently, HAProxy is capable of generating codes
|
||||
200, 400, 403, 404, 405, 408, 410, 425, 429, 500,
|
||||
502, 503, and 504.
|
||||
|
||||
content-type <type> is the response content type, for instance
|
||||
"text/plain". This parameter is ignored and should be
|
||||
omitted when an errorfile is configured or when the
|
||||
payload is empty. Otherwise, it must be defined.
|
||||
|
||||
default-errorfiles Reset the previously defined error message for current
|
||||
proxy for the status <code>. If used on a backend, the
|
||||
frontend error message is used, if defined. If used on
|
||||
a frontend, the default error message is used.
|
||||
|
||||
errorfile <file> designates a file containing the full HTTP response.
|
||||
It is recommended to follow the common practice of
|
||||
appending ".http" to the filename so that people do
|
||||
not confuse the response with HTML error pages, and to
|
||||
use absolute paths, since files are read before any
|
||||
chroot is performed.
|
||||
|
||||
errorfiles <name> designates the http-errors section to use to import
|
||||
the error message with the status code <code>. If no
|
||||
such message is found, the proxy's error messages are
|
||||
considered.
|
||||
|
||||
file <file> specifies the file to use as response payload. If the
|
||||
file is not empty, its content-type must be set as
|
||||
argument to "content-type", otherwise, any
|
||||
"content-type" argument is ignored. <file> is
|
||||
considered as a raw string.
|
||||
|
||||
string <str> specifies the raw string to use as response payload.
|
||||
The content-type must always be set as argument to
|
||||
"content-type".
|
||||
|
||||
lf-file <file> specifies the file to use as response payload. If the
|
||||
file is not empty, its content-type must be set as
|
||||
argument to "content-type", otherwise, any
|
||||
"content-type" argument is ignored. <file> is
|
||||
evaluated as a log-format string.
|
||||
|
||||
lf-string <str> specifies the log-format string to use as response
|
||||
payload. The content-type must always be set as
|
||||
argument to "content-type".
|
||||
|
||||
hdr <name> <fmt> adds to the response the HTTP header field whose name
|
||||
is specified in <name> and whose value is defined by
|
||||
<fmt>, which follows to the log-format rules.
|
||||
This parameter is ignored if an errorfile is used.
|
||||
|
||||
This directive may be used instead of "errorfile", to define a custom error
|
||||
message. As "errorfile" directive, it is used for errors detected and
|
||||
returned by HAProxy. If an errorfile is defined, it is parsed when HAProxy
|
||||
starts and must be valid according to the HTTP standards. The generated
|
||||
response must not exceed the configured buffer size (BUFFSIZE), otherwise an
|
||||
internal error will be returned. Finally, if you consider to use some
|
||||
http-after-response rules to rewrite these errors, the reserved buffer space
|
||||
should be available (see "tune.maxrewrite").
|
||||
|
||||
The files are read at the same time as the configuration and kept in memory.
|
||||
For this reason, the errors continue to be returned even when the process is
|
||||
chrooted, and no file change is considered while the process is running.
|
||||
|
||||
See also : "errorfile", "errorfiles", "errorloc", "errorloc302",
|
||||
"errorloc303" and section 3.8 about http-errors.
|
||||
|
||||
|
||||
http-request <action> [options...] [ { if | unless } <condition> ]
|
||||
Access control for Layer 7 requests
|
||||
|
||||
|
|
|
@ -82,6 +82,7 @@ enum {
|
|||
ARGC_SPOE, /* spoe message args */
|
||||
ARGC_UBK, /* use_backend message */
|
||||
ARGC_USRV, /* use-server message */
|
||||
ARGC_HERR, /* http-error */
|
||||
};
|
||||
|
||||
/* flags used when compiling and executing regex */
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
varnishtest "Test the http-error directive"
|
||||
#REQUIRE_VERSION=2.2
|
||||
|
||||
# This config tests the http-error directive.
|
||||
|
||||
feature ignore_unknown_macro
|
||||
|
||||
|
||||
haproxy h1 -conf {
|
||||
http-errors errors-1
|
||||
errorfile 400 ${testdir}/errors/400-1.http
|
||||
errorfile 403 ${testdir}/errors/403-1.http
|
||||
errorfile 404 ${testdir}/errors/404-1.http
|
||||
errorfile 500 ${testdir}/errors/500-1.http
|
||||
|
||||
defaults
|
||||
mode http
|
||||
timeout connect 1s
|
||||
timeout client 1s
|
||||
timeout server 1s
|
||||
errorfile 400 ${testdir}/errors/400.http
|
||||
errorfile 404 ${testdir}/errors/404.http
|
||||
|
||||
frontend fe1
|
||||
bind "fd@${fe1}"
|
||||
|
||||
http-error status 400
|
||||
http-error status 403 default-errorfiles
|
||||
http-error status 404 errorfiles errors-1
|
||||
http-error status 500 errorfile ${testdir}/errors/500.http
|
||||
http-error status 200 content-type "text/plain" hdr x-path "path=%[path]" lf-string "The path is \"%[path]\""
|
||||
|
||||
http-request return status 200 default-errorfiles if { path /200 }
|
||||
http-request deny deny_status 400 if { path /400 }
|
||||
http-request deny deny_status 403 if { path /403 }
|
||||
http-request deny deny_status 404 if { path /404 }
|
||||
http-request deny deny_status 500 if { path /500 }
|
||||
|
||||
} -start
|
||||
|
||||
client c1r1 -connect ${h1_fe1_sock} {
|
||||
txreq -req GET -url /200
|
||||
rxresp
|
||||
expect resp.status == 200
|
||||
expect resp.http.x-path == "path=/200"
|
||||
expect resp.http.content-type == "text/plain"
|
||||
expect resp.body == "The path is \"/200\""
|
||||
} -run
|
||||
client c1r2 -connect ${h1_fe1_sock} {
|
||||
txreq -req GET -url /400
|
||||
rxresp
|
||||
expect resp.status == 400
|
||||
expect resp.http.x-err-type == <undef>
|
||||
expect resp.http.content-length == 0
|
||||
} -run
|
||||
client c1r3 -connect ${h1_fe1_sock} {
|
||||
txreq -req GET -url /403
|
||||
rxresp
|
||||
expect resp.status == 403
|
||||
expect resp.http.x-err-type == <undef>
|
||||
expect resp.http.content-length == 93
|
||||
expect resp.http.content-type == "text/html"
|
||||
} -run
|
||||
client c1r3 -connect ${h1_fe1_sock} {
|
||||
txreq -req GET -url /404
|
||||
rxresp
|
||||
expect resp.status == 404
|
||||
expect resp.http.x-err-type == "errors-1"
|
||||
} -run
|
||||
client c1r4 -connect ${h1_fe1_sock} {
|
||||
txreq -req GET -url /500
|
||||
rxresp
|
||||
expect resp.status == 500
|
||||
expect resp.http.x-err-type == "default"
|
||||
} -run
|
|
@ -1335,9 +1335,12 @@ struct http_reply *http_parse_http_reply(const char **args, int *orig_arg, struc
|
|||
reply->type = HTTP_REPLY_EMPTY;
|
||||
reply->status = default_status;
|
||||
|
||||
cap = ((px->conf.args.ctx == ARGC_HRQ)
|
||||
? ((px->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR)
|
||||
: ((px->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR));
|
||||
if (px->conf.args.ctx == ARGC_HERR)
|
||||
cap = (SMP_VAL_REQUEST | SMP_VAL_RESPONSE);
|
||||
else
|
||||
cap = ((px->conf.args.ctx == ARGC_HRQ)
|
||||
? ((px->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR)
|
||||
: ((px->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR));
|
||||
|
||||
cur_arg = *orig_arg;
|
||||
while (*args[cur_arg]) {
|
||||
|
@ -1837,6 +1840,80 @@ static int proxy_parse_errorfiles(char **args, int section, struct proxy *curpx,
|
|||
goto out;
|
||||
}
|
||||
|
||||
/* Parses the "http-error" proxy keyword */
|
||||
static int proxy_parse_http_error(char **args, int section, struct proxy *curpx,
|
||||
struct proxy *defpx, const char *file, int line,
|
||||
char **errmsg)
|
||||
{
|
||||
struct conf_errors *conf_err;
|
||||
struct http_reply *reply = NULL;
|
||||
int rc, cur_arg, ret = 0;
|
||||
|
||||
if (warnifnotcap(curpx, PR_CAP_FE | PR_CAP_BE, file, line, args[0], NULL)) {
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cur_arg = 1;
|
||||
curpx->conf.args.ctx = ARGC_HERR;
|
||||
reply = http_parse_http_reply((const char **)args, &cur_arg, curpx, 0, errmsg);
|
||||
if (!reply) {
|
||||
memprintf(errmsg, "%s : %s", args[0], *errmsg);
|
||||
goto error;
|
||||
}
|
||||
else if (!reply->status) {
|
||||
memprintf(errmsg, "%s : expects at least a <status> as arguments.\n", args[0]);
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
|
||||
if (http_err_codes[rc] == reply->status)
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc >= HTTP_ERR_SIZE) {
|
||||
memprintf(errmsg, "%s: status code '%d' not handled.", args[0], reply->status);
|
||||
goto error;
|
||||
}
|
||||
if (*args[cur_arg]) {
|
||||
memprintf(errmsg, "%s : unknown keyword '%s'.", args[0], args[cur_arg]);
|
||||
goto error;
|
||||
}
|
||||
|
||||
conf_err = calloc(1, sizeof(*conf_err));
|
||||
if (!conf_err) {
|
||||
memprintf(errmsg, "%s : out of memory.", args[0]);
|
||||
goto error;
|
||||
}
|
||||
if (reply->type == HTTP_REPLY_ERRFILES) {
|
||||
int rc = http_get_status_idx(reply->status);
|
||||
|
||||
conf_err->type = 2;
|
||||
conf_err->info.errorfiles.name = reply->body.http_errors;
|
||||
conf_err->info.errorfiles.status[rc] = 2;
|
||||
reply->body.http_errors = NULL;
|
||||
release_http_reply(reply);
|
||||
}
|
||||
else {
|
||||
conf_err->type = 1;
|
||||
conf_err->info.errorfile.status = reply->status;
|
||||
conf_err->info.errorfile.reply = reply;
|
||||
LIST_ADDQ(&http_replies_list, &reply->list);
|
||||
}
|
||||
conf_err->file = strdup(file);
|
||||
conf_err->line = line;
|
||||
LIST_ADDQ(&curpx->conf.errors, &conf_err->list);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
|
||||
error:
|
||||
release_http_reply(reply);
|
||||
ret = -1;
|
||||
goto out;
|
||||
|
||||
}
|
||||
|
||||
/* Check "errorfiles" proxy keyword */
|
||||
static int proxy_check_errors(struct proxy *px)
|
||||
{
|
||||
|
@ -1849,6 +1926,10 @@ static int proxy_check_errors(struct proxy *px)
|
|||
/* errorfile */
|
||||
rc = http_get_status_idx(conf_err->info.errorfile.status);
|
||||
px->replies[rc] = conf_err->info.errorfile.reply;
|
||||
|
||||
/* For proxy, to rely on default replies, just don't reference a reply */
|
||||
if (px->replies[rc]->type == HTTP_REPLY_ERRMSG && !px->replies[rc]->body.errmsg)
|
||||
px->replies[rc] = NULL;
|
||||
}
|
||||
else {
|
||||
/* errorfiles */
|
||||
|
@ -2069,6 +2150,7 @@ static struct cfg_kw_list cfg_kws = {ILH, {
|
|||
{ CFG_LISTEN, "errorloc303", proxy_parse_errorloc },
|
||||
{ CFG_LISTEN, "errorfile", proxy_parse_errorfile },
|
||||
{ CFG_LISTEN, "errorfiles", proxy_parse_errorfiles },
|
||||
{ CFG_LISTEN, "http-error", proxy_parse_http_error },
|
||||
{ 0, NULL, NULL },
|
||||
}};
|
||||
|
||||
|
|
|
@ -310,6 +310,8 @@ static inline const char *fmt_directive(const struct proxy *curproxy)
|
|||
return "spoe-message";
|
||||
case ARGC_UBK:
|
||||
return "use_backend";
|
||||
case ARGC_HERR:
|
||||
return "http-error";
|
||||
default:
|
||||
return "undefined(please report this bug)"; /* must never happen */
|
||||
}
|
||||
|
|
|
@ -1132,6 +1132,7 @@ int smp_resolve_args(struct proxy *p)
|
|||
case ARGC_ACL: ctx = "ACL keyword"; break;
|
||||
case ARGC_SRV: where = "in server directive in"; break;
|
||||
case ARGC_SPOE: where = "in spoe-message directive in"; break;
|
||||
case ARGC_HERR: where = "in http-error directive in"; break;
|
||||
}
|
||||
|
||||
/* set a few default settings */
|
||||
|
|
Loading…
Reference in New Issue