You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by sf...@apache.org on 2011/05/28 13:47:56 UTC

svn commit: r1128614 - in /httpd/httpd/trunk: CHANGES STATUS docs/manual/expr.xml docs/manual/howto/ssi.xml docs/manual/mod/mod_include.xml docs/manual/upgrading.xml modules/filters/mod_include.c

Author: sf
Date: Sat May 28 11:47:55 2011
New Revision: 1128614

URL: http://svn.apache.org/viewvc?rev=1128614&view=rev
Log:
Use the new "ap_expr" expression parser.
The old parser can still be used by setting the new directive
SSILegacyExprParser

Modified:
    httpd/httpd/trunk/CHANGES
    httpd/httpd/trunk/STATUS
    httpd/httpd/trunk/docs/manual/expr.xml
    httpd/httpd/trunk/docs/manual/howto/ssi.xml
    httpd/httpd/trunk/docs/manual/mod/mod_include.xml
    httpd/httpd/trunk/docs/manual/upgrading.xml
    httpd/httpd/trunk/modules/filters/mod_include.c

Modified: httpd/httpd/trunk/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/CHANGES?rev=1128614&r1=1128613&r2=1128614&view=diff
==============================================================================
--- httpd/httpd/trunk/CHANGES [utf-8] (original)
+++ httpd/httpd/trunk/CHANGES [utf-8] Sat May 28 11:47:55 2011
@@ -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

Modified: httpd/httpd/trunk/STATUS
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/STATUS?rev=1128614&r1=1128613&r2=1128614&view=diff
==============================================================================
--- httpd/httpd/trunk/STATUS (original)
+++ httpd/httpd/trunk/STATUS Sat May 28 11:47:55 2011
@@ -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 

Modified: httpd/httpd/trunk/docs/manual/expr.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/manual/expr.xml?rev=1128614&r1=1128613&r2=1128614&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/manual/expr.xml (original)
+++ httpd/httpd/trunk/docs/manual/expr.xml Sat May 28 11:47:55 2011
@@ -354,48 +354,50 @@ listfunction ::= listfuncname "<strong>(
     <table border="1" style="zebra">
     <columnspec><column width=".2"/><column width=".2"/><column width=".6"/></columnspec>
 
-    <tr><th>Name</th><th>Description</th></tr>
+    <tr><th>Name</th><th>Description</th><th>Restricted</th></tr>
     <tr><td><code>-d</code></td>
         <td>The argument is treated as a filename.
-            True if the file exists and is a directory</td></tr>
+            True if the file exists and is a directory</td><td>yes</td></tr>
     <tr><td><code>-e</code></td>
         <td>The argument is treated as a filename.
-            True if the file (or dir or special) exists</td></tr>
+            True if the file (or dir or special) exists</td><td>yes</td></tr>
     <tr><td><code>-f</code></td>
         <td>The argument is treated as a filename.
-            True if the file exists and is regular file</td></tr>
+            True if the file exists and is regular file</td><td>yes</td></tr>
     <tr><td><code>-L</code></td>
         <td>The argument is treated as a filename.
-            True if the file exists and is symlink</td></tr>
+            True if the file exists and is symlink</td><td>yes</td></tr>
     <tr><td><code>-h</code></td>
         <td>The argument is treated as a filename.
             True if the file exists and is symlink
-            (same as <code>-L</code>)</td></tr>
+            (same as <code>-L</code>)</td><td>yes</td></tr>
     <tr><td><code>-F</code></td>
         <td>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!</td></tr>
+            impact your server's performance!</td><td></td></tr>
     <tr><td><code>-U</code></td>
         <td>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!</td></tr>
+            impact your server's performance!</td><td></td></tr>
     <tr><td><code>-A</code></td>
-        <td>Alias for <code>-U</code></td></tr>
+        <td>Alias for <code>-U</code></td><td></td></tr>
     <tr><td><code>-n</code></td>
-        <td>True if string is not empty</td></tr>
+        <td>True if string is not empty</td><td></td></tr>
     <tr><td><code>-z</code></td>
