Skip to content

Commit f0e9534

Browse files
Alan M. Carrollshinrich
authored andcommitted
Extend body factory templates to have a default per custom template set. (apache#399)
YTSATS-473 Cherry-pick 335543a
1 parent 60c2298 commit f0e9534

File tree

2 files changed

+38
-23
lines changed

2 files changed

+38
-23
lines changed

doc/admin-guide/monitoring/error-messages.en.rst

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -145,18 +145,22 @@ is provided in :ref:`appendix-http-status-codes`.
145145

146146
The error messages can be customized. The actual response is generated from a template. These
147147
templates are stored in files which means the errors responses can be customized by modifying these
148-
files. The default directory for the template files is ``PREFIX/body_factory/default``
149-
but this can be changed by the configuration variable
150-
:ts:cv:`proxy.config.body_factory.template_sets_dir`. All files in this directory are added to a
151-
lookup table which is consulted when the error message is generated. The name used for lookup is by
152-
default that listed in the :ref:`following table <body-factory-error-table>`. It can be overridden by
148+
files. The default directory for the template files is ``PREFIX/body_factory/default`` but this can
149+
be changed by the configuration variable :ts:cv:`proxy.config.body_factory.template_sets_dir`. All
150+
files in this directory are added to a lookup table which is consulted when the error message is
151+
generated. The name used for lookup is by default that listed in the :ref:`following table
152+
<body-factory-error-table>`. It can be overridden by
153153
:ts:cv:`proxy.config.body_factory.template_base` which, if set, is a string that is prepended to the
154154
search name along with an underscore. For example, if the default lookup name is
155155
``cache#read_error`` then by default the response will be generated from the template in the file
156-
named ``cache#read_error``. If the template base name were set to "apache" then the lookup would
156+
named ``cache#read_error``. If the template base name were set to ``apache`` then the lookup would
157157
look for a file named ``apache_cache#read_error`` in the template table. This can be used to switch
158158
out error message sets or, because this variable is overridable, to select an error message set
159-
based on data in the transaction.
159+
based on data in the transaction. In addition the suffix ``_default`` has a special meaning. If
160+
there is a file with the base name and that suffix it is used as the default error page for the base
161+
set, instead of falling back to the global (built in) default page in the case where there is not a
162+
file that matches the specific error. In the example case, if the file ``apache_default`` exists
163+
it would be used instead of ``cache#read_error`` if there is no ``apache_cache#read_error``.
160164

161165
The text for an error message is processed as if it were a :ref:`admin-logging-fields` which
162166
enables customization by values present in the transaction for which the error occurred.

proxy/http/HttpBodyFactory.cc

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ HttpBodyFactory::fabricate_with_old_api(const char *type, HttpTransact::State *c
107107
Log::error("BODY_FACTORY: suppressing '%s' response for url '%s'", type, url);
108108
}
109109
unlock();
110-
return (nullptr);
110+
return nullptr;
111111
}
112112
//////////////////////////////////////////////////////////////////////////////////
113113
// if language-targeting activated, get client Accept-Language & Accept-Charset //
@@ -400,7 +400,7 @@ HttpBodyFactory::fabricate(StrList *acpt_language_list, StrList *acpt_charset_li
400400
char *buffer;
401401
const char *pType = context->txn_conf->body_factory_template_base;
402402
const char *set;
403-
HttpBodyTemplate *t;
403+
HttpBodyTemplate *t = NULL;
404404
HttpBodySet *body_set;
405405
char template_base[PATH_NAME_MAX];
406406

@@ -416,12 +416,12 @@ HttpBodyFactory::fabricate(StrList *acpt_language_list, StrList *acpt_charset_li
416416
// if error body suppressed, return NULL
417417
if (is_response_suppressed(context)) {
418418
Debug("body_factory", " error suppression enabled, returning NULL template");
419-
return (nullptr);
419+
return nullptr;
420420
}
421421
// if custom error pages are disabled, return NULL
422422
if (!enable_customizations) {
423423
Debug("body_factory", " customization disabled, returning NULL template");
424-
return (nullptr);
424+
return nullptr;
425425
}
426426

427427
// what set should we use (language target if enable_customizations == 2)
@@ -437,25 +437,30 @@ HttpBodyFactory::fabricate(StrList *acpt_language_list, StrList *acpt_charset_li
437437
}
438438
if (pType != nullptr && 0 != *pType && 0 != strncmp(pType, "NONE", 4)) {
439439
sprintf(template_base, "%s_%s", pType, type);
440-
} else {
441-
sprintf(template_base, "%s", type);
440+
t = find_template(set, template_base, &body_set);
441+
// Check for default alternate.
442+
if (t == nullptr) {
443+
sprintf(template_base, "%s_default", pType);
444+
t = find_template(set, template_base, &body_set);
445+
}
442446
}
443-
// see if we have a custom error page template
444-
t = find_template(set, template_base, &body_set);
447+
448+
// Check for base customizations if specializations didn't work.
445449
if (t == nullptr) {
446450
t = find_template(set, type, &body_set); // this executes if the template_base is wrong and doesn't exist
447451
}
452+
448453
if (t == nullptr) {
449454
Debug("body_factory", " can't find template, returning NULL template");
450-
return (nullptr);
455+
return nullptr;
451456
}
452457

453458
*content_language_return = body_set->content_language;
454459
*content_charset_return = body_set->content_charset;
455460

456461
// build the custom error page
457462
buffer = t->build_instantiated_buffer(context, buffer_length_return);
458-
return (buffer);
463+
return buffer;
459464
}
460465

461466
// LOCKING: must be called with lock taken
@@ -692,8 +697,9 @@ HttpBodyFactory::load_body_set_from_directory(char *set_name, char *tmpl_dir)
692697
DIR *dir;
693698
int status;
694699
struct stat stat_buf;
695-
char path[MAXPATHLEN + 1];
696700
struct dirent *dirEntry;
701+
char path[MAXPATHLEN + 1];
702+
static const char BASED_DEFAULT[] = "_default";
697703

698704
////////////////////////////////////////////////
699705
// ensure we can open tmpl_dir as a directory //
@@ -702,7 +708,7 @@ HttpBodyFactory::load_body_set_from_directory(char *set_name, char *tmpl_dir)
702708
Debug("body_factory", " load_body_set_from_directory(%s)", tmpl_dir);
703709
dir = opendir(tmpl_dir);
704710
if (dir == nullptr) {
705-
return (nullptr);
711+
return nullptr;
706712
}
707713

708714
/////////////////////////////////////////////
@@ -713,7 +719,7 @@ HttpBodyFactory::load_body_set_from_directory(char *set_name, char *tmpl_dir)
713719
status = stat(path, &stat_buf);
714720
if ((status < 0) || !S_ISREG(stat_buf.st_mode)) {
715721
closedir(dir);
716-
return (nullptr);
722+
return nullptr;
717723
}
718724
Debug("body_factory", " found '%s'", path);
719725

@@ -729,14 +735,19 @@ HttpBodyFactory::load_body_set_from_directory(char *set_name, char *tmpl_dir)
729735

730736
while ((dirEntry = readdir(dir))) {
731737
HttpBodyTemplate *tmpl;
738+
size_t d_len = strlen(dirEntry->d_name);
732739

733740
///////////////////////////////////////////////////////////////
734-
// all template files have name of the form <type>#<subtype> //
741+
// all template files must have a file name of the form //
742+
// - <type>#<subtype> //
743+
// - <base>_<type>#<subtype> //
744+
// - <base>_default [based default] //
745+
// - default [global default] //
735746
///////////////////////////////////////////////////////////////
736747

737-
if ((strchr(dirEntry->d_name, '#') == nullptr) && (strcmp(dirEntry->d_name, "default") != 0)) {
748+
if (!(nullptr != strchr(dirEntry->d_name, '#') || (0 == strcmp(dirEntry->d_name, "default")) ||
749+
(d_len >= sizeof(BASED_DEFAULT) && 0 == strcmp(dirEntry->d_name + d_len - (sizeof(BASED_DEFAULT) - 1), BASED_DEFAULT))))
738750
continue;
739-
}
740751

741752
snprintf(path, sizeof(path), "%s/%s", tmpl_dir, dirEntry->d_name);
742753
status = stat(path, &stat_buf);

0 commit comments

Comments
 (0)