From: Stefan Fritsch
Date: Sat, 28 May 2011 11:47:55 +0000 (+0000)
Subject: Use the new "ap_expr" expression parser.
X-Git-Tag: 2.3.13~101
X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3dd90a26b710c4935728a3c1a076dbe61eeb2c83;p=thirdparty%2Fapache%2Fhttpd.git
Use the new "ap_expr" expression parser.
The old parser can still be used by setting the new directive
SSILegacyExprParser
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1128614 13f79535-47bb-0310-9956-ffa450edef68
---
diff --git a/CHANGES b/CHANGES
index 9883c78cd97..626ecc31027 100644
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,10 @@
Changes with Apache 2.3.13
+ *) mod_include: Make the "#if expr" element use the new "ap_expr" expression
+ parser. The old parser can still be used by setting the new directive
+ SSILegacyExprParser. [Stefan Fritsch]
+
*) core: Add some features to ap_expr for use by mod_include: a restricted
mode that does not allow to bypass request access restrictions; new
variables DOCUMENT_URI (alias for REQUEST_URI), LAST_MODIFIED; -A as an
diff --git a/STATUS b/STATUS
index 4d313990081..182289049c6 100644
--- a/STATUS
+++ b/STATUS
@@ -96,8 +96,6 @@ RELEASE SHOWSTOPPERS:
jim sez: Why a blocker?, pgollucci +1 jim
wrowe asks: what's the API change required?
- * mod_includes aught to use ap_expr
-
* Clarify/potentially change the meaning of MaxConnections for Event MPM
with respect to accepting new connections and keep alive requests for
the docs and example config. This shouldn't change after users and
diff --git a/docs/manual/expr.xml b/docs/manual/expr.xml
index 03bf655ab34..bc86b793ab1 100644
--- a/docs/manual/expr.xml
+++ b/docs/manual/expr.xml
@@ -354,48 +354,50 @@ listfunction ::= listfuncname "(" word ")"
- Name | Description |
+ Name | Description | Restricted |
-d |
The argument is treated as a filename.
- True if the file exists and is a directory |
+ True if the file exists and is a directoryyes |
-e |
The argument is treated as a filename.
- True if the file (or dir or special) exists |
+ True if the file (or dir or special) existsyes |
-f |
The argument is treated as a filename.
- True if the file exists and is regular file |
+ True if the file exists and is regular fileyes |
-L |
The argument is treated as a filename.
- True if the file exists and is symlink |
+ True if the file exists and is symlinkyes |
-h |
The argument is treated as a filename.
True if the file exists and is symlink
- (same as -L ) |
+ (same as -L
)yes |
-F |
True if string is a valid file, accessible via all the server's
currently-configured access controls for that path. This uses an
internal subrequest to do the check, so use it with care - it can
- impact your server's performance! |
+ impact your server's performance! |
-U |
True if string is a valid URL, accessible via all the server's
currently-configured access controls for that path. This uses an
internal subrequest to do the check, so use it with care - it can
- impact your server's performance! |
+ impact your server's performance! |
-A |
- Alias for -U |
+ Alias for -U | |
-n |
- True if string is not empty |
+ True if string is not empty | |
-z |
- True if string is empty |
+ True if string is empty | |
-T |
False if string is empty, "0 ", "off ",
"false ", or "no " (case insensitive).
- True otherwise. |
+ True otherwise. |
-R |
Same as "%{REMOTE_ADDR} -ipmatch ... ", but more efficient
- |
+ |
+ The operators marked as "restricted" are not available in some modules
+ like mod_include.
@@ -408,35 +410,40 @@ listfunction ::= listfuncname "(" word ")"
- Name | Description |
+ Name | Description | Restricted |
req , http |
- Get HTTP request header |
+ Get HTTP request header | |
resp |
- Get HTTP response header |
+ Get HTTP response header | |
reqenv |
- Lookup request environment variable |
+ Lookup request environment variable | |
osenv |
- Lookup operating system environment variable |
+ Lookup operating system environment variable | |
note |
- Lookup request note |
+ Lookup request note | |
env |
Return first match of note , reqenv ,
- osenv |
+ osenv
|
tolower |
- Convert string to lower case |
+ Convert string to lower case | |
toupper |
- Convert string to uppser case |
+ Convert string to uppser case | |
escape |
- Escape special characters in %hex encoding |
+ Escape special characters in %hex encoding | |
unescape |
- Unescape %hex encoded string, leaving URL-special characters encoded (XXX: describe better) |
+ Unescape %hex encoded string, leaving URL-special characters
+ encoded (XXX: describe better) | |
file |
- Read contents from a file |
+ Read contents from a file | yes |
filesize |
- Return size of a file (or 0 if file does not exist or is not regular file) |
+ Return size of a file (or 0 if file does not exist or is not
+ regular file) | yes |
+ The functions marked as "restricted" are not available in some modules
+ like mod_include.
+
In addition to string-valued functions, there are also list-valued functions which
take one string as argument and return a wordlist, i.e. a list of strings. The wordlist
can be used with the special -in
operator.
diff --git a/docs/manual/howto/ssi.xml b/docs/manual/howto/ssi.xml
index b40dafc8fa9..577c5155a41 100644
--- a/docs/manual/howto/ssi.xml
+++ b/docs/manual/howto/ssi.xml
@@ -448,7 +448,8 @@ modified?
Then, in your SSI-enabled document, you might do the
following:
- <!--#if expr="${Mac} && ${InternetExplorer}" -->
+ <!--#if expr="-T reqenv('Mac') &&
+ -T reqenv('InternetExplorer')" -->
Apologetic text goes here
<!--#else -->
Cool JavaScript code goes here
diff --git a/docs/manual/mod/mod_include.xml b/docs/manual/mod/mod_include.xml
index 9828384a72d..4dd0ac70b90 100644
--- a/docs/manual/mod/mod_include.xml
+++ b/docs/manual/mod/mod_include.xml
@@ -504,12 +504,14 @@
directive. This includes the config
,
exec
, flastmod
, fsize
,
include
, echo
, and set
- directives, as well as the arguments to conditional operators.
+ directives. If SSILegacyExprParser is set to on
,
+ substitution also occures in the arguments to conditional operators.
You can insert a literal dollar sign into the string using backslash
quoting:
- <!--#if expr="$a = \$test" -->
+ <!--#set var="cur" value="\$test" -->
If a variable reference needs to be substituted in the
@@ -526,26 +528,6 @@
to "X_Y
" if REMOTE_HOST
is
"X
" and REQUEST_METHOD
is
"Y
".
-
- The below example will print "in foo" if the
- DOCUMENT_URI
is /foo/file.html
, "in bar"
- if it is /bar/file.html
and "in neither" otherwise:
-
-
- <!--#if expr='"$DOCUMENT_URI" = "/foo/file.html"' -->
-
- in foo
-
- <!--#elif expr='"$DOCUMENT_URI" = "/bar/file.html"' -->
-
- in bar
-
- <!--#else -->
-
- in neither
-
- <!--#endif -->
-
@@ -573,7 +555,55 @@
The endif
element ends the if
element
and is required.
- test_condition is one of the following:
+ test_condition is a boolean expression tha follows the
+ ap_expr syntax. The syntax can be changed
+ to be compatible with Apache HTTPD 2.2.x using SSILegacyExprParser.
+
+ The SSI variables set with the var
element are exported
+ into the request environment and can be accessed with the
+ reqenv
function. As a short-cut, the function name
+ v
is also available inside mod_include.
+
+ The below example will print "from local net" if client IP address
+ belongs to the 10.0.0.0/8 subnet.
+
+
+ <!--#if expr='-R "10.0.0.0/8"' -->
+
+ from local net
+
+ <!--#else -->
+
+ from somewhere else
+
+ <!--#endif -->
+
+
+ The below example will print "foo is bar" if the variable
+ foo
is set to the value "bar".
+
+
+ <!--#if expr='v("foo") = "bar"' -->
+
+ foo is bar
+
+ <!--#endif -->
+
+
+ Reference Documentation
+ See also: Expressions in Apache HTTP Server,
+ for a complete reference and examples. The restricted functions
+ are not available inside mod_include
+
+
+
+
+ Legacy expression syntax
+
+ This section describes the syntax of the #if expr
+ element if SSILegacyExprParser
+ is set to on
.
string
@@ -713,12 +743,6 @@
be escaped. This is regardless of their meaning to the regex engine.
-
@@ -856,14 +880,20 @@ displayed
SSIAccessEnable
-Enable the -A flag during conditional flow control processing.
+Enable the -A flag in legacy conditional expressions.
SSIAccessEnable on|off
SSIAccessEnable off
directory.htaccess
+ SSIAccessEnable has no effect unless
+ SSILegacyExprParser is set to
+ on
.
+
+
The SSIAccessEnable directive controls whether
- the -A test is enabled during conditional flow control processing.
+ the -A test is enabled during conditional flow control processing when
+ using the 2.2.x compatible expression parser.
SSIAccessEnable can take on the following values:
@@ -961,7 +991,25 @@ server.
-
+
+
+SSILegacyExprParser
+Enable compatibility mode for conditional expressions.
+SSILegacyExprParser on|off
+SSILegacyExprParser off
+directory.htaccess
+Available in version 2.3.13 and later.
+
+
+ As of version 2.3.13, mod_include has switched to the
+ new ap_expr syntax for conditional expressions
+ in #if
flow control elements. This directive allows to
+ switch to the old syntax which is compatible
+ with Apache HTTPD version 2.2.x and earlier.
+
+
+
+
XBitHack
Parse SSI directives in files with the execute bit
diff --git a/docs/manual/upgrading.xml b/docs/manual/upgrading.xml
index 9c95f5e8178..3a2423006a9 100644
--- a/docs/manual/upgrading.xml
+++ b/docs/manual/upgrading.xml
@@ -226,9 +226,17 @@
now uses a boolean expression to determine if a filter is applied.
- mod_include: An SSI* config directive in directory
- scope no longer causes all other per-directory SSI* directives to be
- reset to their default values.
+ mod_include:
+
+ - The
#if expr
element now uses the new expression parser. The old syntax can be
+ restored with the new directive SSILegacyExprParser.
+
+ - An SSI* config directive in directory scope no longer causes
+ all other per-directory SSI* directives to be reset to their
+ default values.
+
diff --git a/modules/filters/mod_include.c b/modules/filters/mod_include.c
index d520785570e..def1994af2d 100644
--- a/modules/filters/mod_include.c
+++ b/modules/filters/mod_include.c
@@ -39,6 +39,7 @@
#include "util_script.h"
#include "http_core.h"
#include "mod_include.h"
+#include "ap_expr.h"
/* helper for Latin1 <-> entity encoding */
#if APR_CHARSET_EBCDIC
@@ -119,6 +120,7 @@ typedef struct {
signed char accessenable;
signed char lastmodified;
signed char etag;
+ signed char legacy_expr;
} include_dir_config;
typedef struct {
@@ -195,8 +197,13 @@ struct ssi_internal_ctx {
const char *undefined_echo;
apr_size_t undefined_echo_len;
- int accessenable; /* is using the access tests allowed? */
+ char accessenable; /* is using the access tests allowed? */
+ char legacy_expr; /* use ap_expr or legacy mod_include
+ expression parser? */
+ ap_expr_eval_ctx_t *expr_eval_ctx; /* NULL if there wasn't an ap_expr yet */
+ const char *expr_vary_this; /* for use by ap_expr_eval_ctx */
+ const char *expr_err; /* for use by ap_expr_eval_ctx */
#ifdef DEBUG_INCLUDE
struct {
ap_filter_t *f;
@@ -454,7 +461,7 @@ static APR_OPTIONAL_FN_TYPE(ap_register_include_handler) *ssi_pfn_register;
/* Sentinel value to store in subprocess_env for items that
* shouldn't be evaluated until/unless they're actually used
*/
-static const char lazy_eval_sentinel;
+static const char lazy_eval_sentinel = '\0';
#define LAZY_VALUE (&lazy_eval_sentinel)
/* default values */
@@ -689,6 +696,48 @@ static const char *get_include_var(const char *var, include_ctx_t *ctx)
return val;
}
+static const char *include_expr_var_fn(ap_expr_eval_ctx_t *eval_ctx,
+ const void *data,
+ const char *arg)
+{
+ const char *res, *name = data;
+ include_ctx_t *ctx = eval_ctx->data;
+ if (name[0] == 'e') {
+ /* keep legacy "env" semantics */
+ if ((res = apr_table_get(ctx->r->notes, arg)) != NULL)
+ return res;
+ else if ((res = get_include_var(arg, ctx)) != NULL)
+ return res;
+ else
+ return getenv(arg);
+ }
+ else {
+ return get_include_var(arg, ctx);
+ }
+}
+
+static int include_expr_lookup(ap_expr_lookup_parms *parms)
+{
+ switch (parms->type) {
+ case AP_EXPR_FUNC_STRING:
+ if (strcasecmp(parms->name, "v") == 0 ||
+ strcasecmp(parms->name, "reqenv") == 0 ||
+ strcasecmp(parms->name, "env") == 0) {
+ *parms->func = include_expr_var_fn;
+ *parms->data = parms->name;
+ return OK;
+ }
+ break;
+ /*
+ * We could also make the SSI vars available as %{...} style variables
+ * (AP_EXPR_FUNC_VAR), but this would create problems if we ever want
+ * to cache parsed expressions for performance reasons.
+ */
+ }
+ return ap_run_expr_lookup(parms);
+}
+
+
/*
* Do variable substitution on strings
*
@@ -1536,6 +1585,69 @@ static int parse_expr(include_ctx_t *ctx, const char *expr, int *was_error)
return (root ? root->value : 0);
}
+/* same as above, but use common ap_expr syntax / API */
+static int parse_ap_expr(include_ctx_t *ctx, const char *expr, int *was_error)
+{
+ ap_expr_info_t expr_info;
+ const char *err;
+ int ret;
+ backref_t *re = ctx->intern->re;
+ ap_expr_eval_ctx_t *eval_ctx = ctx->intern->expr_eval_ctx;
+
+ expr_info.filename = ctx->r->filename;
+ expr_info.line_number = 0;
+ expr_info.module_index = APLOG_MODULE_INDEX;
+ expr_info.flags = AP_EXPR_FLAGS_RESTRICTED;
+ err = ap_expr_parse(ctx->r->pool, ctx->r->pool, &expr_info, expr,
+ include_expr_lookup);
+ if (err) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->r,
+ "Could not parse expr \"%s\" in %s: %s", expr,
+ ctx->r->filename, err);
+ *was_error = 1;
+ return 0;
+ }
+
+ if (!re) {
+ ctx->intern->re = re = apr_pcalloc(ctx->pool, sizeof(*re));
+ }
+ else {
+ /* ap_expr_exec_ctx() does not care about re->have_match but only about
+ * re->source
+ */
+ if (!re->have_match)
+ re->source = NULL;
+ }
+
+ if (!eval_ctx) {
+ eval_ctx = apr_pcalloc(ctx->pool, sizeof(*eval_ctx));
+ ctx->intern->expr_eval_ctx = eval_ctx;
+ eval_ctx->r = ctx->r;
+ eval_ctx->c = ctx->r->connection;
+ eval_ctx->s = ctx->r->server;
+ eval_ctx->p = ctx->r->pool;
+ eval_ctx->data = ctx;
+ eval_ctx->err = &ctx->intern->expr_err;
+ eval_ctx->vary_this = &ctx->intern->expr_vary_this;
+ eval_ctx->re_nmatch = AP_MAX_REG_MATCH;
+ eval_ctx->re_pmatch = re->match;
+ eval_ctx->re_source = &re->source;
+ }
+
+ eval_ctx->info = &expr_info;
+ ret = ap_expr_exec_ctx(eval_ctx);
+ if (ret < 0) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->r,
+ "Could not evaluate expr \"%s\" in %s: %s", expr,
+ ctx->r->filename, ctx->intern->expr_err);
+ *was_error = 1;
+ return 0;
+ }
+ *was_error = 0;
+ if (re->source)
+ re->have_match = 1;
+ return ret;
+}
/*
* +-------------------------------------------------------+
@@ -2211,7 +2323,10 @@ static apr_status_t handle_if(include_ctx_t *ctx, ap_filter_t *f,
DEBUG_PRINTF((ctx, "**** if expr=\"%s\"\n", expr));
- expr_ret = parse_expr(ctx, expr, &was_error);
+ if (ctx->intern->legacy_expr)
+ expr_ret = parse_expr(ctx, expr, &was_error);
+ else
+ expr_ret = parse_ap_expr(ctx, expr, &was_error);
if (was_error) {
SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
@@ -3731,6 +3846,10 @@ static apr_status_t includes_filter(ap_filter_t *f, apr_bucket_brigade *b)
ctx->flags |= SSI_FLAG_NO_EXEC;
}
intern->accessenable = (conf->accessenable > 0);
+ intern->legacy_expr = (conf->legacy_expr > 0);
+ intern->expr_eval_ctx = NULL;
+ intern->expr_err = NULL;
+ intern->expr_vary_this = NULL;
ctx->if_nesting_level = 0;
intern->re = NULL;
@@ -3890,6 +4009,7 @@ static void *create_includes_dir_config(apr_pool_t *p, char *dummy)
result->accessenable = UNSET;
result->lastmodified = UNSET;
result->etag = UNSET;
+ result->accessenable = UNSET;
return result;
}
@@ -3907,6 +4027,7 @@ static void *merge_includes_dir_config(apr_pool_t *p, void *basev, void *overrid
MERGE(base, over, new, accessenable, UNSET);
MERGE(base, over, new, lastmodified, UNSET);
MERGE(base, over, new, etag, UNSET);
+ MERGE(base, over, new, legacy_expr, UNSET);
return new;
}
@@ -4058,6 +4179,11 @@ static const command_rec includes_cmds[] =
AP_INIT_FLAG("SSIAccessEnable", ap_set_flag_slot_char,
(void *)APR_OFFSETOF(include_dir_config, accessenable),
OR_LIMIT, "Whether testing access is enabled. Limited to 'on' or 'off'"),
+ AP_INIT_FLAG("SSILegacyExprParser", ap_set_flag_slot_char,
+ (void *)APR_OFFSETOF(include_dir_config, legacy_expr),
+ OR_LIMIT,
+ "Whether to use the legacy expression parser compatible "
+ "with <= 2.2.x. Limited to 'on' or 'off'"),
AP_INIT_FLAG("SSILastModified", ap_set_flag_slot_char,
(void *)APR_OFFSETOF(include_dir_config, lastmodified),
OR_LIMIT, "Whether to set the last modified header or respect "