-        <td>True if string is empty</td></tr>
+        <td>True if string is empty</td><td></td></tr>
     <tr><td><code>-T</code></td>
         <td>False if string is empty, "<code>0</code>", "<code>off</code>",
             "<code>false</code>", or "<code>no</code>" (case insensitive).
-            True otherwise.</td></tr>
+            True otherwise.</td><td></td></tr>
     <tr><td><code>-R</code></td>
         <td>Same as "<code>%{REMOTE_ADDR} -ipmatch ...</code>", but more efficient
-        </td></tr>
+        </td><td></td></tr>
     </table>
 
+    <p>The operators marked as "restricted" are not available in some modules
+    like <module>mod_include</module>.</p>
 </section>
 
 <section id="functions">
@@ -408,35 +410,40 @@ listfunction ::= listfuncname "<strong>(
     <table border="1" style="zebra">
     <columnspec><column width=".2"/><column width=".8"/></columnspec>
 
-    <tr><th>Name</th><th>Description</th></tr>
+    <tr><th>Name</th><th>Description</th><th>Restricted</th></tr>
     <tr><td><code>req</code>, <code>http</code></td>
-        <td>Get HTTP request header</td></tr>
+        <td>Get HTTP request header</td><td></td></tr>
     <tr><td><code>resp</code></td>
-        <td>Get HTTP response header</td></tr>
+        <td>Get HTTP response header</td><td></td></tr>
     <tr><td><code>reqenv</code></td>
-        <td>Lookup request environment variable</td></tr>
+        <td>Lookup request environment variable</td><td></td></tr>
     <tr><td><code>osenv</code></td>
-        <td>Lookup operating system environment variable</td></tr>
+        <td>Lookup operating system environment variable</td><td></td></tr>
     <tr><td><code>note</code></td>
-        <td>Lookup request note</td></tr>
+        <td>Lookup request note</td><td></td></tr>
     <tr><td><code>env</code></td>
         <td>Return first match of <code>note</code>, <code>reqenv</code>,
-            <code>osenv</code></td></tr>
+            <code>osenv</code></td><td></td></tr>
     <tr><td><code>tolower</code></td>
-        <td>Convert string to lower case</td></tr>
+        <td>Convert string to lower case</td><td></td></tr>
     <tr><td><code>toupper</code></td>
-        <td>Convert string to uppser case</td></tr>
+        <td>Convert string to uppser case</td><td></td></tr>
     <tr><td><code>escape</code></td>
-        <td>Escape special characters in %hex encoding</td></tr>
+        <td>Escape special characters in %hex encoding</td><td></td></tr>
     <tr><td><code>unescape</code></td>
-        <td>Unescape %hex encoded string, leaving URL-special characters encoded (XXX: describe better)</td></tr>
+        <td>Unescape %hex encoded string, leaving URL-special characters
+            encoded (XXX: describe better)</td><td></td></tr>
     <tr><td><code>file</code></td>
-        <td>Read contents from a file</td></tr>
+        <td>Read contents from a file</td><td>yes</td></tr>
     <tr><td><code>filesize</code></td>
-        <td>Return size of a file (or 0 if file does not exist or is not regular file)</td></tr>
+        <td>Return size of a file (or 0 if file does not exist or is not
+            regular file)</td><td>yes</td></tr>
 
     </table>
 
+    <p>The functions marked as "restricted" are not available in some modules
+    like <module>mod_include</module>.</p>
+
     <p>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 <code>-in</code> operator.

Modified: httpd/httpd/trunk/docs/manual/howto/ssi.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/manual/howto/ssi.xml?rev=1128614&r1=1128613&r2=1128614&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/manual/howto/ssi.xml (original)
+++ httpd/httpd/trunk/docs/manual/howto/ssi.xml Sat May 28 11:47:55 2011
@@ -448,7 +448,8 @@ modified?</title>
     <p>Then, in your SSI-enabled document, you might do the
     following:</p>
 <example>
-        &lt;!--#if expr="${Mac} &amp;&amp; ${InternetExplorer}" --&gt;<br />
+        &lt;!--#if expr="-T reqenv('Mac') &amp;&amp;
+                         -T reqenv('InternetExplorer')" --&gt;<br />
         Apologetic text goes here<br />
         &lt;!--#else --&gt;<br />
         Cool JavaScript code goes here<br />

