Skip to content

Commit dc8e3c0

Browse files
author
Stefan Fritsch
committed
- Add <ElseIf> and <Else> to complement <If> sections. These are both easier
to use and more efficient than using several <If> sections. - Update <If> documentation a bit. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1132469 13f79535-47bb-0310-9956-ffa450edef68
1 parent 3e24f87 commit dc8e3c0

7 files changed

Lines changed: 213 additions & 39 deletions

File tree

CHANGES

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
Changes with Apache 2.3.13
44

5+
*) core: Add <ElseIf> and <Else> to complement <If> sections.
6+
[Stefan Fritsch]
7+
58
*) mod_ext_filter: Remove DebugLevel option in favor of per-module loglevel.
69
[Stefan Fritsch]
710

docs/manual/expr.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@
3838
</p>
3939
</summary>
4040

41-
<seealso><directive module="core">If</directive></seealso>
41+
<seealso><directive module="core" type="section">If</directive></seealso>
42+
<seealso><directive module="core" type="section">ElseIf</directive></seealso>
43+
<seealso><directive module="core" type="section">Else</directive></seealso>
4244
<seealso><directive module="mod_rewrite">RewriteCond</directive></seealso>
4345
<seealso><directive module="mod_setenvif">SetEnvIfExpr</directive></seealso>
4446
<seealso><directive module="mod_filter">FilterProvider</directive></seealso>

docs/manual/mod/core.xml

Lines changed: 115 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,102 @@ from the web</description>
801801
Locations</a></seealso>
802802
</directivesynopsis>
803803

804+
<directivesynopsis type="section">
805+
<name>Else</name>
806+
<description>Contains directives that apply only if the condition of a
807+
previous <directive type="section" module="core">If</directive> or
808+
<directive type="section" module="core">ElseIf</directive> section is not
809+
satisfied by a request at runtime</description>
810+
<syntax>&lt;Else&gt; ... &lt;/Else&gt;</syntax>
811+
<contextlist><context>server config</context><context>virtual host</context>
812+
<context>directory</context><context>.htaccess</context>
813+
</contextlist>
814+
<override>All</override>
815+
816+
<usage>
817+
<p>The <directive type="section">Else</directive> applies the enclosed
818+
directives if and only if the most recent
819+
<directive type="section">If</directive> or
820+
<directive type="section">ElseIf</directive> section
821+
in the same scope has not been applied.
822+
For example: In </p>
823+
824+
<example>
825+
&lt;If "-z req('Host')"&gt;<br/>
826+
...<br/>
827+
&lt;/If&gt;<br/>
828+
&lt;Else&gt;<br/>
829+
...<br/>
830+
&lt;/Else&gt;<br/>
831+
</example>
832+
833+
<p> The <directive type="section">If</directive> would match HTTP/1.0
834+
requests without a <var>Host:</var> header and the
835+
<directive type="section">Else</directive> would match requests
836+
with a <var>Host:</var> header.</p>
837+
838+
</usage>
839+
<seealso><directive type="section" module="core">If</directive></seealso>
840+
<seealso><directive type="section" module="core">ElseIf</directive></seealso>
841+
<seealso><a href="../sections.html">How &lt;Directory&gt;, &lt;Location&gt;,
842+
&lt;Files&gt; sections work</a> for an explanation of how these
843+
different sections are combined when a request is received.
844+
<directive type="section">If</directive>,
845+
<directive type="section">ElseIf</directive>, and
846+
<directive type="section">Else</directive> are applied last.</seealso>
847+
</directivesynopsis>
848+
849+
<directivesynopsis type="section">
850+
<name>ElseIf</name>
851+
<description>Contains directives that apply only if a condition is satisfied
852+
by a request at runtime while the condition of a previous
853+
<directive type="section" module="core">If</directive> or
854+
<directive type="section">ElseIf</directive> section is not
855+
satisfied</description>
856+
<syntax>&lt;ElseIf <var>expression</var>&gt; ... &lt;/ElseIf&gt;</syntax>
857+
<contextlist><context>server config</context><context>virtual host</context>
858+
<context>directory</context><context>.htaccess</context>
859+
</contextlist>
860+
<override>All</override>
861+
862+
<usage>
863+
<p>The <directive type="section">ElseIf</directive> applies the enclosed
864+
directives if and only if both the given condition evaluates to true and
865+
the most recent <directive type="section">If</directive> or
866+
<directive type="section">ElseIf</directive> section in the same scope has
867+
not been applied. For example: In </p>
868+
869+
<example>
870+
&lt;If "-R '10.1.0.0/16'"&gt;<br/>
871+
...<br/>
872+
&lt;/If&gt;<br/>
873+
&lt;ElseIf "-R '10.0.0.0/8'"&gt;<br/>
874+
...<br/>
875+
&lt;/ElseIf&gt;<br/>
876+
&lt;Else&gt;<br/>
877+
...<br/>
878+
&lt;/Else&gt;<br/>
879+
</example>
880+
881+
<p>The <directive type="section">ElseIf</directive> would match if
882+
the remote address of a request belongs to the subnet 10.0.0.0/8 but
883+
not to the subnet 10.1.0.0/16.</p>
884+
885+
</usage>
886+
<seealso><a href="../expr.html">Expressions in Apache HTTP Server</a>,
887+
for a complete reference and more examples.</seealso>
888+
<seealso><directive type="section" module="core">If</directive></seealso>
889+
<seealso><directive type="section" module="core">Else</directive></seealso>
890+
<seealso><a href="../sections.html">How &lt;Directory&gt;, &lt;Location&gt;,
891+
&lt;Files&gt; sections work</a> for an explanation of how these
892+
different sections are combined when a request is received.
893+
<directive type="section">If</directive>,
894+
<directive type="section">ElseIf</directive>, and
895+
<directive type="section">Else</directive> are applied last.</seealso>
896+
</directivesynopsis>
897+
898+
899+
804900
<directivesynopsis>
805901
<name>EnableMMAP</name>
806902
<description>Use memory-mapping to read files during delivery</description>
@@ -1603,31 +1699,38 @@ satisfied by a request at runtime</description>
16031699
For example:</p>
16041700

