]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: http-htx: Add a new section to create groups of custom HTTP errors
authorChristopher Faulet <cfaulet@haproxy.com>
Wed, 15 Jan 2020 10:22:56 +0000 (11:22 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Mon, 20 Jan 2020 14:18:46 +0000 (15:18 +0100)
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.

include/types/http_htx.h
src/http_htx.c

index d9c3052f97edca3c3f17eeaa38a7e8033abdd0ee..4c49b257423d0867ddd5d3eed3168806597c28c0 100644 (file)
@@ -26,6 +26,7 @@
 #include <ebistree.h>
 
 #include <common/buf.h>
+#include <common/http.h>
 #include <common/htx.h>
 #include <common/ist.h>
 
@@ -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 */
index 98a62bdc93bec98e591bfce104f2e5e9ce06aefe..e848e37e84d15c4260cb20702e47063fda57ad00 100644 (file)
@@ -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 <http-errors> 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 <status_code> and <file> 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                       */
 /************************************************************************/