On Wed, Feb 22, 2017 at 10:00:08PM +0100, Yann Ylavic wrote:
> On Wed, Feb 22, 2017 at 11:47 AM, Joe Orton <[email protected]> wrote:
> > (b) for <IfDirective foo> match both "foo" and "<foo".
>
> I'd vote for this, it's very unlikely that some day we want to add a
> directive called VirtualHost or If (w/o the leading '<') which may
> conflict here, so it shouldn't hurt.
I'm fine with that, I'll commit like this unless anybody else has strong
opinions.
Regards, Joe
Index: server/config.c
===================================================================
--- server/config.c (revision 1784534)
+++ server/config.c (working copy)
@@ -2668,6 +2668,24 @@
printf(" %s\n", ap_loaded_modules[n]->name);
}
+AP_DECLARE(int) ap_exists_directive(apr_pool_t *p, const char *name)
+{
+ char *lname;
+
+ if (!ap_config_hash)
+ return 0;
+
+ lname = apr_pstrdup(p, name);
+ ap_str_tolower(lname);
+
+ if (apr_hash_get(ap_config_hash, lname, APR_HASH_KEY_STRING) != NULL)
+ return 1;
+
+ /* Try '<'-prefixed form. */
+ return apr_hash_get(ap_config_hash, apr_pstrcat(p, "<", lname, NULL),
+ APR_HASH_KEY_STRING) != NULL;
+ }
+
AP_DECLARE(void *) ap_retained_data_get(const char *key)
{
void *retained;
Index: include/http_config.h
===================================================================
--- include/http_config.h (revision 1784534)
+++ include/http_config.h (working copy)
@@ -992,6 +992,15 @@
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 Temporary pool
+ * @param name Directive name to match, case-insensitively, either
+ * directly or against '<'-prefixed container form.
+ */
+AP_DECLARE(int) ap_exists_directive(apr_pool_t *p, const char *name);
+
+/**
* Show the preloaded module names. Used for httpd -l.
*/
AP_DECLARE(void) ap_show_modules(void);
Index: server/core.c
===================================================================
--- server/core.c (revision 1784534)
+++ server/core.c (working copy)
@@ -2894,6 +2894,46 @@
}
}
+
+static const char *start_ifdirective(cmd_parms *cmd, void *dummy, 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_pstrmemdup(cmd->temp_pool, arg, endp - arg);
+
+ if (arg[0] == '!') {
+ not = 1;
+ arg++;
+ }
+
+ if (!arg[0]) {
+ return missing_container_arg(cmd);
+ }
+
+ defined = ap_exists_directive(cmd->temp_pool, arg);
+ if ((!not && defined) || (not && !defined)) {
+ 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, "<IfDirective");
+ *(ap_directive_t **)dummy = current;
+ return retval;
+ }
+ else {
+ *(ap_directive_t **)dummy = NULL;
+ return ap_soak_end_container(cmd, "<IfDirective");
+ }
+}
+
/* httpd.conf commands... beginning with the <VirtualHost> business */
static const char *virtualhost_section(cmd_parms *cmd, void *dummy,
@@ -4509,6 +4549,8 @@
"Container for directives based on existence of command line defines"),
AP_INIT_TAKE1("<IfFile", start_iffile, NULL, EXEC_ON_READ | OR_ALL,
"Container for directives based on existence of files on disk"),
+AP_INIT_TAKE1("<IfDirective", start_ifdirective, NULL, EXEC_ON_READ | OR_ALL,
+ "Container for directives based on existence of named directive"),
AP_INIT_RAW_ARGS("<DirectoryMatch", dirsection, (void*)1, RSRC_CONF,
"Container for directives affecting resources located in the "
"specified directories"),