16051701
<example>
1606-
&lt;If "$req{Host} = ''"&gt;
1702+
&lt;If "-z req('Host')"&gt;
16071703
</example>
16081704

1609-
<p>would match HTTP/1.0 requests without a <var>Host:</var> header.</p>
1610-
1611-
<p>You may compare the value of any variable in the request headers
1612-
($req), response headers ($resp) or environment ($env) in your
1613-
expression.</p>
1614-
1615-
<p>Apart from <code>=</code>, <code>If</code> can use the <code>IN</code>
1616-
operator to compare if the expression is in a given range:</p>
1705+
<p>would match HTTP/1.0 requests without a <var>Host:</var> header.
1706+
Expressions may contain various shell-like operators for string
1707+
comparison (<code>=</code>, <code>!=</code>, <code>&lt;</code>, ...),
1708+
integer comparison (<code>-eq</code>, <code>-ne</code>, ...),
1709+
and others (<code>-n</code>, <code>-z</code>, <code>-f</code>, ...).
1710+
It is also possible to use regular expressions, </p>
16171711

16181712
<example>
1619-
&lt;If %{REQUEST_METHOD} IN GET,HEAD,OPTIONS&gt;
1713+
&lt;If "%{QUERY_STRING =~ /(delete|commit)=.*?elem/"&gt;
16201714
</example>
16211715

1716+
<p>shell-like pattern matches and many other operations. These operations
1717+
can be done on request headers (<code>req</code>), environment variables
1718+
(<code>env</code>), and a large number of other properties. The full
1719+
documentation is available in <a href="../expr.html">Expressions in
1720+
Apache HTTP Server</a>.</p>
1721+
16221722
</usage>
16231723

