From: Christopher Faulet Date: Wed, 15 Jan 2020 10:22:56 +0000 (+0100) Subject: MINOR: http-htx: Add a new section to create groups of custom HTTP errors X-Git-Tag: v2.2-dev1~24 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=35cd81d363f0ba7947d78ccaae0f54b0e74fcf23;p=thirdparty%2Fhaproxy.git MINOR: http-htx: Add a new section to create groups of custom HTTP errors A new section may now be declared in the configuration to create global groups of HTTP errors. These groups are not linked to a proxy and are referenced by name. The section must be declared using the keyword "http-errors" followed by the group name. This name must be unique. A list of "errorfile" directives may be declared in such section. For instance: http-errors website-1 errorfile 400 /path/to/site1/400.http errorfile 404 /path/to/site1/404.http http-errors website-2 errorfile 400 /path/to/site2/400.http errorfile 404 /path/to/site2/404.http For now, it is just possible to create "http-errors" sections. There is no documentation because these groups are not used yet. --- diff --git a/include/types/http_htx.h b/include/types/http_htx.h index d9c3052f97..4c49b25742 100644 --- a/include/types/http_htx.h +++ b/include/types/http_htx.h @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -45,4 +46,16 @@ struct http_error { struct ebpt_node node; }; +/* http-errors section and parameters. */ +struct http_errors { + char *id; /* unique identifier */ + struct { + char *file; /* file where the section appears */ + int line; /* line where the section appears */ + } conf; /* config information */ + + struct buffer *errmsg[HTTP_ERR_SIZE]; /* customized error messages for known errors */ + struct list list; /* http-errors list */ +}; + #endif /* _TYPES_HTTP_HTX_H */ diff --git a/src/http_htx.c b/src/http_htx.c index 98a62bdc93..e848e37e84 100644 --- a/src/http_htx.c +++ b/src/http_htx.c @@ -30,6 +30,7 @@ struct buffer http_err_chunks[HTTP_ERR_SIZE]; struct eb_root http_error_messages = EB_ROOT; +struct list http_errors_list = LIST_HEAD_INIT(http_errors_list); static int http_update_authority(struct htx *htx, struct htx_sl *sl, const struct ist host); static int http_update_host(struct htx *htx, struct htx_sl *sl, const struct ist uri); @@ -839,6 +840,7 @@ end: static void http_htx_deinit(void) { + struct http_errors *http_errs, *http_errsb; struct ebpt_node *node, *next; struct http_error *http_err; @@ -852,6 +854,13 @@ static void http_htx_deinit(void) free(http_err); node = next; } + + list_for_each_entry_safe(http_errs, http_errsb, &http_errors_list, list) { + free(http_errs->conf.file); + free(http_errs->id); + LIST_DEL(&http_errs->list); + free(http_errs); + } } REGISTER_CONFIG_POSTPARSER("http_htx", http_htx_init); @@ -1121,6 +1130,89 @@ static int proxy_parse_errorfile(char **args, int section, struct proxy *curpx, } +/* + * Parse an section. + * Returns the error code, 0 if OK, or any combination of : + * - ERR_ABORT: must abort ASAP + * - ERR_FATAL: we can continue parsing but not start the service + * - ERR_WARN: a warning has been emitted + * - ERR_ALERT: an alert has been emitted + * Only the two first ones can stop processing, the two others are just + * indicators. + */ +static int cfg_parse_http_errors(const char *file, int linenum, char **args, int kwm) +{ + static struct http_errors *curr_errs = NULL; + int err_code = 0; + const char *err; + char *errmsg = NULL; + + if (strcmp(args[0], "http-errors") == 0) { /* new errors section */ + if (!*args[1]) { + ha_alert("parsing [%s:%d] : missing name for http-errors section.\n", file, linenum); + err_code |= ERR_ALERT | ERR_ABORT; + goto out; + } + + err = invalid_char(args[1]); + if (err) { + ha_alert("parsing [%s:%d] : character '%c' is not permitted in '%s' name '%s'.\n", + file, linenum, *err, args[0], args[1]); + err_code |= ERR_ALERT | ERR_FATAL; + } + + list_for_each_entry(curr_errs, &http_errors_list, list) { + /* Error if two errors section owns the same name */ + if (strcmp(curr_errs->id, args[1]) == 0) { + ha_alert("parsing [%s:%d]: http-errors section '%s' already exists (declared at %s:%d).\n", + file, linenum, args[1], curr_errs->conf.file, curr_errs->conf.line); + err_code |= ERR_ALERT | ERR_FATAL; + } + } + + if ((curr_errs = calloc(1, sizeof(*curr_errs))) == NULL) { + ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum); + err_code |= ERR_ALERT | ERR_ABORT; + goto out; + } + + LIST_ADDQ(&http_errors_list, &curr_errs->list); + curr_errs->id = strdup(args[1]); + curr_errs->conf.file = strdup(file); + curr_errs->conf.line = linenum; + } + else if (!strcmp(args[0], "errorfile")) { /* error message from a file */ + struct buffer *msg; + int status, rc; + + if (*(args[1]) == 0 || *(args[2]) == 0) { + ha_alert("parsing [%s:%d] : %s: expects and as arguments.\n", + file, linenum, args[0]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + + status = atol(args[1]); + msg = http_parse_errorfile(status, args[2], &errmsg); + if (!msg) { + ha_alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + rc = http_get_status_idx(status); + curr_errs->errmsg[rc] = msg; + } + else if (*args[0] != 0) { + ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], cursection); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + +out: + free(errmsg); + return err_code; +} + static struct cfg_kw_list cfg_kws = {ILH, { { CFG_LISTEN, "errorloc", proxy_parse_errorloc }, { CFG_LISTEN, "errorloc302", proxy_parse_errorloc }, @@ -1131,6 +1223,8 @@ static struct cfg_kw_list cfg_kws = {ILH, { INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws); +REGISTER_CONFIG_SECTION("http-errors", cfg_parse_http_errors, NULL); + /************************************************************************/ /* HTX sample fetches */ /************************************************************************/