Modified: httpd/httpd/trunk/docs/manual/mod/mod_include.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/manual/mod/mod_include.xml?rev=1128614&r1=1128613&r2=1128614&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/manual/mod/mod_include.xml (original)
+++ httpd/httpd/trunk/docs/manual/mod/mod_include.xml Sat May 28 11:47:55 2011
@@ -504,12 +504,14 @@
     directive. This includes the <code>config</code>,
     <code>exec</code>, <code>flastmod</code>, <code>fsize</code>,
     <code>include</code>, <code>echo</code>, and <code>set</code>
-    directives, as well as the arguments to conditional operators.
+    directives. If <directive module="mod_include"
+    >SSILegacyExprParser</directive> is set to <code>on</code>,
+    substitution also occures in the arguments to conditional operators.
     You can insert a literal dollar sign into the string using backslash
     quoting:</p>
 
     <example>
-      &lt;!--#if expr="$a = \$test" --&gt;
+      &lt;!--#set var="cur" value="\$test" --&gt;
     </example>
 
     <p>If a variable reference needs to be substituted in the
@@ -526,26 +528,6 @@
     to "<code>X_Y</code>" if <code>REMOTE_HOST</code> is
     "<code>X</code>" and <code>REQUEST_METHOD</code> is
     "<code>Y</code>".</p>
-
-    <p>The below example will print "in foo" if the
-    <code>DOCUMENT_URI</code> is <code>/foo/file.html</code>, "in bar"
-    if it is <code>/bar/file.html</code> and "in neither" otherwise:</p>
-
-    <example>
-      &lt;!--#if expr='"$DOCUMENT_URI" = "/foo/file.html"' --&gt;<br />
-      <indent>
-        in foo<br />
-      </indent>
-      &lt;!--#elif expr='"$DOCUMENT_URI" = "/bar/file.html"' --&gt;<br />
-      <indent>
-        in bar<br />
-      </indent>
-      &lt;!--#else --&gt;<br />
-      <indent>
-        in neither<br />
-      </indent>
-      &lt;!--#endif --&gt;
-    </example>
 </section>
 
 <section id="flowctrl">
@@ -573,7 +555,55 @@
     <p>The <code>endif</code> element ends the <code>if</code> element
     and is required.</p>
 
-    <p><var>test_condition</var> is one of the following:</p>
+    <p><var>test_condition</var> is a boolean expression tha follows the
+    <a href="../expr.html">ap_expr</a> syntax. The syntax can be changed
+    to be compatible with Apache HTTPD 2.2.x using <directive
+    module="mod_include">SSILegacyExprParser</directive>.</p>
+
+    <p>The SSI variables set with the <code>var</code> element are exported
+    into the request environment and can be accessed with the
+    <code>reqenv</code> function. As a short-cut, the function name
+    <code>v</code> is also available inside <module>mod_include</module>.</p>
+
+    <p>The below example will print "from local net" if client IP address
+    belongs to the 10.0.0.0/8 subnet.</p>
+
+    <example>
+      &lt;!--#if expr='-R "10.0.0.0/8"' --&gt;<br />
+      <indent>
+        from local net<br />
+      </indent>
+      &lt;!--#else --&gt;<br />
+      <indent>
+        from somewhere else<br />
+      </indent>
+      &lt;!--#endif --&gt;
+    </example>
+
+    <p>The below example will print "foo is bar" if the variable
+    <code>foo</code> is set to the value "bar".</p>
+
+    <example>
+      &lt;!--#if expr='v("foo") = "bar"' --&gt;<br />
+      <indent>
+        foo is bar<br />
+      </indent>
+      &lt;!--#endif --&gt;
+    </example>
+
+    <note><title>Reference Documentation</title>
+    <p>See also: <a href="../expr.html">Expressions in Apache HTTP Server</a>,
+    for a complete reference and examples. The <em>restricted</em> functions
+    are not available inside <module>mod_include</module></p>
+    </note>
+</section>
+
+<section id="legacyexpr">
+    <title>Legacy expression syntax</title>
+
+    <p>This section describes the syntax of the <code>#if expr</code>
+    element if <directive module="mod_include">SSILegacyExprParser</directive>
+    is set to <code>on</code>.</p>
 
     <dl>
       <dt><code><var>string</var></code></dt>