16241724
<seealso><a href="../expr.html">Expressions in Apache HTTP Server</a>,
16251725
for a complete reference and more examples.</seealso>
1726+
<seealso><directive type="section" module="core">ElseIf</directive></seealso>
1727+
<seealso><directive type="section" module="core">Else</directive></seealso>
16261728
<seealso><a href="../sections.html">How &lt;Directory&gt;, &lt;Location&gt;,
16271729
&lt;Files&gt; sections work</a> for an explanation of how these
16281730
different sections are combined when a request is received.
1629-
<directive type="section">If</directive> has the same precedence
1630-
and usage as <directive type="section">Files</directive></seealso>
1731+
<directive type="section">If</directive>,
1732+
<directive type="section">ElseIf</directive>, and
1733+
<directive type="section">Else</directive> are applied last.</seealso>
16311734
</directivesynopsis>
16321735

16331736
<directivesynopsis type="section">

include/ap_mmn.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,12 +326,14 @@
326326
* 20110329.6 (2.3.13-dev) Add AP_EXPR_FLAGS_RESTRICTED, ap_expr_eval_ctx_t->data,
327327
* ap_expr_exec_ctx()
328328
* 20110604.0 (2.3.13-dev) Make ap_rputs() inline
329+
* 20110605.0 (2.3.13-dev) add core_dir_config->condition_ifelse, change return
330+
* type of ap_add_if_conf()
329331
*/
330332

331333
#define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */
332334

333335
#ifndef MODULE_MAGIC_NUMBER_MAJOR
334-
#define MODULE_MAGIC_NUMBER_MAJOR 20110604
336+
#define MODULE_MAGIC_NUMBER_MAJOR 20110605
335337
#endif
336338
#define MODULE_MAGIC_NUMBER_MINOR 0 /* 0...n */
337339

