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