add an <IfFile> config section like <IfDefine>
It allows a non httpd config file to be used as a marker directly in
httpd.conf without hiding logic in a script in front of apachectl
to do test -f and pass extra -D's.
This is something we've had in IBM's httpd distro for a little bit and
hadn't remembered to share. I've seen some questions/config files come
up in a few places lately that would benefit from this as an option.
Remove duplicate implementations of conditional section function. No
functional change.
* server/core.c (start_cond_section): Factor out from start_if*.
Adjust to use apr_strmemdup.
(test_ifmod_section, test_iffile_section, test_ifdefine_section):
Move container-specific tests into callbacks from start_if*.
(core_cmds): Adjust <IfFile, <IfDefine, <IfModule to use
start_cond_section with callbacks.
Add <IfDirective> and <IfSection>:
* server/core.c
(test_ifdirective_section, test_ifsection_section): New callbacks.
(core_cmds): Define new directives.
* include/http_config.h, server/config.c (ap_exists_directive):
New function.
* include/ap_mmn.h: Bump MMN minor for above.
* docs/manual/mod/core.xml: Add docs.
* server/core.c (start_cond_section): Comment & variable name fixes,
no functional change.
Submitted by: covener, jorton
Reviewed by: jorton, ylavic, covener
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@
1832623 13f79535-47bb-0310-9956-
ffa450edef68
*) mod_ssl: Fix cmake-based build. PR 62266. [Rainer Jung]
+ *) core: Add <IfFile>, <IfDirective> and <IfSection> conditional
+ section containers. [Eric Covener, Joe Orton]
+
Changes with Apache 2.4.33
*) core: Fix request timeout logging and possible crash for error_log hooks.
http://svn.apache.org/r1804531
2.4.x patch: https://svn.apache.org/repos/asf/httpd/httpd/patches/2.4.x/ssl-policy.patch
+1: icing
+ -0: jorton: some unused code paths and legacy of previous iterations still
+ included in patch? more at msgid <20180523075115.GA4654@redhat.com>
*) ap_rgetline()+mod_proxy_http: Add and handle AP_GETLINE_NOSPC_EOL flag,
fixes responses header thrown away on APR_ENOSPC, and allow their size to
<context>directory</context></contextlist>
<usage>
- <p>In its one parameter form, <directive>Define</directive> is equivalent
- to passing the <code>-D</code> argument to <program>httpd</program>. It
- can be used to toggle the use of
- <directive module="core" type="section">IfDefine</directive> sections
- without needing to alter <code>-D</code> arguments in any startup
- scripts.</p>
+ <p>In its one parameter form, <directive>Define</directive> is
+ equivalent to passing the <code>-D</code> argument to
+ <program>httpd</program>. It can be used to toggle the use of
+ <directive module="core" type="section">IfDefine</directive>
+ sections without needing to alter <code>-D</code> arguments in any
+ startup scripts.</p>
<p>In addition to that, if the second parameter is given, a config variable
is set to this value. The variable can be used in the configuration using
</usage>
</directivesynopsis>
+<directivesynopsis type="section">
+<name>IfFile</name>
+<description>Encloses directives that will be processed only
+if file exists at startup</description>
+<syntax><IfFile [!]<var>parameter-name</var>> ...
+ </IfFile></syntax>
+<contextlist><context>server config</context><context>virtual host</context>
+<context>directory</context><context>.htaccess</context>
+</contextlist>
+<compatibility>Available in 2.4.34 and later.</compatibility>
+
+<usage>
+ <p>The <code><IfFile <var>filename</var>>...</IfFile>
+ </code> section is used to mark directives that are conditional on
+ the existence of a file on disk. The directives within an
+ <directive type="section">IfFile</directive> section are only
+ processed if the <var>filename</var> exists. If <var> filename</var>
+ doesn't exist, everything between the start and end markers is
+ ignored. <var>filename</var> can be an absolute path or a path
+ relative to the server root.</p>
+
+ <p>The <var>filename</var> in the <directive type="section">IfFile
+ </directive> section directive can take the same forms as the
+ <var>test</var> variable in the <directive type="section">IfDefine
+ </directive> section, i.e. the test can be negated if the <code>
+ !</code> character is placed directly before <var>filename</var>.
+ </p>
+
+ <p>If a relative <var>filename</var> is supplied, the check is
+ <directive>ServerRoot</directive> relative. In the case where
+ this directive occurs before the <directive>ServerRoot</directive>,
+ the path will be checked relative to the compiled-in server root or
+ the server root passed in on the command line via the <code>-d</code>
+ parameter.</p>
+
+</usage>
+</directivesynopsis>
+
<directivesynopsis type="section">
<name>IfModule</name>
<description>Encloses directives that are processed conditional on the
</usage>
</directivesynopsis>
+<directivesynopsis type="section">
+<name>IfDirective</name>
+<description>Encloses directives that are processed conditional on the
+presence or absence of a specific directive</description>
+<syntax><IfDirective [!]<var>directive-name</var>> ...
+ </IfDirective></syntax>
+<contextlist><context>server config</context><context>virtual host</context>
+<context>directory</context><context>.htaccess</context>
+</contextlist>
+<override>All</override>
+<compatibility>Available in 2.4.34 and later.</compatibility>
+
+<usage>
+ <p>The <code><IfDirective <var>test</var>>...</IfDirective></code>
+ section is used to mark directives that are conditional on the presence of
+ a specific directive. The directives within an <directive type="section"
+ >IfDirective</directive> section are only processed if the <var>test</var>
+ is true. If <var>test</var> is false, everything between the start and
+ end markers is ignored.</p>
+
+ <p>The <var>test</var> in the <directive type="section"
+ >IfDirective</directive> section can be one of two forms:</p>
+
+ <ul>
+ <li><var>directive-name</var></li>
+
+ <li>!<var>directive-name</var></li>
+ </ul>
+
+ <p>In the former case, the directives between the start and end
+ markers are only processed if a directive of the given name is
+ available at the time of processing. The second format reverses the test,
+ and only processes the directives if the <var>directive-name</var> is
+ <strong>not</strong> defined.</p>
+
+ <note>This section should only be used if you need to have one
+ configuration file that works across multiple versions of
+ <program>httpd</program>, regardless of whether a particular
+ directive is available. In normal operation, directives need not
+ be placed in <directive type="section">IfDirective</directive>
+ sections.</note>
+</usage>
+<seealso><directive module="core" type="section">IfSection</directive></seealso>
+</directivesynopsis>
+
+<directivesynopsis type="section">
+<name>IfSection</name>
+<description>Encloses directives that are processed conditional on the
+presence or absence of a specific section directive</description>
+<syntax><IfSection [!]<var>section-name</var>> ...
+ </IfSection></syntax>
+<contextlist><context>server config</context><context>virtual host</context>
+<context>directory</context><context>.htaccess</context>
+</contextlist>
+<override>All</override>
+<compatibility>Available in 2.4.34 and later.</compatibility>
+
+<usage>
+ <p>The <code><IfSection
+ <var>test</var>>...</IfSection></code> section is used
+ to mark directives that are conditional on the presence of a
+ specific section directive. A section directive is any directive
+ such as <directive type="section">virtualhost</directive> which
+ encloses other directives, and has a directive name with a leading
+ "<". The sec
+
+ The directives within an <directive type="section"
+ >IfSection</directive> section are only processed if the <var>test</var>
+ is true. If <var>test</var> is false, everything between the start and
+ end markers is ignored.</p>
+
+ <p>The <var>section-name</var> specified must not include the
+ leading "<". The <var>test</var> in the <directive
+ type="section">IfSection</directive> section can be one of two
+ forms:</p>
+
+ <ul>
+ <li><var>section-name</var></li>
+ <li>!<var>section-name</var></li>
+ </ul>
+
+ <p>In the former case, the directives between the start and
+ end markers are only processed if a section directive of the given
+ name is available at the time of processing. The second format
+ reverses the test, and only processes the directives if the
+ <var>section-name</var> is <strong>not</strong> defined.</p>
+
+ <p>For example:</p>
+
+ <highlight language="config">
+<IfSection VirtualHost>
+ ...
+</IfSection>
+ </highlight>
+
+ <note>This section should only be used if you need to have one
+ configuration file that works across multiple versions of <program>httpd</program>,
+ regardless of whether a particular section directive is
+ available. In normal operation, directives need not be placed in
+ <directive type="section">IfSection</directive> sections.</note>
+</usage>
+<seealso><directive module="core" type="section">IfDirective</directive></seealso>
+</directivesynopsis>
+
<directivesynopsis>
<name>Include</name>
<description>Includes other configuration files from within
* ap_regcomp_default_cflag_by_name
* 20120211.75 (2.4.30-dev) Add hostname_ex to proxy_worker_shared
* 20120211.76 (2.4.30-dev) Add CONN_STATE_NUM to enum conn_state_e
+ * 20120211.77 (2.4.34-dev) add ap_exists_directive()
*/
#define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */
#ifndef MODULE_MAGIC_NUMBER_MAJOR
#define MODULE_MAGIC_NUMBER_MAJOR 20120211
#endif
-#define MODULE_MAGIC_NUMBER_MINOR 76 /* 0...n */
+#define MODULE_MAGIC_NUMBER_MINOR 77 /* 0...n */
/**
* Determine if the server's current MODULE_MAGIC_NUMBER is at least a
*/
AP_DECLARE(void) ap_show_directives(void);
+/**
+ * Returns non-zero if a configuration directive of the given name has
+ * been registered by a module at the time of calling.
+ * @param p Pool for temporary allocations
+ * @param name Directive name
+ */
+AP_DECLARE(int) ap_exists_directive(apr_pool_t *p, const char *name);
+
/**
* Show the preloaded module names. Used for httpd -l.
*/
printf(" %s\n", ap_loaded_modules[n]->name);
}
+AP_DECLARE(int) ap_exists_directive(apr_pool_t *p, const char *name)
+{
+ char *lname = apr_pstrdup(p, name);
+
+ ap_str_tolower(lname);
+
+ return ap_config_hash &&
+ apr_hash_get(ap_config_hash, lname, APR_HASH_KEY_STRING) != NULL;
+}
+
AP_DECLARE(void *) ap_retained_data_get(const char *key)
{
void *retained;
return found;
}
+/* Callback function type used by start_cond_section. */
+typedef int (*test_cond_section_fn)(cmd_parms *cmd, const char *arg);
-static const char *start_ifmod(cmd_parms *cmd, void *mconfig, const char *arg)
+/* Implementation of <IfXXXXX>-style conditional sections. Callback
+ * to test condition must be in cmd->info, matching function type
+ * test_cond_section_fn. */
+static const char *start_cond_section(cmd_parms *cmd, void *mconfig, const char *arg)
{
const char *endp = ap_strrchr_c(arg, '>');
- int not = (arg[0] == '!');
- module *found;
+ int result, not = (arg[0] == '!');
+ test_cond_section_fn testfn = (test_cond_section_fn)cmd->info;
if (endp == NULL) {
return unclosed_directive(cmd);
}
- arg = apr_pstrndup(cmd->temp_pool, arg, endp - arg);
+ arg = apr_pstrmemdup(cmd->temp_pool, arg, endp - arg);
if (not) {
arg++;
return missing_container_arg(cmd);
}
- found = find_module(cmd->server, arg);
+ result = testfn(cmd, arg);
- if ((!not && found) || (not && !found)) {
+ if ((!not && result) || (not && !result)) {
ap_directive_t *parent = NULL;
ap_directive_t *current = NULL;
const char *retval;
retval = ap_build_cont_config(cmd->pool, cmd->temp_pool, cmd,
- ¤t, &parent, "<IfModule");
+ ¤t, &parent, (char *)cmd->cmd->name);
*(ap_directive_t **)mconfig = current;
return retval;
}
else {
*(ap_directive_t **)mconfig = NULL;
- return ap_soak_end_container(cmd, "<IfModule");
+ return ap_soak_end_container(cmd, (char *)cmd->cmd->name);
}
}
+/* Callback to implement <IfModule> test for start_cond_section. */
+static int test_ifmod_section(cmd_parms *cmd, const char *arg)
+{
+ return find_module(cmd->server, arg) != NULL;
+}
+
AP_DECLARE(int) ap_exists_config_define(const char *name)
{
return ap_array_str_contains(ap_server_config_defines, name);
}
-static const char *start_ifdefine(cmd_parms *cmd, void *dummy, const char *arg)
+static int test_ifdefine_section(cmd_parms *cmd, const char *arg)
{
- const char *endp;
- int defined;
- int not = 0;
-
- endp = ap_strrchr_c(arg, '>');
- if (endp == NULL) {
- return unclosed_directive(cmd);
- }
-
- arg = apr_pstrndup(cmd->temp_pool, arg, endp - arg);
+ return ap_exists_config_define(arg);
+}
- if (arg[0] == '!') {
- not = 1;
- arg++;
- }
+static int test_iffile_section(cmd_parms *cmd, const char *arg)
+{
+ const char *relative;
+ apr_finfo_t sb;
- if (!arg[0]) {
- return missing_container_arg(cmd);
- }
+ relative = ap_server_root_relative(cmd->temp_pool, arg);
+ return (apr_stat(&sb, relative, 0, cmd->pool) == APR_SUCCESS);
+}
- defined = ap_exists_config_define(arg);
- if ((!not && defined) || (not && !defined)) {
- ap_directive_t *parent = NULL;
- ap_directive_t *current = NULL;
- const char *retval;
+static int test_ifdirective_section(cmd_parms *cmd, const char *arg)
+{
+ return ap_exists_directive(cmd->temp_pool, arg);
+}
- retval = ap_build_cont_config(cmd->pool, cmd->temp_pool, cmd,
- ¤t, &parent, "<IfDefine");
- *(ap_directive_t **)dummy = current;
- return retval;
- }
- else {
- *(ap_directive_t **)dummy = NULL;
- return ap_soak_end_container(cmd, "<IfDefine");
- }
+static int test_ifsection_section(cmd_parms *cmd, const char *arg)
+{
+ const char *name = apr_pstrcat(cmd->temp_pool, "<", arg, NULL);
+ return ap_exists_directive(cmd->temp_pool, name);
}
/* httpd.conf commands... beginning with the <VirtualHost> business */
OR_LIMIT | OR_AUTHCFG,
"Container for authentication directives to be applied when any HTTP "
"method other than those specified is used to access the resource"),
-AP_INIT_TAKE1("<IfModule", start_ifmod, NULL, EXEC_ON_READ | OR_ALL,
+AP_INIT_TAKE1("<IfModule", start_cond_section, (void *)test_ifmod_section,
+ EXEC_ON_READ | OR_ALL,
"Container for directives based on existence of specified modules"),
-AP_INIT_TAKE1("<IfDefine", start_ifdefine, NULL, EXEC_ON_READ | OR_ALL,
+AP_INIT_TAKE1("<IfDefine", start_cond_section, (void *)test_ifdefine_section,
+ EXEC_ON_READ | OR_ALL,
"Container for directives based on existence of command line defines"),
+AP_INIT_TAKE1("<IfFile", start_cond_section, (void *)test_iffile_section,
+ EXEC_ON_READ | OR_ALL,
+ "Container for directives based on existence of files on disk"),
+AP_INIT_TAKE1("<IfDirective", start_cond_section, (void *)test_ifdirective_section,
+ EXEC_ON_READ | OR_ALL,
+ "Container for directives based on existence of named directive"),
+AP_INIT_TAKE1("<IfSection", start_cond_section, (void *)test_ifsection_section,
+ EXEC_ON_READ | OR_ALL,
+ "Container for directives based on existence of named section"),
AP_INIT_RAW_ARGS("<DirectoryMatch", dirsection, (void*)1, RSRC_CONF,
"Container for directives affecting resources located in the "
"specified directories"),