Changes with Apache 2.3.13
+ *) core: Add <ElseIf> and <Else> to complement <If> sections.
+ [Stefan Fritsch]
+
*) mod_ext_filter: Remove DebugLevel option in favor of per-module loglevel.
[Stefan Fritsch]
</p>
</summary>
-<seealso><directive module="core">If</directive></seealso>
+<seealso><directive module="core" type="section">If</directive></seealso>
+<seealso><directive module="core" type="section">ElseIf</directive></seealso>
+<seealso><directive module="core" type="section">Else</directive></seealso>
<seealso><directive module="mod_rewrite">RewriteCond</directive></seealso>
<seealso><directive module="mod_setenvif">SetEnvIfExpr</directive></seealso>
<seealso><directive module="mod_filter">FilterProvider</directive></seealso>
Locations</a></seealso>
</directivesynopsis>
+<directivesynopsis type="section">
+<name>Else</name>
+<description>Contains directives that apply only if the condition of a
+previous <directive type="section" module="core">If</directive> or
+<directive type="section" module="core">ElseIf</directive> section is not
+satisfied by a request at runtime</description>
+<syntax><Else> ... </Else></syntax>
+<contextlist><context>server config</context><context>virtual host</context>
+<context>directory</context><context>.htaccess</context>
+</contextlist>
+<override>All</override>
+
+<usage>
+ <p>The <directive type="section">Else</directive> applies the enclosed
+ directives if and only if the most recent
+ <directive type="section">If</directive> or
+ <directive type="section">ElseIf</directive> section
+ in the same scope has not been applied.
+ For example: In </p>
+
+ <example>
+ <If "-z req('Host')"><br/>
+ ...<br/>
+ </If><br/>
+ <Else><br/>
+ ...<br/>
+ </Else><br/>
+ </example>
+
+ <p> The <directive type="section">If</directive> would match HTTP/1.0
+ requests without a <var>Host:</var> header and the
+ <directive type="section">Else</directive> would match requests
+ with a <var>Host:</var> header.</p>
+
+</usage>
+<seealso><directive type="section" module="core">If</directive></seealso>
+<seealso><directive type="section" module="core">ElseIf</directive></seealso>
+<seealso><a href="../sections.html">How <Directory>, <Location>,
+ <Files> sections work</a> for an explanation of how these
+ different sections are combined when a request is received.
+ <directive type="section">If</directive>,
+ <directive type="section">ElseIf</directive>, and
+ <directive type="section">Else</directive> are applied last.</seealso>
+</directivesynopsis>
+
+<directivesynopsis type="section">
+<name>ElseIf</name>
+<description>Contains directives that apply only if a condition is satisfied
+by a request at runtime while the condition of a previous
+<directive type="section" module="core">If</directive> or
+<directive type="section">ElseIf</directive> section is not
+satisfied</description>
+<syntax><ElseIf <var>expression</var>> ... </ElseIf></syntax>
+<contextlist><context>server config</context><context>virtual host</context>
+<context>directory</context><context>.htaccess</context>
+</contextlist>
+<override>All</override>
+
+<usage>
+ <p>The <directive type="section">ElseIf</directive> applies the enclosed
+ directives if and only if both the given condition evaluates to true and
+ the most recent <directive type="section">If</directive> or
+ <directive type="section">ElseIf</directive> section in the same scope has
+ not been applied. For example: In </p>
+
+ <example>
+ <If "-R '10.1.0.0/16'"><br/>
+ ...<br/>
+ </If><br/>
+ <ElseIf "-R '10.0.0.0/8'"><br/>
+ ...<br/>
+ </ElseIf><br/>
+ <Else><br/>
+ ...<br/>
+ </Else><br/>
+ </example>
+
+ <p>The <directive type="section">ElseIf</directive> would match if
+ the remote address of a request belongs to the subnet 10.0.0.0/8 but
+ not to the subnet 10.1.0.0/16.</p>
+
+</usage>
+<seealso><a href="../expr.html">Expressions in Apache HTTP Server</a>,
+for a complete reference and more examples.</seealso>
+<seealso><directive type="section" module="core">If</directive></seealso>
+<seealso><directive type="section" module="core">Else</directive></seealso>
+<seealso><a href="../sections.html">How <Directory>, <Location>,
+ <Files> sections work</a> for an explanation of how these
+ different sections are combined when a request is received.
+ <directive type="section">If</directive>,
+ <directive type="section">ElseIf</directive>, and
+ <directive type="section">Else</directive> are applied last.</seealso>
+</directivesynopsis>
+
+
+
<directivesynopsis>
<name>EnableMMAP</name>
<description>Use memory-mapping to read files during delivery</description>
For example:</p>
<example>
- <If "$req{Host} = ''">
+ <If "-z req('Host')">
</example>
- <p>would match HTTP/1.0 requests without a <var>Host:</var> header.</p>
-
- <p>You may compare the value of any variable in the request headers
- ($req), response headers ($resp) or environment ($env) in your
- expression.</p>
-
- <p>Apart from <code>=</code>, <code>If</code> can use the <code>IN</code>
- operator to compare if the expression is in a given range:</p>
+ <p>would match HTTP/1.0 requests without a <var>Host:</var> header.
+ Expressions may contain various shell-like operators for string
+ comparison (<code>=</code>, <code>!=</code>, <code><</code>, ...),
+ integer comparison (<code>-eq</code>, <code>-ne</code>, ...),
+ and others (<code>-n</code>, <code>-z</code>, <code>-f</code>, ...).
+ It is also possible to use regular expressions, </p>
<example>
- <If %{REQUEST_METHOD} IN GET,HEAD,OPTIONS>
+ <If "%{QUERY_STRING =~ /(delete|commit)=.*?elem/">
</example>
+ <p>shell-like pattern matches and many other operations. These operations
+ can be done on request headers (<code>req</code>), environment variables
+ (<code>env</code>), and a large number of other properties. The full
+ documentation is available in <a href="../expr.html">Expressions in
+ Apache HTTP Server</a>.</p>
+
</usage>
<seealso><a href="../expr.html">Expressions in Apache HTTP Server</a>,
for a complete reference and more examples.</seealso>
+<seealso><directive type="section" module="core">ElseIf</directive></seealso>
+<seealso><directive type="section" module="core">Else</directive></seealso>
<seealso><a href="../sections.html">How <Directory>, <Location>,
<Files> sections work</a> for an explanation of how these
different sections are combined when a request is received.
- <directive type="section">If</directive> has the same precedence
- and usage as <directive type="section">Files</directive></seealso>
+ <directive type="section">If</directive>,
+ <directive type="section">ElseIf</directive>, and
+ <directive type="section">Else</directive> are applied last.</seealso>
</directivesynopsis>
<directivesynopsis type="section">
* 20110329.6 (2.3.13-dev) Add AP_EXPR_FLAGS_RESTRICTED, ap_expr_eval_ctx_t->data,
* ap_expr_exec_ctx()
* 20110604.0 (2.3.13-dev) Make ap_rputs() inline
+ * 20110605.0 (2.3.13-dev) add core_dir_config->condition_ifelse, change return
+ * type of ap_add_if_conf()
*/
#define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */
#ifndef MODULE_MAGIC_NUMBER_MAJOR
-#define MODULE_MAGIC_NUMBER_MAJOR 20110604
+#define MODULE_MAGIC_NUMBER_MAJOR 20110605
#endif
#define MODULE_MAGIC_NUMBER_MINOR 0 /* 0...n */
* pitched indiscriminately */
unsigned int decode_encoded_slashes : 1; /* whether to decode encoded slashes in URLs */
+#define AP_CONDITION_IF 1
+#define AP_CONDITION_ELSE 2
+#define AP_CONDITION_ELSEIF (AP_CONDITION_ELSE|AP_CONDITION_IF)
+ unsigned int condition_ifelse : 2; /* is this an <If>, <ElseIf>, or <Else> */
+
ap_expr_info_t *condition; /* Conditionally merge <If> sections */
/** per-dir log config */
AP_CORE_DECLARE(void) ap_add_per_dir_conf(server_rec *s, void *dir_config);
AP_CORE_DECLARE(void) ap_add_per_url_conf(server_rec *s, void *url_config);
AP_CORE_DECLARE(void) ap_add_file_conf(apr_pool_t *p, core_dir_config *conf, void *url_config);
-AP_CORE_DECLARE(void) ap_add_if_conf(apr_pool_t *p, core_dir_config *conf, void *url_config);
+AP_CORE_DECLARE(const char *) ap_add_if_conf(apr_pool_t *p, core_dir_config *conf, void *url_config);
AP_CORE_DECLARE_NONSTD(const char *) ap_limit_section(cmd_parms *cmd, void *dummy, const char *arg);
/* Core filters; not exported. */
*new_space = url_config;
}
-AP_CORE_DECLARE(void) ap_add_if_conf(apr_pool_t *p, core_dir_config *conf,
- void *url_config)
+AP_CORE_DECLARE(const char *) ap_add_if_conf(apr_pool_t *p,
+ core_dir_config *conf,
+ void *if_config)
{
void **new_space;
+ core_dir_config *new = ap_get_module_config(if_config, &core_module);
- if (!conf->sec_if)
+ if (!conf->sec_if) {
conf->sec_if = apr_array_make(p, 2, sizeof(ap_conf_vector_t *));
+ }
+ if (new->condition_ifelse & AP_CONDITION_ELSE) {
+ int have_if = 0;
+ if (conf->sec_if->nelts > 0) {
+ core_dir_config *last;
+ ap_conf_vector_t *lastelt = APR_ARRAY_IDX(conf->sec_if,
+ conf->sec_if->nelts - 1,
+ ap_conf_vector_t *);
+ last = ap_get_module_config(lastelt, &core_module);
+ if (last->condition_ifelse & AP_CONDITION_IF)
+ have_if = 1;
+ }
+ if (!have_if)
+ return "<Else> or <ElseIf> section without previous <If> or "
+ "<ElseIf> section in same scope";
+ }
new_space = (void **)apr_array_push(conf->sec_if);
- *new_space = url_config;
+ *new_space = if_config;
+ return NULL;
}
return NULL;
}
+
+#define COND_IF ((void *)1)
+#define COND_ELSE ((void *)2)
+#define COND_ELSEIF ((void *)3)
+
static const char *ifsection(cmd_parms *cmd, void *mconfig, const char *arg)
{
const char *errmsg;
char *old_path = cmd->path;
core_dir_config *conf;
const command_rec *thiscmd = cmd->cmd;
- ap_conf_vector_t *new_file_conf = ap_create_per_dir_config(cmd->pool);
+ ap_conf_vector_t *new_if_conf = ap_create_per_dir_config(cmd->pool);
const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
const char *condition;
const char *expr_err;
arg = apr_pstrndup(cmd->temp_pool, arg, endp - arg);
- if (!arg[0]) {
- return missing_container_arg(cmd);
- }
- condition = ap_getword_conf(cmd->pool, &arg);
/* Only if not an .htaccess file */
if (!old_path) {
cmd->override = OR_ALL|ACCESS_CONF;
}
/* initialize our config and fetch it */
- conf = ap_set_config_vectors(cmd->server, new_file_conf, cmd->path,
+ conf = ap_set_config_vectors(cmd->server, new_if_conf, cmd->path,
&core_module, cmd->pool);
- conf->condition = ap_expr_parse_cmd(cmd, condition, &expr_err, NULL);
- if (expr_err) {
- return apr_psprintf(cmd->pool, "Cannot parse condition clause: %s", expr_err);
+ if (cmd->cmd->cmd_data == COND_IF)
+ conf->condition_ifelse = AP_CONDITION_IF;
+ else if (cmd->cmd->cmd_data == COND_ELSEIF)
+ conf->condition_ifelse = AP_CONDITION_ELSEIF;
+ else if (cmd->cmd->cmd_data == COND_ELSE)
+ conf->condition_ifelse = AP_CONDITION_ELSE;
+ else
+ ap_assert(0);
+
+ if (conf->condition_ifelse == AP_CONDITION_ELSE) {
+ if (arg[0])
+ return "<Else> does not take an argument";
+ }
+ else {
+ if (!arg[0])
+ return missing_container_arg(cmd);
+ condition = ap_getword_conf(cmd->pool, &arg);
+ conf->condition = ap_expr_parse_cmd(cmd, condition, &expr_err, NULL);
+ if (expr_err)
+ return apr_psprintf(cmd->pool, "Cannot parse condition clause: %s",
+ expr_err);
+ conf->condition->module_index = APLOG_MODULE_INDEX;
}
- conf->condition->module_index = APLOG_MODULE_INDEX;
- errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_file_conf);
+ errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_if_conf);
if (errmsg != NULL)
return errmsg;
conf->d_is_fnmatch = 0;
conf->r = NULL;
- ap_add_if_conf(cmd->pool, (core_dir_config *)mconfig, new_file_conf);
+ errmsg = ap_add_if_conf(cmd->pool, (core_dir_config *)mconfig, new_if_conf);
+ if (errmsg != NULL)
+ return errmsg;
if (*arg != '\0') {
return apr_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
"Undefine the existence of a variable. Undo a Define."),
AP_INIT_RAW_ARGS("Error", generate_error, NULL, OR_ALL,
"Generate error message from within configuration"),
-AP_INIT_RAW_ARGS("<If", ifsection, NULL, OR_ALL,
+AP_INIT_RAW_ARGS("<If", ifsection, COND_IF, OR_ALL,
+ "Container for directives to be conditionally applied"),
+AP_INIT_RAW_ARGS("<ElseIf", ifsection, COND_ELSEIF, OR_ALL,
+ "Container for directives to be conditionally applied"),
+AP_INIT_RAW_ARGS("<Else", ifsection, COND_ELSE, OR_ALL,
"Container for directives to be conditionally applied"),
/* Old resource config file commands */
int sec_idx;
int matches;
int cached_matches;
+ int prev_result = -1;
walk_walked_t *last_walk;
if (dconf->sec_if) {
int rc;
entry_core = ap_get_module_config(sec_ent[sec_idx], &core_module);
- rc = ap_expr_exec(r, entry_core->condition, &err);
- if (rc <= 0) {
- if (rc < 0)
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "Failed to evaluate <If > condition: %s",
- err);
- continue;
+ AP_DEBUG_ASSERT(entry_core->condition_ifelse != 0);
+ if (entry_core->condition_ifelse & AP_CONDITION_ELSE) {
+ AP_DEBUG_ASSERT(prev_result != -1);
+ if (prev_result == 1)
+ continue;
+ }
+
+ if (entry_core->condition_ifelse & AP_CONDITION_IF) {
+ rc = ap_expr_exec(r, entry_core->condition, &err);
+ if (rc <= 0) {
+ if (rc < 0)
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "Failed to evaluate <If > condition: %s",
+ err);
+ prev_result = 0;
+ continue;
+ }
+ prev_result = 1;
+ }
+ else {
+ prev_result = -1;
}
/* If we merged this same section last time, reuse it