]> granicus.if.org Git - apache/commitdiff
Merge r1769718, r1785943, r1786110, r1786119 from trunk:
authorJoe Orton <jorton@apache.org>
Thu, 31 May 2018 15:10:26 +0000 (15:10 +0000)
committerJoe Orton <jorton@apache.org>
Thu, 31 May 2018 15:10:26 +0000 (15:10 +0000)
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

CHANGES
STATUS
docs/manual/mod/core.xml
include/ap_mmn.h
include/http_config.h
server/config.c
server/core.c

diff --git a/CHANGES b/CHANGES
index 491845096adfe4b1c19d71bf1ff9b6fc3546b8ee..17338e34103451f5abfab41bf6291ada9ee750f5 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -61,6 +61,9 @@ Changes with Apache 2.4.34
 
   *) 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.
diff --git a/STATUS b/STATUS
index 17aaf3125b9f7dcd82c12335ded2b82d91dc2982..41ec51db66f534bf7752a6cfb611e92edeb470e1 100644 (file)
--- a/STATUS
+++ b/STATUS
@@ -192,6 +192,8 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK:
                   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
index 3d629dfd436512647c95dad0adac6063ea23bdcc..4da8fe4ee105b3ef675fe0e51e6f5c9b08b92222 100644 (file)
@@ -763,12 +763,12 @@ DefaultType None
 <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
@@ -2269,6 +2269,44 @@ if a test is true at startup</description>
 </usage>
 </directivesynopsis>
 
+<directivesynopsis type="section">
+<name>IfFile</name>
+<description>Encloses directives that will be processed only
+if file exists at startup</description>
+<syntax>&lt;IfFile [!]<var>parameter-name</var>&gt; ...
+    &lt;/IfFile&gt;</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>&lt;IfFile <var>filename</var>&gt;...&lt;/IfFile&gt;
+    </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
@@ -2326,6 +2364,110 @@ later.</compatibility>
 </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>&lt;IfDirective [!]<var>directive-name</var>&gt; ...
+    &lt;/IfDirective&gt;</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>&lt;IfDirective <var>test</var>&gt;...&lt;/IfDirective&gt;</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>&lt;IfSection [!]<var>section-name</var>&gt; ...
+    &lt;/IfSection&gt;</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>&lt;IfSection
+    <var>test</var>&gt;...&lt;/IfSection&gt;</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
+    "&lt;".  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 "&lt;".  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">
+&lt;IfSection VirtualHost&gt;
+   ...
+&lt;/IfSection&gt;
+    </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
index f57d64ad1b50202c83ea397154bdd21342787822..539fc1e119c0f9c481ef3520628c7b97346fd1bb 100644 (file)
  *                          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
index 9600dd3d626cca351e7f7239369fac0d0bee9d63..adc58252d3a7f758a11e600044f6e8f45b109364 100644 (file)
@@ -1014,6 +1014,14 @@ AP_DECLARE(const char *) ap_setup_prelinked_modules(process_rec *process);
  */
 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.
  */
index 7f1d50e08db983d4d38009d5770336c39e49d37e..f815b22d701e18ed277dd49f6d76e2a7dff89751 100644 (file)
@@ -2687,6 +2687,16 @@ AP_DECLARE(void) ap_show_modules(void)
         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;
index 5e9d6501bd423f079379ee792c972f7ae4f8d202..32d19e20adda0e42ef0797455ce15e9f23dc1288 100644 (file)
@@ -2710,18 +2710,23 @@ static module *find_module(server_rec *s, const char *name)
     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++;
@@ -2731,66 +2736,58 @@ static const char *start_ifmod(cmd_parms *cmd, void *mconfig, const char *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,
-                                      &current, &parent, "<IfModule");
+                                      &current, &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,
-                                      &current, &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 */
@@ -4306,10 +4303,21 @@ AP_INIT_RAW_ARGS("<LimitExcept", ap_limit_section, (void*)1,
                  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"),