@@ -713,12 +743,6 @@
      be escaped.  This is regardless of their meaning to the regex engine.</p>
     </note>
 
-    <!-- mod_include does not use ap_expr, yet
-    <note><title>Reference Documentation</title>
-    <p>See also: <a href="../expr.html">Expressions in Apache HTTP Server</a>,
-    for a complete reference and examples.</p>
-    </note>
-    -->
 </section>
 
 <directivesynopsis>
@@ -856,14 +880,20 @@ displayed</description>
 
 <directivesynopsis>
 <name>SSIAccessEnable</name>
-<description>Enable the -A flag during conditional flow control processing.</description>
+<description>Enable the -A flag in legacy conditional expressions.</description>
 <syntax>SSIAccessEnable on|off</syntax>
 <default>SSIAccessEnable off</default>
 <contextlist><context>directory</context><context>.htaccess</context></contextlist>
 
 <usage>
+    <note><directive>SSIAccessEnable</directive> has no effect unless
+    <directive module="mod_include">SSILegacyExprParser</directive> is set to
+    <code>on</code>.
+    </note>
+
     <p>The <directive>SSIAccessEnable</directive> 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.
     <directive>SSIAccessEnable</directive> can take on the following values:</p>
 
     <dl>
@@ -961,7 +991,25 @@ server.</description>
       
 </usage>
 </directivesynopsis>
-  
+
+<directivesynopsis>
+<name>SSILegacyExprParser</name>
+<description>Enable compatibility mode for conditional expressions.</description>
+<syntax>SSILegacyExprParser on|off</syntax>
+<default>SSILegacyExprParser off</default>
+<contextlist><context>directory</context><context>.htaccess</context></contextlist>
+<compatibility>Available in version 2.3.13 and later.</compatibility>
+
+<usage>
+    <p>As of version 2.3.13, <module>mod_include</module> has switched to the
+    new <a href="../expr.html">ap_expr</a> syntax for conditional expressions
+    in <code>#if</code> flow control elements.  This directive allows to
+    switch to the <a href="#legacyexpr">old syntax</a> which is compatible
+    with Apache HTTPD version 2.2.x and earlier. 
+    </p>
+</usage>
+</directivesynopsis>
+
 <directivesynopsis>
 <name>XBitHack</name>
 <description>Parse SSI directives in files with the execute bit

Modified: httpd/httpd/trunk/docs/manual/upgrading.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/manual/upgrading.xml?rev=1128614&r1=1128613&r2=1128614&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/manual/upgrading.xml (original)
+++ httpd/httpd/trunk/docs/manual/upgrading.xml Sat May 28 11:47:55 2011
@@ -226,9 +226,17 @@
         now uses a boolean expression to determine if a filter is applied.
         </li>
 
-        <li><module>mod_include</module>: An SSI* config directive in directory
-        scope no longer causes all other per-directory SSI* directives to be
-        reset to their default values.
+        <li><module>mod_include</module>:
+            <ul>
+            <li>The <code>#if expr</code> element now uses the new <a
+            href="expr.html">expression parser</a>. The old syntax can be
+            restored with the new directive <directive module="include"
+            >SSILegacyExprParser</directive>.
+            </li>
+            <li>An SSI* config directive in directory scope no longer causes
+            all other per-directory SSI* directives to be reset to their
+            default values.</li>
+            </ul>
         </li>
       </ul>
     </section>

Modified: httpd/httpd/trunk/modules/filters/mod_include.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/filters/mod_include.c?rev=1128614&r1=1128613&r2=1128614&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/filters/mod_include.c (original)
+++ httpd/httpd/trunk/modules/filters/mod_include.c Sat May 28 11:47:55 2011
@@ -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_
 /* 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
     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
     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_ct
 
     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_f
             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(
     result->accessenable      = UNSET;
     result->lastmodified      = UNSET;
     result->etag              = UNSET;
+    result->accessenable      = UNSET;
 
     return result;
 }
@@ -3907,6 +4027,7 @@ static void *merge_includes_dir_config(a
     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 "