From: Stefan Fritsch
Date: Sun, 5 Jun 2011 18:15:02 +0000 (+0000)
Subject: - Add and to complement sections. These are both easier
X-Git-Tag: 2.3.13~78
X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=93623482e38ff281785b3c2c5b292f5c87afef4f;p=apache
- Add and to complement sections. These are both easier
to use and more efficient than using several sections.
- Update documentation a bit.
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1132469 13f79535-47bb-0310-9956-ffa450edef68
---
diff --git a/CHANGES b/CHANGES
index eea1479c00..515b0a78a9 100644
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,9 @@
Changes with Apache 2.3.13
+ *) core: Add and to complement sections.
+ [Stefan Fritsch]
+
*) mod_ext_filter: Remove DebugLevel option in favor of per-module loglevel.
[Stefan Fritsch]
diff --git a/docs/manual/expr.xml b/docs/manual/expr.xml
index bc86b793ab..cd382bfc89 100644
--- a/docs/manual/expr.xml
+++ b/docs/manual/expr.xml
@@ -38,7 +38,9 @@
-If
+If
+ElseIf
+Else
RewriteCond
SetEnvIfExpr
FilterProvider
diff --git a/docs/manual/mod/core.xml b/docs/manual/mod/core.xml
index a219feccd6..0263701fca 100644
--- a/docs/manual/mod/core.xml
+++ b/docs/manual/mod/core.xml
@@ -801,6 +801,102 @@ from the web
Locations
+
+Else
+Contains directives that apply only if the condition of a
+previous If or
+ElseIf section is not
+satisfied by a request at runtime
+<Else> ... </Else>
+server configvirtual host
+directory.htaccess
+
+All
+
+
+ The Else applies the enclosed
+ directives if and only if the most recent
+ If or
+ ElseIf section
+ in the same scope has not been applied.
+ For example: In
+
+
+ <If "-z req('Host')">
+ ...
+ </If>
+ <Else>
+ ...
+ </Else>
+
+
+ The If would match HTTP/1.0
+ requests without a Host: header and the
+ Else would match requests
+ with a Host: header.
+
+
+If
+ElseIf
+How <Directory>, <Location>,
+ <Files> sections work for an explanation of how these
+ different sections are combined when a request is received.
+ If,
+ ElseIf, and
+ Else are applied last.
+
+
+
+ElseIf
+Contains directives that apply only if a condition is satisfied
+by a request at runtime while the condition of a previous
+If or
+ElseIf section is not
+satisfied
+<ElseIf expression> ... </ElseIf>
+server configvirtual host
+directory.htaccess
+
+All
+
+
+ The ElseIf applies the enclosed
+ directives if and only if both the given condition evaluates to true and
+ the most recent If or
+ ElseIf section in the same scope has
+ not been applied. For example: In
+
+
+ <If "-R '10.1.0.0/16'">
+ ...
+ </If>
+ <ElseIf "-R '10.0.0.0/8'">
+ ...
+ </ElseIf>
+ <Else>
+ ...
+ </Else>
+
+
+ The ElseIf 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.
+
+
+Expressions in Apache HTTP Server,
+for a complete reference and more examples.
+If
+Else
+How <Directory>, <Location>,
+ <Files> sections work for an explanation of how these
+ different sections are combined when a request is received.
+ If,
+ ElseIf, and
+ Else are applied last.
+
+
+
+
EnableMMAP
Use memory-mapping to read files during delivery
@@ -1603,31 +1699,38 @@ satisfied by a request at runtime
For example:
- <If "$req{Host} = ''">
+ <If "-z req('Host')">
- would match HTTP/1.0 requests without a Host: header.
-
- You may compare the value of any variable in the request headers
- ($req), response headers ($resp) or environment ($env) in your
- expression.
-
- Apart from =
, If
can use the IN
- operator to compare if the expression is in a given range:
+ would match HTTP/1.0 requests without a Host: header.
+ Expressions may contain various shell-like operators for string
+ comparison (=
, !=
, <
, ...),
+ integer comparison (-eq
, -ne
, ...),
+ and others (-n
, -z
, -f
, ...).
+ It is also possible to use regular expressions,
- <If %{REQUEST_METHOD} IN GET,HEAD,OPTIONS>
+ <If "%{QUERY_STRING =~ /(delete|commit)=.*?elem/">
+ shell-like pattern matches and many other operations. These operations
+ can be done on request headers (req
), environment variables
+ (env
), and a large number of other properties. The full
+ documentation is available in Expressions in
+ Apache HTTP Server.
+
Expressions in Apache HTTP Server,
for a complete reference and more examples.
+ElseIf
+Else
How <Directory>, <Location>,
<Files> sections work for an explanation of how these
different sections are combined when a request is received.
- If has the same precedence
- and usage as Files
+ If,
+ ElseIf, and
+ Else are applied last.
diff --git a/include/ap_mmn.h b/include/ap_mmn.h
index a3afd13f7b..c35b0f093f 100644
--- a/include/ap_mmn.h
+++ b/include/ap_mmn.h
@@ -326,12 +326,14 @@
* 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 */
diff --git a/include/http_core.h b/include/http_core.h
index 4d7a7e3582..c32a86540c 100644
--- a/include/http_core.h
+++ b/include/http_core.h
@@ -538,6 +538,11 @@ typedef struct {
* 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 , , or */
+
ap_expr_info_t *condition; /* Conditionally merge sections */
/** per-dir log config */
@@ -602,7 +607,7 @@ void ap_core_reorder_directories(apr_pool_t *, server_rec *);
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. */
diff --git a/server/core.c b/server/core.c
index 32b42c08f3..6566bef1fb 100644
--- a/server/core.c
+++ b/server/core.c
@@ -535,16 +535,35 @@ AP_CORE_DECLARE(void) ap_add_file_conf(apr_pool_t *p, core_dir_config *conf,
*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 " or section without previous or "
+ " section in same scope";
+ }
new_space = (void **)apr_array_push(conf->sec_if);
- *new_space = url_config;
+ *new_space = if_config;
+ return NULL;
}
@@ -2182,6 +2201,11 @@ static const char *filesection(cmd_parms *cmd, void *mconfig, const char *arg)
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;
@@ -2190,7 +2214,7 @@ static const char *ifsection(cmd_parms *cmd, void *mconfig, const char *arg)
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;
@@ -2205,27 +2229,41 @@ static const char *ifsection(cmd_parms *cmd, void *mconfig, const char *arg)
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 " 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;
@@ -2233,7 +2271,9 @@ static const char *ifsection(cmd_parms *cmd, void *mconfig, const char *arg)
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,
@@ -3659,7 +3699,11 @@ AP_INIT_TAKE1("UnDefine", unset_define, NULL, EXEC_ON_READ|ACCESS_CONF|RSRC_CONF
"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("sec_if) {
@@ -1659,13 +1660,27 @@ AP_DECLARE(int) ap_if_walk(request_rec *r)
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 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 condition: %s",
+ err);
+ prev_result = 0;
+ continue;
+ }
+ prev_result = 1;
+ }
+ else {
+ prev_result = -1;
}
/* If we merged this same section last time, reuse it