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 d9c3052..4c49b25 100644
--- a/include/types/http_htx.h
+++ b/include/types/http_htx.h
@@ -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 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 98a62bd..e848e37 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 @@
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 @@
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);
@@ -1119,6 +1128,89 @@
out:
return ret;
+}
+
+/*
+ * 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, {
@@ -1131,6 +1223,8 @@
INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
+REGISTER_CONFIG_SECTION("http-errors", cfg_parse_http_errors, NULL);
+
/************************************************************************/
/* HTX sample fetches */
/************************************************************************/