include/http_core.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,11 @@ typedef struct {
538538
* pitched indiscriminately */
539539
unsigned int decode_encoded_slashes : 1; /* whether to decode encoded slashes in URLs */
540540

541+
#define AP_CONDITION_IF 1
542+
#define AP_CONDITION_ELSE 2
543+
#define AP_CONDITION_ELSEIF (AP_CONDITION_ELSE|AP_CONDITION_IF)
544+
unsigned int condition_ifelse : 2; /* is this an <If>, <ElseIf>, or <Else> */
545+
541546
ap_expr_info_t *condition; /* Conditionally merge <If> sections */
542547

543548
/** per-dir log config */
@@ -602,7 +607,7 @@ void ap_core_reorder_directories(apr_pool_t *, server_rec *);
602607
AP_CORE_DECLARE(void) ap_add_per_dir_conf(server_rec *s, void *dir_config);
603608
AP_CORE_DECLARE(void) ap_add_per_url_conf(server_rec *s, void *url_config);
604609
AP_CORE_DECLARE(void) ap_add_file_conf(apr_pool_t *p, core_dir_config *conf, void *url_config);
605-
AP_CORE_DECLARE(void) ap_add_if_conf(apr_pool_t *p, core_dir_config *conf, void *url_config);
610+
AP_CORE_DECLARE(const char *) ap_add_if_conf(apr_pool_t *p, core_dir_config *conf, void *url_config);
606611
AP_CORE_DECLARE_NONSTD(const char *) ap_limit_section(cmd_parms *cmd, void *dummy, const char *arg);
607612

608613
/* Core filters; not exported. */

server/core.c

Lines changed: 61 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -535,16 +535,35 @@ AP_CORE_DECLARE(void) ap_add_file_conf(apr_pool_t *p, core_dir_config *conf,
535535
*new_space = url_config;
536536
}
537537

538-
AP_CORE_DECLARE(void) ap_add_if_conf(apr_pool_t *p, core_dir_config *conf,
539-
void *url_config)
538+
AP_CORE_DECLARE(const char *) ap_add_if_conf(apr_pool_t *p,
539+
core_dir_config *conf,
540+
void *if_config)
540541
{
541542
void **new_space;
543+
core_dir_config *new = ap_get_module_config(if_config, &core_module);
542544

543-
if (!conf->sec_if)
545+
if (!conf->sec_if) {
544546
conf->sec_if = apr_array_make(p, 2, sizeof(ap_conf_vector_t *));
547+
}
548+
if (new->condition_ifelse & AP_CONDITION_ELSE) {
549+
int have_if = 0;
550+
if (conf->sec_if->nelts > 0) {
551+
core_dir_config *last;
552+
ap_conf_vector_t *lastelt = APR_ARRAY_IDX(conf->sec_if,
553+
conf->sec_if->nelts - 1,
554+
ap_conf_vector_t *);
555+
last = ap_get_module_config(lastelt, &core_module);
556+
if (last->condition_ifelse & AP_CONDITION_IF)
557+
have_if = 1;
558+
}
559+
if (!have_if)
560+
return "<Else> or <ElseIf> section without previous <If> or "
561+
"<ElseIf> section in same scope";
562+
}
545563

546564
new_space = (void **)apr_array_push(conf->sec_if);
547-
*new_space = url_config;
565+
*new_space = if_config;
566+
return NULL;
548567
}
549568

550569

@@ -2182,6 +2201,11 @@ static const char *filesection(cmd_parms *cmd, void *mconfig, const char *arg)
21822201

21832202
return NULL;
21842203
}
2204+
2205+
#define COND_IF ((void *)1)
2206+
#define COND_ELSE ((void *)2)
2207+
#define COND_ELSEIF ((void *)3)
2208+
21852209
static const char *ifsection(cmd_parms *cmd, void *mconfig, const char *arg)
21862210
{
21872211
const char *errmsg;
@@ -2190,7 +2214,7 @@ static const char *ifsection(cmd_parms *cmd, void *mconfig, const char *arg)
21902214
char *old_path = cmd->path;
21912215
core_dir_config *conf;
21922216
const command_rec *thiscmd = cmd->cmd;
2193-
ap_conf_vector_t *new_file_conf = ap_create_per_dir_config(cmd->pool);
2217+
ap_conf_vector_t *new_if_conf = ap_create_per_dir_config(cmd->pool);
21942218
const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
21952219
const char *condition;
21962220
const char *expr_err;
@@ -2205,35 +2229,51 @@ static const char *ifsection(cmd_parms *cmd, void *mconfig, const char *arg)
22052229

22062230
arg = apr_pstrndup(cmd->temp_pool, arg, endp - arg);
22072231

2208-
if (!arg[0]) {
2209-
return missing_container_arg(cmd);
2210-
}
22112232

2212-
condition = ap_getword_conf(cmd->pool, &arg);
22132233
/* Only if not an .htaccess file */
22142234
if (!old_path) {
22152235
cmd->override = OR_ALL|ACCESS_CONF;
22162236
}
22172237

22182238
/* initialize our config and fetch it */
2219-
conf = ap_set_config_vectors(cmd->server, new_file_conf, cmd->path,
2239+
conf = ap_set_config_vectors(cmd->server, new_if_conf, cmd->path,
22202240
&core_module, cmd->pool);
22212241

2222-
conf->condition = ap_expr_parse_cmd(cmd, condition, &expr_err, NULL);
2223-
if (expr_err) {
2224-
return apr_psprintf(cmd->pool, "Cannot parse condition clause: %s", expr_err);
2242+
if (cmd->cmd->cmd_data == COND_IF)
2243+
conf->condition_ifelse = AP_CONDITION_IF;
2244+
else if (cmd->cmd->cmd_data == COND_ELSEIF)
2245+
conf->condition_ifelse = AP_CONDITION_ELSEIF;
2246+
else if (cmd->cmd->cmd_data == COND_ELSE)
2247+
conf->condition_ifelse = AP_CONDITION_ELSE;
2248+
else
2249+
ap_assert(0);
2250+
2251+
if (conf->condition_ifelse == AP_CONDITION_ELSE) {
2252+
if (arg[0])
2253+
return "<Else> does not take an argument";
2254+
}
2255+
else {
2256+
if (!arg[0])
2257+
return missing_container_arg(cmd);
2258+
condition = ap_getword_conf(cmd->pool, &arg);
2259+
conf->condition = ap_expr_parse_cmd(cmd, condition, &expr_err, NULL);
2260+
if (expr_err)
2261+
return apr_psprintf(cmd->pool, "Cannot parse condition clause: %s",
2262+
expr_err);
2263+
conf->condition->module_index = APLOG_MODULE_INDEX;
22252264
}
2226-
conf->condition->module_index = APLOG_MODULE_INDEX;
22272265

2228-
errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_file_conf);
2266+
errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_if_conf);
22292267
if (errmsg != NULL)
22302268
return errmsg;
22312269

22322270
conf->d = cmd->path;
22332271
conf->d_is_fnmatch = 0;
22342272
conf->r = NULL;
22352273

2236-
ap_add_if_conf(cmd->pool, (core_dir_config *)mconfig, new_file_conf);
2274+
errmsg = ap_add_if_conf(cmd->pool, (core_dir_config *)mconfig, new_if_conf);
2275+
if (errmsg != NULL)
2276+
return errmsg;
22372277

22382278
if (*arg != '\0') {
22392279
return apr_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
@@ -3659,7 +3699,11 @@ AP_INIT_TAKE1("UnDefine", unset_define, NULL, EXEC_ON_READ|ACCESS_CONF|RSRC_CONF
36593699
"Undefine the existence of a variable. Undo a Define."),
36603700
AP_INIT_RAW_ARGS("Error", generate_error, NULL, OR_ALL,
36613701
"Generate error message from within configuration"),
3662-
AP_INIT_RAW_ARGS("<If", ifsection, NULL, OR_ALL,
3702+
AP_INIT_RAW_ARGS("<If", ifsection, COND_IF, OR_ALL,
3703+
"Container for directives to be conditionally applied"),
3704+
AP_INIT_RAW_ARGS("<ElseIf", ifsection, COND_ELSEIF, OR_ALL,
3705+
"Container for directives to be conditionally applied"),
3706+
AP_INIT_RAW_ARGS("<Else", ifsection, COND_ELSE, OR_ALL,
36633707
"Container for directives to be conditionally applied"),
36643708

36653709
/* Old resource config file commands */

server/request.c

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1628,6 +1628,7 @@ AP_DECLARE(int) ap_if_walk(request_rec *r)
16281628
int sec_idx;
16291629
int matches;
16301630
int cached_matches;
1631+
int prev_result = -1;
16311632
walk_walked_t *last_walk;
16321633

16331634
if (dconf->sec_if) {
@@ -1659,13 +1660,27 @@ AP_DECLARE(int) ap_if_walk(request_rec *r)
16591660
int rc;
16601661
entry_core = ap_get_module_config(sec_ent[sec_idx], &core_module);
16611662

1662-
rc = ap_expr_exec(r, entry_core->condition, &err);
1663-
if (rc <= 0) {
1664-
if (rc < 0)
1665-
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
1666-
"Failed to evaluate <If > condition: %s",
1667-
err);
1668-
continue;
1663+
AP_DEBUG_ASSERT(entry_core->condition_ifelse != 0);
1664+
if (entry_core->condition_ifelse & AP_CONDITION_ELSE) {
1665+
AP_DEBUG_ASSERT(prev_result != -1);
1666+
if (prev_result == 1)
1667+
continue;
1668+
}
1669+
1670+
if (entry_core->condition_ifelse & AP_CONDITION_IF) {
1671+
rc = ap_expr_exec(r, entry_core->condition, &err);
1672+
if (rc <= 0) {
1673+
if (rc < 0)
1674+
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
1675+
"Failed to evaluate <If > condition: %s",
1676+
err);
1677+
prev_result = 0;
1678+
continue;
1679+
}
1680+
prev_result = 1;
1681+
}
1682+
else {
1683+
prev_result = -1;
16691684
}
16701685

16711686
/* If we merged this same section last time, reuse it

0 commit comments

Comments
 (0)