httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From s.@apache.org
Subject svn commit: r1032073 [1/3] - in /httpd/httpd/trunk: ./ include/ modules/aaa/ modules/filters/ modules/metadata/ modules/ssl/ server/
Date Sat, 06 Nov 2010 14:31:17 GMT
Author: sf
Date: Sat Nov  6 14:31:16 2010
New Revision: 1032073

URL: http://svn.apache.org/viewvc?rev=1032073&view=rev
Log:
Replace ap_expr with a parser derived from mod_ssl's parser. Make mod_ssl use
the new parser. Rework ap_expr's public interface and provide hooks for modules
to add variables and functions.

The Netware and Windows build files still need to be adjusted

Added:
    httpd/httpd/trunk/server/util_expr_eval.c
      - copied, changed from r1032057, httpd/httpd/trunk/modules/ssl/ssl_expr_eval.c
    httpd/httpd/trunk/server/util_expr_parse.c
      - copied, changed from r1032057, httpd/httpd/trunk/modules/ssl/ssl_expr_parse.c
    httpd/httpd/trunk/server/util_expr_parse.h
      - copied, changed from r1032057, httpd/httpd/trunk/modules/ssl/ssl_expr_parse.h
    httpd/httpd/trunk/server/util_expr_parse.y
      - copied, changed from r1032057, httpd/httpd/trunk/modules/ssl/ssl_expr_parse.y
    httpd/httpd/trunk/server/util_expr_private.h
      - copied, changed from r1032057, httpd/httpd/trunk/modules/ssl/ssl_expr.h
    httpd/httpd/trunk/server/util_expr_scan.c
      - copied, changed from r1032057, httpd/httpd/trunk/modules/ssl/ssl_expr_scan.c
    httpd/httpd/trunk/server/util_expr_scan.l
      - copied, changed from r1032057, httpd/httpd/trunk/modules/ssl/ssl_expr_scan.l
Removed:
    httpd/httpd/trunk/modules/ssl/ssl_expr.c
    httpd/httpd/trunk/modules/ssl/ssl_expr.h
    httpd/httpd/trunk/modules/ssl/ssl_expr_eval.c
    httpd/httpd/trunk/modules/ssl/ssl_expr_parse.c
    httpd/httpd/trunk/modules/ssl/ssl_expr_parse.h
    httpd/httpd/trunk/modules/ssl/ssl_expr_parse.y
    httpd/httpd/trunk/modules/ssl/ssl_expr_scan.c
    httpd/httpd/trunk/modules/ssl/ssl_expr_scan.l
    httpd/httpd/trunk/server/util_expr.c
Modified:
    httpd/httpd/trunk/CHANGES
    httpd/httpd/trunk/buildconf
    httpd/httpd/trunk/include/ap_expr.h
    httpd/httpd/trunk/include/ap_mmn.h
    httpd/httpd/trunk/include/http_core.h
    httpd/httpd/trunk/modules/aaa/mod_authz_core.c
    httpd/httpd/trunk/modules/filters/mod_filter.c
    httpd/httpd/trunk/modules/metadata/mod_headers.c
    httpd/httpd/trunk/modules/ssl/Makefile.in
    httpd/httpd/trunk/modules/ssl/config.m4
    httpd/httpd/trunk/modules/ssl/mod_ssl.c
    httpd/httpd/trunk/modules/ssl/ssl_engine_config.c
    httpd/httpd/trunk/modules/ssl/ssl_engine_kernel.c
    httpd/httpd/trunk/modules/ssl/ssl_engine_vars.c
    httpd/httpd/trunk/modules/ssl/ssl_private.h
    httpd/httpd/trunk/server/Makefile.in
    httpd/httpd/trunk/server/core.c
    httpd/httpd/trunk/server/main.c
    httpd/httpd/trunk/server/request.c

Modified: httpd/httpd/trunk/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/CHANGES?rev=1032073&r1=1032072&r2=1032073&view=diff
==============================================================================
--- httpd/httpd/trunk/CHANGES [utf-8] (original)
+++ httpd/httpd/trunk/CHANGES [utf-8] Sat Nov  6 14:31:16 2010
@@ -6,6 +6,12 @@ Changes with Apache 2.3.9
      Fix a denial of service attack against mod_reqtimeout.
      [Stefan Fritsch]
 
+  *) core, mod_include, mod_ssl: Move the expression parser derived from
+     mod_include back into mod_include. Replace ap_expr with a parser
+     derived from mod_ssl's parser. Make mod_ssl use the new parser. Rework
+     ap_expr's public interface and provide hooks for modules to add variables
+     and functions. [Stefan Fritsch]
+
   *) core: Do the hook sorting earlier so that the hooks are properly sorted
      for the pre_config hook and during parsing the config. [Stefan Fritsch] 
 

Modified: httpd/httpd/trunk/buildconf
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/buildconf?rev=1032073&r1=1032072&r2=1032073&view=diff
==============================================================================
--- httpd/httpd/trunk/buildconf (original)
+++ httpd/httpd/trunk/buildconf Sat Nov  6 14:31:16 2010
@@ -226,15 +226,15 @@ if [ -f `which cut` ]; then
     > httpd.spec )
 fi
 
-# ensure that the mod_ssl expression parser sources are never regenerated
+# ensure that the ap_expr expression parser sources are never regenerated
 # when running make
-echo fixing timestamps for mod_ssl sources
-cd modules/ssl
-touch ssl_expr_parse.y
+echo fixing timestamps for ap_expr sources
+cd server
+touch util_expr_parse.y
 sleep 1
-touch ssl_expr_parse.c ssl_expr_parse.h ssl_expr_scan.l
+touch util_expr_parse.c util_expr_parse.h util_expr_scan.l
 sleep 1
-touch ssl_expr_scan.c
-cd ../..
+touch util_expr_scan.c
+cd ..
 
 exit 0

Modified: httpd/httpd/trunk/include/ap_expr.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/include/ap_expr.h?rev=1032073&r1=1032072&r2=1032073&view=diff
==============================================================================
--- httpd/httpd/trunk/include/ap_expr.h (original)
+++ httpd/httpd/trunk/include/ap_expr.h Sat Nov  6 14:31:16 2010
@@ -23,128 +23,193 @@
 #define AP_EXPR_H
 
 #include "httpd.h"
+#include "http_config.h"
 #include "ap_regex.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-/* conditional expression parser stuff */
-typedef enum {
-    TOKEN_STRING,
-    TOKEN_RE,
-    TOKEN_AND,
-    TOKEN_OR,
-    TOKEN_NOT,
-    TOKEN_EQ,
-    TOKEN_NE,
-    TOKEN_RBRACE,
-    TOKEN_LBRACE,
-    TOKEN_GROUP,
-    TOKEN_GE,
-    TOKEN_LE,
-    TOKEN_GT,
-    TOKEN_LT,
-    TOKEN_ACCESS,
-    TOKEN_IN
-} token_type_t;
+/** A node in the expression parse tree */
+typedef struct ap_expr_node ap_expr;
 
+/** Struct describing a parsed expression */
 typedef struct {
-    token_type_t  type;
-    const char   *value;
-#ifdef DEBUG_INCLUDE
-    const char   *s;
-#endif
-} token_t;
+    /** The root of the actual expression parse tree */
+    ap_expr *root_node;
+    /** The filename where the expression has been defined (for logging).
+     *  May be NULL
+     */
+    const char *filename;
+    /** The line number where the expression has been defined (for logging). */
+    unsigned int line_number;
+#define AP_EXPR_FLAGS_SSL_EXPR_COMPAT       1
+    /** Flags relevant for the expression */
+    unsigned int flags;
+    /** The module that is used for loglevel configuration (XXX put into eval_ctx?) */
+    int module_index;
+} ap_expr_info_t;
 
-typedef struct parse_node {
-    struct parse_node *parent;
-    struct parse_node *left;
-    struct parse_node *right;
-    token_t token;
-    int value;
-    int done;
-#ifdef DEBUG_INCLUDE
-    int dump_done;
-#endif
-} ap_parse_node_t;
 
+/**
+ * Evaluate a parse tree
+ * @param r The current request
+ * @param expr The expression to be evaluated
+ * @param err A more detailed error string
+ * @return > 0 if expression evaluates to true, == 0 if false, < 0 on error
+ */
+AP_DECLARE(int) ap_expr_exec(request_rec *r, const ap_expr_info_t *expr,
+                             const char **err);
+
+/** Context used during evaluation of a parse tree, created by ap_expr_exec */
 typedef struct {
-    const char *source;
-    const char *rexp;
-    apr_size_t  nsub;
-    ap_regmatch_t match[AP_MAX_REG_MATCH];
-    int have_match;
-} backref_t;
+    /** the current request */
+    request_rec *r;
+    /** the current connection */
+    conn_rec *c;
+    /** the current connection */
+    server_rec *s;
+    /** the pool to use */
+    apr_pool_t *p;
+    /** where to store the error string */
+    const char **err;
+    /** ap_expr_info_t for the expression */
+    const ap_expr_info_t *info;
+} ap_expr_eval_ctx;
 
-typedef const char *(*string_func_t)(request_rec*, const char*);
-typedef int (*opt_func_t)(request_rec*, ap_parse_node_t*, string_func_t);
 
 /**
- * Parse an expression into a parse tree
- * @param pool Pool
- * @param expr The expression to parse
- * @param was_error On return, set to zero if parse successful, nonzero on error
- * @return The parse tree
+ * The parse can be extended with variable lookup, functions, and
+ * and operators.
+ *
+ * During parsing, the parser calls the lookup function to resolve a
+ * name into a function pointer and an opaque context for the function.
+ *
+ * The default lookup function is the hook 'ap_run_expr_lookup'.
+ * Modules can use it to make functions and variables generally available.
+ *
+ * An ap_expr consumer can also provide its own custom lookup function to
+ * modify the set of variables and functions that are available. The custom
+ * lookup function can in turn call 'ap_run_expr_lookup'.
  */
-AP_DECLARE(ap_parse_node_t*) ap_expr_parse(apr_pool_t *pool, const char *expr,
-                                           int *was_error);
-/**
- * Evaluate a parse tree
- * @param r The current request
- * @param root The root node of the parse tree
- * @param was_error On return, set to zero if parse successful, nonzero on error
- * @param reptr Regular expression memory for backreferencing if a regexp was parsed
- * @param string_func String parser function - perform variable substitutions
- *                    Use ap_expr_string where applicable
- * @param eval_func Option evaluation function (e.g. -A filename)
- * @return the value the expression parsed to
- */
-AP_DECLARE(int) ap_expr_eval(request_rec *r, const ap_parse_node_t *root,
-                             int *was_error, backref_t **reptr,
-                             string_func_t string_func, opt_func_t eval_func);
-/**
- * Evaluate an expression.  This is functionally equivalent to
- * ap_expr_parse followed by ap_expr_eval, but faster and more efficient
- * when an expression only needs to be parsed once and discarded.
- * @param r The current request
- * @param expr The expression to parse
- * @param was_error On return, set to zero if parse successful, nonzero on error
- * @param reptr Regular expression memory for backreferencing if a regexp was parsed
- * @param string_func String parser function - perform variable substitutions
- *                    Use ap_expr_string where applicable
- * @param eval_func Option evaluation function (e.g. -A filename)
- * @return the value the expression parsed to
- */
-AP_DECLARE(int) ap_expr_evalstring(request_rec *r, const char *expr,
-                                   int *was_error, backref_t **reptr,
-                                   string_func_t string_func,
-                                   opt_func_t eval_func);
+
+/** Unary operator, takes one string argument and returns a bool value.
+ * The name must have the form '-z' (one letter only).
+ * @param ctx The evaluation context
+ * @param data An opaque context provided by the lookup hook function
+ * @param arg The (right) operand
+ * @return 0 or 1
+ */
+typedef int ap_expr_op_unary_t(ap_expr_eval_ctx *ctx, const void *data,
+                               const char *arg);
+
+/** Binary operator, takes two string arguments and returns a bool value.
+ * The name must have the form '-cmp' (at least two letters).
+ * @param ctx The evaluation context
+ * @param data An opaque context provided by the lookup hook function
+ * @param arg1 The left operand
+ * @param arg2 The right operand
+ * @return 0 or 1
+ */
+typedef int ap_expr_op_binary_t(ap_expr_eval_ctx *ctx, const void *data,
+                                const char *arg1, const char *arg2);
+
+/** String valued function, takes a string argument and returns a string
+ * @param ctx The evaluation context
+ * @param data An opaque context provided by the lookup hook function
+ * @param arg The argument
+ * @return The functions result string, may be NULL for 'empty string'
+ */
+typedef const char *(ap_expr_string_func_t)(ap_expr_eval_ctx *ctx, const void *data,
+                                            const char *arg);
+
+/** List valued function, takes a string argument and returns a list of strings
+ * Can currently only be called following the builtin '-in' operator.
+ * @param ctx The evaluation context
+ * @param data An opaque context provided by the lookup hook function
+ * @param arg The argument
+ * @return The functions result list of strings, may be NULL for 'empty array'
+ */
+typedef apr_array_header_t *(ap_expr_list_func_t)(ap_expr_eval_ctx *ctx, const void *data,
+                                                  const char *arg);
+
+/** Variable lookup function, takes no argument and returns a string
+ * @param ctx The evaluation context
+ * @param data An opaque context provided by the lookup hook function
+ * @return The expanded variable
+ */
+typedef const char *(ap_expr_var_func_t)(ap_expr_eval_ctx *ctx, const void *data);
+
+/** parameter struct passed to the lookup hook functions */
+typedef struct {
+    /** type of the looked up object */
+    int type;
+#define AP_EXPR_FUNC_VAR        0
+#define AP_EXPR_FUNC_STRING     1
+#define AP_EXPR_FUNC_LIST       2
+#define AP_EXPR_FUNC_OP_UNARY   3
+#define AP_EXPR_FUNC_OP_BINARY  4
+    /** name of the looked up object */
+    const char *name;
+
+    int flags;
+
+    apr_pool_t *pool;
+    apr_pool_t *ptemp;
+
+    /** where to store the function pointer */
+    const void **func;
+    /** where to store the function's context */
+    const void **data;
+    /** Where to store the error message (if any) */
+    const char **err;
+} ap_expr_lookup_parms;
+
+/** Function for looking up the provider function for a variable, operator
+ *  or function in an expression.
+ *  @param parms The parameter struct, also determins where the result is
+ *               stored.
+ *  @return OK on success,
+ *          !OK on failure,
+ *          DECLINED if the requested name is not handled by this function
+ */
+typedef int (ap_expr_lookup_fn)(ap_expr_lookup_parms *parms);
+
+AP_DECLARE_HOOK(int, expr_lookup, (ap_expr_lookup_parms *parms))
 
 /**
- * Internal initialisation of ap_expr (for httpd)
+ * Parse an expression into a parse tree
  * @param pool Pool
- * @return APR_SUCCESS or error
+ * @param ptemp temp pool
+ * @param info The ap_expr_info_t struct (with values filled in)
+ * @param expr The expression string to parse
+ * @param lookup_fn The lookup function to use, NULL for default
+ * @return NULL on success, error message on error.
+ *         A pointer to the resulting parse tree will be stored in
+ *         info->root_node.
  */
-AP_DECLARE(apr_status_t) ap_expr_init(apr_pool_t *pool);
+AP_DECLARE(const char *) ap_expr_parse(apr_pool_t *pool, apr_pool_t *ptemp,
+                                       ap_expr_info_t *info, const char *expr,
+                                       ap_expr_lookup_fn *lookup_fn);
 
 /**
- * Default string evaluation function for passing to ap_expr_eval and
- * ap_expr_evalstring.  Use this (and update as necessary) to offer
- * a consistent expression syntax across different modules.
- * Supports the following:
- *     $req{foo}     - request header "foo"
- *     $resp{foo}    - response header "foo"
- *     $env{foo}     - environment variable "foo"
- *     $handler      - r->handler
- *     $content-type - r->content_type
- * Other strings are returned unmodified.
- * @param r The current request
- * @param str The string to evaluate
- * @return The evaluated string
+ * High level interface to ap_expr_parse that also creates ap_expr_info_t and
+ * uses info from cmd_parms to fill in most of it.
+ * @param cmd The cmd_parms struct
+ * @param expr The expression string to parse
+ * @param err Set to NULL on success, error message on error
+ * @return The parsed expression
  */
-AP_DECLARE_NONSTD(const char*) ap_expr_string(request_rec *r, 
-                                              const char *str);
+AP_DECLARE(ap_expr_info_t *) ap_expr_parse_cmd(const cmd_parms *cmd,
+                                               const char *expr,
+                                               const char **err,
+                                               ap_expr_lookup_fn *lookup_fn);
+
+
+ /**
+  * Internal initialisation of ap_expr (for httpd internal use)
+  */
+void ap_expr_init(apr_pool_t *pool);
 
 #ifdef __cplusplus
 }

Modified: httpd/httpd/trunk/include/ap_mmn.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/include/ap_mmn.h?rev=1032073&r1=1032072&r2=1032073&view=diff
==============================================================================
--- httpd/httpd/trunk/include/ap_mmn.h (original)
+++ httpd/httpd/trunk/include/ap_mmn.h Sat Nov  6 14:31:16 2010
@@ -277,12 +277,16 @@
  * 20101016.0 (2.3.9-dev)  Remove ap_cache_check_allowed().
  * 20101017.0 (2.3.9-dev)  Make ap_cache_control() public, add cache_control_t
  *                         to mod_disk_cache format.
+ * 20101106.0 (2.3.9-dev)  Replace the ap_expr parser derived from
+ *                         mod_include's parser with one derived from
+ *                         mod_ssl's parser. Clean up ap_expr's public
+ *                         interface.
  */
 
 #define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */
 
 #ifndef MODULE_MAGIC_NUMBER_MAJOR
-#define MODULE_MAGIC_NUMBER_MAJOR 20101017
+#define MODULE_MAGIC_NUMBER_MAJOR 20101106
 #endif
 #define MODULE_MAGIC_NUMBER_MINOR 0                     /* 0...n */
 

Modified: httpd/httpd/trunk/include/http_core.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/include/http_core.h?rev=1032073&r1=1032072&r2=1032073&view=diff
==============================================================================
--- httpd/httpd/trunk/include/http_core.h (original)
+++ httpd/httpd/trunk/include/http_core.h Sat Nov  6 14:31:16 2010
@@ -534,7 +534,7 @@ typedef struct {
 #define USE_CANONICAL_PHYS_PORT_UNSET (2)
     unsigned use_canonical_phys_port : 2;
 
-    ap_parse_node_t *condition;   /* Conditionally merge <If> sections */
+    ap_expr_info_t *condition;   /* Conditionally merge <If> sections */
 
     /** per-dir log config */
     struct ap_logconf *log;

Modified: httpd/httpd/trunk/modules/aaa/mod_authz_core.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/aaa/mod_authz_core.c?rev=1032073&r1=1032072&r2=1032073&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/aaa/mod_authz_core.c (original)
+++ httpd/httpd/trunk/modules/aaa/mod_authz_core.c Sat Nov  6 14:31:16 2010
@@ -988,20 +988,22 @@ static authz_status expr_check_authoriza
                                              const char *require_line,
                                              const void *parsed_require_line)
 {
-    int err = 0;
-    const ap_parse_node_t *expr = parsed_require_line;
+    const char *err = NULL;
+    const ap_expr_info_t *expr = parsed_require_line;
+    int rc = ap_expr_exec(r, expr, &err);
 
-    if (ap_expr_eval(r, expr, &err, NULL, ap_expr_string, NULL))
-        return AUTHZ_GRANTED;
-    else
+    if (err || !rc)
+	    /* XXX: real error handling? */
         return AUTHZ_DENIED;
+    else
+        return AUTHZ_GRANTED;
 }
 
 static const char *expr_parse_config(cmd_parms *cmd, const char *require_line,
                                      const void **parsed_require_line)
 {
-    int expr_err = 0;
-    ap_parse_node_t *expr = ap_expr_parse(cmd->pool, require_line, &expr_err);
+    const char *expr_err = NULL;
+    ap_expr_info_t *expr = ap_expr_parse_cmd(cmd, require_line, &expr_err, NULL);
 
     if (expr_err)
         return "Cannot parse expression in require line";

Modified: httpd/httpd/trunk/modules/filters/mod_filter.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/filters/mod_filter.c?rev=1032073&r1=1032072&r2=1032073&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/filters/mod_filter.c (original)
+++ httpd/httpd/trunk/modules/filters/mod_filter.c Sat Nov  6 14:31:16 2010
@@ -36,7 +36,7 @@ module AP_MODULE_DECLARE_DATA filter_mod
  * (2.0-compatible) ap_filter_rec_t* frec.
  */
 struct ap_filter_provider_t {
-    ap_parse_node_t *expr;
+    ap_expr_info_t *expr;
 
     /** The filter that implements this provider */
     ap_filter_rec_t *frec;
@@ -134,7 +134,7 @@ static int filter_lookup(ap_filter_t *f,
 {
     ap_filter_provider_t *provider;
     int match;
-    int err = 0;
+    const char *err = NULL;
     unsigned int proto_flags;
     request_rec *r = f->r;
     harness_ctx *ctx = f->ctx;
@@ -146,11 +146,12 @@ static int filter_lookup(ap_filter_t *f,
 
     /* Check registered providers in order */
     for (provider = filter->providers; provider; provider = provider->next) {
-        match = ap_expr_eval(r, provider->expr, &err, NULL, ap_expr_string, NULL);
+        match = ap_expr_exec(r, provider->expr, &err);
         if (err) {
             /* log error but accept match value ? */
             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
-                          "Error evaluating filter dispatch condition");
+                          "Error evaluating filter dispatch condition: %s",
+                          err);
         }
 
         if (match) {
@@ -402,8 +403,8 @@ static const char *filter_provider(cmd_p
     const char *c;
     ap_filter_rec_t* frec;
     ap_filter_rec_t* provider_frec;
-    ap_parse_node_t *node;
-    int err = 0;
+    ap_expr_info_t *node;
+    const char *err = NULL;
 
     /* fname has been declared with DeclareFilter, so we can look it up */
     frec = apr_hash_get(cfg->live_filters, fname, APR_HASH_KEY_STRING);
@@ -426,9 +427,11 @@ static const char *filter_provider(cmd_p
     if (!provider_frec) {
         return apr_psprintf(cmd->pool, "Unknown filter provider %s", pname);
     }
-    node = ap_expr_parse(cmd->pool, expr, &err);
+    node = ap_expr_parse_cmd(cmd, expr, &err, NULL);
     if (err) {
-        return "Error parsing FilterProvider expression.";
+        return apr_pstrcat(cmd->pool,
+                           "Error parsing FilterProvider expression:", err,
+                           NULL);
     }
 
     provider = apr_palloc(cmd->pool, sizeof(ap_filter_provider_t));
@@ -545,7 +548,7 @@ static const char *filter_bytype1(cmd_pa
         *p++ = *type++;
     } while (*type);
     *p = 0;
-    expr = apr_psprintf(cmd->temp_pool, "$content-type = /^%s/", etype);
+    expr = apr_psprintf(cmd->temp_pool, "%%{CONTENT_TYPE} =~ m!^%s!", etype);
 
     rv = filter_provider(cmd, CFG, fname, pname, expr);
 

Modified: httpd/httpd/trunk/modules/metadata/mod_headers.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/metadata/mod_headers.c?rev=1032073&r1=1032072&r2=1032073&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/metadata/mod_headers.c (original)
+++ httpd/httpd/trunk/modules/metadata/mod_headers.c Sat Nov  6 14:31:16 2010
@@ -130,7 +130,7 @@ typedef struct {
     ap_regex_t *regex;
     const char *condition_var;
     const char *subs;
-    ap_parse_node_t *expr;
+    ap_expr_info_t *expr;
 } header_entry;
 
 /* echo_do is used for Header echo to iterate through the request headers*/
@@ -398,7 +398,7 @@ static APR_INLINE const char *header_ino
     const char *condition_var = NULL;
     const char *colon;
     header_entry *new;
-    ap_parse_node_t *expr = NULL;
+    ap_expr_info_t *expr = NULL;
 
     apr_array_header_t *fixup = (cmd->info == &hdr_in)
         ? dirconf->fixup_in   : (cmd->info == &hdr_out_always)
@@ -491,10 +491,12 @@ static APR_INLINE const char *header_ino
             condition_var = envclause + 4;
         }
         else {
-            int err = 0;
-            expr = ap_expr_parse(cmd->pool, envclause, &err);
+            const char *err = NULL;
+            expr = ap_expr_parse_cmd(cmd, envclause, &err, NULL);
             if (err) {
-                return "Can't parse envclause/expression";
+                return apr_pstrcat(cmd->pool,
+                                   "Can't parse envclause/expression: ", err,
+                                   NULL);
             }
         }
     }
@@ -645,12 +647,12 @@ static void do_headers_fixup(request_rec
         }
         /* Do we have an expression to evaluate? */
         else if (hdr->expr != NULL) {
-            int err = 0;
-            int eval = ap_expr_eval(r, hdr->expr, &err, NULL,
-                                    ap_expr_string, NULL);
+            const char *err = NULL;
+            int eval = ap_expr_exec(r, hdr->expr, &err);
             if (err) {
                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
-                              "Failed to evaluate expression - ignoring");
+                              "Failed to evaluate expression (%s) - ignoring",
+                              err);
             }
             else if (!eval) {
                 continue;

Modified: httpd/httpd/trunk/modules/ssl/Makefile.in
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ssl/Makefile.in?rev=1032073&r1=1032072&r2=1032073&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/ssl/Makefile.in (original)
+++ httpd/httpd/trunk/modules/ssl/Makefile.in Sat Nov  6 14:31:16 2010
@@ -18,20 +18,3 @@
 #
 
 include $(top_srcdir)/build/special.mk
-
-#
-#   developer stuff
-#   (we really don't expect end users to use these targets!)
-#
-
-ssl_expr_scan.c: $(top_srcdir)/modules/ssl/ssl_expr_scan.l ssl_expr_parse.h
-	flex -Pssl_expr_yy -o ssl_expr_scan.c $(top_srcdir)/ssl_expr_scan.l
-	mv ssl_expr_scan.c ssl_expr_scan.c.tmp
-	sed -e "s|\"`pwd`/|\"|g" <ssl_expr_scan.c.tmp >ssl_expr_scan.c
-	rm -f ssl_expr_scan.c.tmp
-
-ssl_expr_parse.c ssl_expr_parse.h: $(top_srcdir)/modules/ssl/ssl_expr_parse.y
-	bison -pssl_expr_yy --defines=ssl_expr_parse.h -o ssl_expr_parse.c $(top_srcdir)/modules/ssl/ssl_expr_parse.y
-	mv ssl_expr_parse.c ssl_expr_parse.c.tmp
-	sed -e "s|\"`pwd`/|\"|g" < ssl_expr_parse.c.tmp > ssl_expr_parse.c
-	rm -f ssl_expr_parse.c.tmp

Modified: httpd/httpd/trunk/modules/ssl/config.m4
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ssl/config.m4?rev=1032073&r1=1032072&r2=1032073&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/ssl/config.m4 (original)
+++ httpd/httpd/trunk/modules/ssl/config.m4 Sat Nov  6 14:31:16 2010
@@ -35,10 +35,6 @@ ssl_engine_mutex.lo dnl
 ssl_engine_pphrase.lo dnl
 ssl_engine_rand.lo dnl
 ssl_engine_vars.lo dnl
-ssl_expr.lo dnl
-ssl_expr_eval.lo dnl
-ssl_expr_parse.lo dnl
-ssl_expr_scan.lo dnl
 ssl_scache.lo dnl
 ssl_util_stapling.lo dnl
 ssl_util.lo dnl

Modified: httpd/httpd/trunk/modules/ssl/mod_ssl.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ssl/mod_ssl.c?rev=1032073&r1=1032072&r2=1032073&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/ssl/mod_ssl.c (original)
+++ httpd/httpd/trunk/modules/ssl/mod_ssl.c Sat Nov  6 14:31:16 2010
@@ -565,11 +565,6 @@ static void ssl_register_hooks(apr_pool_
                               &ssl_authz_provider_verify_client,
                               AP_AUTH_INTERNAL_PER_CONF);
 
-    ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "ssl-require",
-                              AUTHZ_PROVIDER_VERSION,
-                              &ssl_authz_provider_sslrequire,
-                              AP_AUTH_INTERNAL_PER_CONF);
-
 }
 
 module AP_MODULE_DECLARE_DATA ssl_module = {

Modified: httpd/httpd/trunk/modules/ssl/ssl_engine_config.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ssl/ssl_engine_config.c?rev=1032073&r1=1032072&r2=1032073&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/ssl/ssl_engine_config.c (original)
+++ httpd/httpd/trunk/modules/ssl/ssl_engine_config.c Sat Nov  6 14:31:16 2010
@@ -1147,17 +1147,21 @@ const char *ssl_cmd_SSLRequire(cmd_parms
                                const char *arg)
 {
     SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg;
-    ssl_expr *expr;
+    ap_expr_info_t *info = apr_pcalloc(cmd->pool, sizeof(ap_expr_info_t));
     ssl_require_t *require;
     const char *errstring;
 
-    if (!(expr = ssl_expr_comp(cmd->pool, arg, &errstring))) {
+    info->flags = AP_EXPR_FLAGS_SSL_EXPR_COMPAT;
+    info->filename = cmd->directive->filename;
+    info->line_number = cmd->directive->line_num;
+    errstring = ap_expr_parse(cmd->pool, cmd->temp_pool, info, arg, NULL);
+    if (errstring) {
         return apr_pstrcat(cmd->pool, "SSLRequire: ", errstring, NULL);
     }
 
     require = apr_array_push(dc->aRequirement);
     require->cpExpr = apr_pstrdup(cmd->pool, arg);
-    require->mpExpr = expr;
+    require->mpExpr = info;
 
     return NULL;
 }

Modified: httpd/httpd/trunk/modules/ssl/ssl_engine_kernel.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ssl/ssl_engine_kernel.c?rev=1032073&r1=1032072&r2=1032073&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/ssl/ssl_engine_kernel.c (original)
+++ httpd/httpd/trunk/modules/ssl/ssl_engine_kernel.c Sat Nov  6 14:31:16 2010
@@ -302,7 +302,6 @@ int ssl_hook_Access(request_rec *r)
     SSL_CTX *ctx = NULL;
     apr_array_header_t *requires;
     ssl_require_t *ssl_requires;
-    char *cp;
     int ok, i;
     BOOL renegotiate = FALSE, renegotiate_quick = FALSE;
     X509 *cert;
@@ -900,17 +899,13 @@ int ssl_hook_Access(request_rec *r)
     for (i = 0; i < requires->nelts; i++) {
         ssl_require_t *req = &ssl_requires[i];
         const char *errstring;
-        ok = ssl_expr_exec(r, req->mpExpr, &errstring);
+        ok = ap_expr_exec(r, req->mpExpr, &errstring);
 
         if (ok < 0) {
-            cp = apr_psprintf(r->pool,
-                              "Failed to execute "
-                              "SSL requirement expression: %s",
-                              errstring);
-
             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
-                          "access to %s failed, reason: %s",
-                          r->filename, cp);
+                          "access to %s failed, reason: Failed to execute "
+                          "SSL requirement expression: %s",
+                          r->filename, errstring);
 
             /* remember forbidden access for strict require option */
             apr_table_setn(r->notes, "ssl-access-forbidden", "1");
@@ -1282,54 +1277,6 @@ const authz_provider ssl_authz_provider_
 };
 
 
-static authz_status ssl_authz_sslrequire_check(request_rec *r,
-                                               const char *require_line,
-                                               const void *parsed)
-{
-    const ssl_expr *expr = parsed;
-    const char *errstring;
-    int ok = ssl_expr_exec(r, expr, &errstring);
-
-    if (ok < 0) {
-        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
-                      "Failed to execute SSL requirement expression in "
-                      "'Require ssl-require': %s",
-                      errstring);
-        return AUTHZ_DENIED;
-    }
-
-    if (ok != 1) {
-        ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
-                      "SSL requirement expression in 'Require ssl-require' "
-                      "not fulfilled");
-        return AUTHZ_DENIED;
-    }
-
-    return AUTHZ_GRANTED;
-}
-
-static const char *ssl_authz_sslrequire_parse(cmd_parms *cmd,
-                                              const char *require_line,
-                                              const void **parsed)
-{
-    const char *errstring;
-    ssl_expr *expr = ssl_expr_comp(cmd->pool, require_line, &errstring);
-
-    if (!expr)
-        return apr_psprintf(cmd->pool, "Error in 'Require require-ssl': %s",
-                            errstring);
-
-    *parsed = expr;
-
-    return NULL;
-}
-
-const authz_provider ssl_authz_provider_sslrequire =
-{
-    &ssl_authz_sslrequire_check,
-    &ssl_authz_sslrequire_parse,
-};
-
 
 /*  _________________________________________________________________
 **

Modified: httpd/httpd/trunk/modules/ssl/ssl_engine_vars.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ssl/ssl_engine_vars.c?rev=1032073&r1=1032072&r2=1032073&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/ssl/ssl_engine_vars.c (original)
+++ httpd/httpd/trunk/modules/ssl/ssl_engine_vars.c Sat Nov  6 14:31:16 2010
@@ -29,6 +29,7 @@
                                                   -- Unknown       */
 #include "ssl_private.h"
 #include "mod_ssl.h"
+#include "ap_expr.h"
 
 #include "apr_time.h"
 
@@ -62,6 +63,45 @@ static const char var_interface[] = "mod
 static char var_library_interface[] = SSL_LIBRARY_TEXT;
 static char *var_library = NULL;
 
+static apr_array_header_t *expr_peer_ext_list_fn(ap_expr_eval_ctx *ctx,
+                                                 const void *dummy,
+                                                 const char *arg)
+{
+    return ssl_ext_list(ctx->p, ctx->c, 1, arg);
+}
+
+static const char *expr_var_fn(ap_expr_eval_ctx *ctx, const void *data)
+{
+    char *var = (char *)data;
+    return ssl_var_lookup_ssl(ctx->p, ctx->c, var);
+}
+
+static int ssl_expr_lookup(ap_expr_lookup_parms *parms)
+{
+    switch (parms->type) {
+    case AP_EXPR_FUNC_VAR:
+        /* for now, we just handle everything that starts with SSL_, but
+         * register our hook as APR_HOOK_LAST
+         * XXX: This can be optimized
+         */
+        if (strcEQn(parms->name, "SSL_", 4)) {
+            *parms->func = expr_var_fn;
+            *parms->data = parms->name + 4;
+            return OK;
+        }
+        break;
+    case AP_EXPR_FUNC_LIST:
+        if (strcEQ(parms->name, "PeerExtList")) {
+            *parms->func = expr_peer_ext_list_fn;
+            *parms->data = "PeerExtList";
+            return OK;
+        }
+	break;
+    }
+    return DECLINED;
+}
+
+
 void ssl_var_register(apr_pool_t *p)
 {
     char *cp, *cp2;
@@ -84,6 +124,8 @@ void ssl_var_register(apr_pool_t *p)
         if ((cp2 = strchr(cp, ' ')) != NULL)
             *cp2 = NUL;
     }
+
+    ap_hook_expr_lookup(ssl_expr_lookup, NULL, NULL, APR_HOOK_MIDDLE);
 }
 
 /* This function must remain safe to use for a non-SSL connection. */
@@ -984,3 +1026,4 @@ static const char *ssl_var_log_handler_x
     return result;
 }
 
+

Modified: httpd/httpd/trunk/modules/ssl/ssl_private.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ssl/ssl_private.h?rev=1032073&r1=1032072&r2=1032073&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/ssl/ssl_private.h (original)
+++ httpd/httpd/trunk/modules/ssl/ssl_private.h Sat Nov  6 14:31:16 2010
@@ -55,9 +55,38 @@
 
 #define MOD_SSL_VERSION AP_SERVER_BASEREVISION
 
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE !FALSE
+#endif
+
+#ifndef YY_NULL
+#define YY_NULL 0
+#endif
+
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+#ifndef BOOL
+#define BOOL unsigned int
+#endif
+
+#ifndef NULL
+#define NULL (void *)0
+#endif
+
+#ifndef NUL
+#define NUL '\0'
+#endif
+
+
 /* mod_ssl headers */
 #include "ssl_toolkit_compat.h"
-#include "ssl_expr.h"
+#include "ap_expr.h"
 #include "ssl_util_ssl.h"
 
 /* The #ifdef macros are only defined AFTER including the above
@@ -272,8 +301,8 @@ typedef enum {
  * Define the SSL requirement structure
  */
 typedef struct {
-    char     *cpExpr;
-    ssl_expr *mpExpr;
+    char           *cpExpr;
+    ap_expr_info_t *mpExpr;
 } ssl_require_t;
 
 /**
@@ -617,7 +646,6 @@ void         ssl_hook_ConfigTest(apr_poo
 /** Apache authz provisders */
 extern const authz_provider ssl_authz_provider_require_ssl;
 extern const authz_provider ssl_authz_provider_verify_client;
-extern const authz_provider ssl_authz_provider_sslrequire;
 
 /**  OpenSSL callbacks */
 RSA         *ssl_callback_TmpRSA(SSL *, int, int);

Modified: httpd/httpd/trunk/server/Makefile.in
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/Makefile.in?rev=1032073&r1=1032072&r2=1032073&view=diff
==============================================================================
--- httpd/httpd/trunk/server/Makefile.in (original)
+++ httpd/httpd/trunk/server/Makefile.in Sat Nov  6 14:31:16 2010
@@ -12,9 +12,10 @@ LTLIBRARY_SOURCES = \
 	util_script.c util_md5.c util_cfgtree.c util_ebcdic.c util_time.c \
 	connection.c listen.c util_mutex.c mpm_common.c mpm_unix.c \
 	util_charset.c util_cookies.c util_debug.c util_xml.c \
-	util_expr.c util_filter.c util_pcre.c util_regex.c exports.c \
+	util_filter.c util_pcre.c util_regex.c exports.c \
 	scoreboard.c error_bucket.c protocol.c core.c request.c provider.c \
-	eoc_bucket.c eor_bucket.c core_filters.c
+	eoc_bucket.c eor_bucket.c core_filters.c \
+	util_expr_parse.c util_expr_scan.c util_expr_eval.c
 
 TARGETS = delete-exports $(LTLIBRARY_NAME) $(CORE_IMPLIB_FILE) export_vars.h httpd.exp
 
@@ -83,3 +84,19 @@ httpd.exp: exports.c export_vars.h
 	@echo "* Please do not edit by hand." >> $@
 	$(CPP) $(ALL_CPPFLAGS) $(ALL_INCLUDES) exports.c | grep "ap_hack_" | grep -v apr_ | sed -e 's/^.*[)]\(.*\);$$/\1/' >> $@
 	$(CPP) $(ALL_CPPFLAGS) $(ALL_INCLUDES) export_vars.h | grep -v apr_ | sed -e 's/^\#[^!]*//' | sed -e '/^$$/d' >> $@
+
+
+#   developer stuff
+#   (we really don't expect end users to use these targets!)
+#
+util_expr_scan.c util_expr_parse.c util_expr_parse.h: util_expr_scan.l util_expr_parse.y
+	bison -pap_expr_yy --defines=$(builddir)/util_expr_parse.h \
+	    -o $(builddir)/util_expr_parse.c $(srcdir)/util_expr_parse.y
+	flex -Pap_expr_yy -o $(builddir)/util_expr_scan.c $(srcdir)/util_expr_scan.l
+	set -e ; \
+	for f in util_expr_scan.c util_expr_parse.c util_expr_parse.h ; do \
+		sed -e "s|\"$(builddir)/|\"|g" < $(builddir)/$$f > \
+			$(builddir)/$$f.$$$$ && \
+		mv $(builddir)/$$f.$$$$ $(builddir)/$$f ; \
+	done
+

Modified: httpd/httpd/trunk/server/core.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/core.c?rev=1032073&r1=1032072&r2=1032073&view=diff
==============================================================================
--- httpd/httpd/trunk/server/core.c (original)
+++ httpd/httpd/trunk/server/core.c Sat Nov  6 14:31:16 2010
@@ -1986,7 +1986,7 @@ static const char *ifsection(cmd_parms *
     const char *err = ap_check_cmd_context(cmd,
                                            NOT_IN_LOCATION | NOT_IN_LIMIT);
     const char *condition;
-    int expr_err = 0;
+    const char *expr_err;
 
     if (err != NULL) {
         return err;
@@ -2012,9 +2012,9 @@ static const char *ifsection(cmd_parms *
     conf = ap_set_config_vectors(cmd->server, new_file_conf, cmd->path,
                                  &core_module, cmd->pool);
 
-    conf->condition = ap_expr_parse(cmd->pool, condition, &expr_err);
+    conf->condition = ap_expr_parse_cmd(cmd, condition, &expr_err, NULL);
     if (expr_err) {
-        return "Cannot parse condition clause";
+        return apr_psprintf(cmd->pool, "Cannot parse condition clause: %s", expr_err);
     }
 
     errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_file_conf);
@@ -4133,6 +4133,7 @@ static void register_hooks(apr_pool_t *p
 {
     errorlog_hash = apr_hash_make(p);
     ap_register_log_hooks(p);
+    ap_expr_init(p);
 
     /* create_connection and pre_connection should always be hooked
      * APR_HOOK_REALLY_LAST by core to give other modules the opportunity

Modified: httpd/httpd/trunk/server/main.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/main.c?rev=1032073&r1=1032072&r2=1032073&view=diff
==============================================================================
--- httpd/httpd/trunk/server/main.c (original)
+++ httpd/httpd/trunk/server/main.c Sat Nov  6 14:31:16 2010
@@ -39,7 +39,6 @@
 #include "apr_uri.h"
 #include "util_ebcdic.h"
 #include "ap_mpm.h"
-#include "ap_expr.h"
 
 #if APR_HAVE_UNISTD_H
 #include <unistd.h>
@@ -472,9 +471,6 @@ int main(int argc, const char * const ar
         destroy_and_exit_process(process, 1);
     }
 #endif
-    if (ap_expr_init(ap_pglobal) != APR_SUCCESS) {
-        destroy_and_exit_process(process, 1);
-    }
 
     apr_pool_create(&pcommands, ap_pglobal);
     apr_pool_tag(pcommands, "pcommands");

Modified: httpd/httpd/trunk/server/request.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/request.c?rev=1032073&r1=1032072&r2=1032073&view=diff
==============================================================================
--- httpd/httpd/trunk/server/request.c (original)
+++ httpd/httpd/trunk/server/request.c Sat Nov  6 14:31:16 2010
@@ -1529,13 +1529,13 @@ AP_DECLARE(int) ap_file_walk(request_rec
          * really try them with the most general first.
          */
         for (sec_idx = 0; sec_idx < num_sec; ++sec_idx) {
-            int err = 0;
+            const char *err = NULL;
             core_dir_config *entry_core;
             entry_core = ap_get_module_config(sec_ent[sec_idx], &core_module);
 
             if (entry_core->condition) {
-                if (!ap_expr_eval(r, entry_core->condition, &err, NULL,
-                                  ap_expr_string, NULL)) {
+                /* XXX: error handling */
+                if (!ap_expr_exec(r, entry_core->condition, &err)) {
                     continue;
                 }
             }

Copied: httpd/httpd/trunk/server/util_expr_eval.c (from r1032057, httpd/httpd/trunk/modules/ssl/ssl_expr_eval.c)
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/util_expr_eval.c?p2=httpd/httpd/trunk/server/util_expr_eval.c&p1=httpd/httpd/trunk/modules/ssl/ssl_expr_eval.c&r1=1032057&r2=1032073&rev=1032073&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/ssl/ssl_expr_eval.c (original)
+++ httpd/httpd/trunk/server/util_expr_eval.c Sat Nov  6 14:31:16 2010
@@ -15,276 +15,1010 @@
  */
 
 /*                      _             _
- *  _ __ ___   ___   __| |    ___ ___| |  mod_ssl
- * | '_ ` _ \ / _ \ / _` |   / __/ __| |  Apache Interface to OpenSSL
- * | | | | | | (_) | (_| |   \__ \__ \ |
- * |_| |_| |_|\___/ \__,_|___|___/___/_|
- *                      |_____|
- *  ssl_expr_eval.c
- *  Expression Evaluation
+ *  ap_expr_eval.c, based on ssl_expr_eval.c from mod_ssl
  */
-                             /* ``Make love,
-                                  not software!''
-                                        -- Unknown */
-#include "ssl_private.h"
-
-/*  _________________________________________________________________
-**
-**  Expression Evaluation
-**  _________________________________________________________________
-*/
-
-static BOOL  ssl_expr_eval_comp(request_rec *, ssl_expr *, const char **err);
-static char *ssl_expr_eval_word(request_rec *, ssl_expr *, const char **err);
-static BOOL  ssl_expr_eval_oid(request_rec *r, const char *word,
-                               const char *oidstr, const char **err);
-static char *ssl_expr_eval_func_file(request_rec *, char *, const char **err);
-static int   ssl_expr_eval_strcmplex(char *, char *, const char **err);
 
-BOOL ssl_expr_eval(request_rec *r, const ssl_expr *node, const char **err)
+#include "httpd.h"
+#include "http_log.h"
+#include "http_core.h"
+#include "http_protocol.h"
+#include "ap_provider.h"
+#include "util_expr_private.h"
+
+#include "apr_lib.h"
+
+APLOG_USE_MODULE(core);
+
+APR_HOOK_STRUCT(
+    APR_HOOK_LINK(expr_lookup)
+)
+
+AP_IMPLEMENT_HOOK_RUN_FIRST(int, expr_lookup, (ap_expr_lookup_parms *parms),
+                            (parms), DECLINED)
+
+static const char *ap_expr_eval_string_func(ap_expr_eval_ctx *ctx, const ap_expr *info,
+                                            const ap_expr *args);
+static const char *ap_expr_eval_var(ap_expr_eval_ctx *ctx,
+                                    const ap_expr_var_func_t *func,
+                                    const void *data);
+static void expr_dump_tree(const ap_expr *e, const server_rec *s, int loglevel, int indent);
+
+static const char *ap_expr_eval_word(ap_expr_eval_ctx *ctx, const ap_expr *node)
 {
+    const char *result = "";
     switch (node->node_op) {
-        case op_True: {
-            return TRUE;
-        }
-        case op_False: {
-            return FALSE;
-        }
-        case op_Not: {
-            ssl_expr *e = (ssl_expr *)node->node_arg1;
-            return (!ssl_expr_eval(r, e, err));
-        }
-        case op_Or: {
-            ssl_expr *e1 = (ssl_expr *)node->node_arg1;
-            ssl_expr *e2 = (ssl_expr *)node->node_arg2;
-            return (ssl_expr_eval(r, e1, err) || ssl_expr_eval(r, e2, err));
-        }
-        case op_And: {
-            ssl_expr *e1 = (ssl_expr *)node->node_arg1;
-            ssl_expr *e2 = (ssl_expr *)node->node_arg2;
-            return (ssl_expr_eval(r, e1, err) && ssl_expr_eval(r, e2, err));
-        }
-        case op_Comp: {
-            ssl_expr *e = (ssl_expr *)node->node_arg1;
-            return ssl_expr_eval_comp(r, e, err);
-        }
-        default: {
-            *err = "Internal evaluation error: Unknown expression node";
-            return FALSE;
+        case op_Digit:
+            result = node->node_arg1;
+            break;
+        case op_String:
+            result = node->node_arg1;
+            break;
+        case op_Var:
+            result = ap_expr_eval_var(ctx, node->node_arg1, node->node_arg2);
+            break;
+        case op_StringFuncCall: {
+            const ap_expr *info = node->node_arg1;
+            const ap_expr *args = node->node_arg2;
+            result = ap_expr_eval_string_func(ctx, info, args);
+            break;
         }
+        default:
+            *ctx->err = "Internal evaluation error: Unknown expression node";
+            break;
     }
+    if (!result)
+        result = "";
+    return result;
+}
+
+static const char *ap_expr_eval_var(ap_expr_eval_ctx *ctx, 
+                                    const ap_expr_var_func_t *func,
+                                    const void *data)
+{
+    AP_DEBUG_ASSERT(func != NULL);
+    AP_DEBUG_ASSERT(data != NULL);
+    return (*func)(ctx, data);
 }
 
-static BOOL ssl_expr_eval_comp(request_rec *r, ssl_expr *node, const char **err)
+static const char *ap_expr_eval_string_func(ap_expr_eval_ctx *ctx, const ap_expr *info,
+                                            const ap_expr *arg)
+{
+    ap_expr_string_func_t *func = info->node_arg1;
+    const void *data = info->node_arg2;
+
+    AP_DEBUG_ASSERT(info->node_op == op_StringFuncInfo);
+    AP_DEBUG_ASSERT(func != NULL);
+    AP_DEBUG_ASSERT(data != NULL);
+    return (*func)(ctx, data, ap_expr_eval_word(ctx, arg));
+}
+
+static int intstrcmp(const char *s1, const char *s2)
+{
+    apr_int64_t i1 = apr_atoi64(s1);
+    apr_int64_t i2 = apr_atoi64(s2);
+
+    if (i1 < i2)
+        return -1;
+    else if (i1 == i2)
+        return 0;
+    else
+        return 1;
+}
+
+static int ap_expr_eval_comp(ap_expr_eval_ctx *ctx, const ap_expr *node)
 {
     switch (node->node_op) {
         case op_EQ: {
-            ssl_expr *e1 = (ssl_expr *)node->node_arg1;
-            ssl_expr *e2 = (ssl_expr *)node->node_arg2;
-            return (strcmp(ssl_expr_eval_word(r, e1, err), ssl_expr_eval_word(r, e2, err)) == 0);
+            const ap_expr *e1 = node->node_arg1;
+            const ap_expr *e2 = node->node_arg2;
+            return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) == 0);
         }
         case op_NE: {
-            ssl_expr *e1 = (ssl_expr *)node->node_arg1;
-            ssl_expr *e2 = (ssl_expr *)node->node_arg2;
-            return (strcmp(ssl_expr_eval_word(r, e1, err), ssl_expr_eval_word(r, e2, err)) != 0);
+            const ap_expr *e1 = node->node_arg1;
+            const ap_expr *e2 = node->node_arg2;
+            return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) != 0);
         }
         case op_LT: {
-            ssl_expr *e1 = (ssl_expr *)node->node_arg1;
-            ssl_expr *e2 = (ssl_expr *)node->node_arg2;
-            return (ssl_expr_eval_strcmplex(ssl_expr_eval_word(r, e1, err), ssl_expr_eval_word(r, e2, err), err) <  0);
+            const ap_expr *e1 = node->node_arg1;
+            const ap_expr *e2 = node->node_arg2;
+            return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <  0);
         }
         case op_LE: {
-            ssl_expr *e1 = (ssl_expr *)node->node_arg1;
-            ssl_expr *e2 = (ssl_expr *)node->node_arg2;
-            return (ssl_expr_eval_strcmplex(ssl_expr_eval_word(r, e1, err), ssl_expr_eval_word(r, e2, err), err) <= 0);
+            const ap_expr *e1 = node->node_arg1;
+            const ap_expr *e2 = node->node_arg2;
+            return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <= 0);
         }
         case op_GT: {
-            ssl_expr *e1 = (ssl_expr *)node->node_arg1;
-            ssl_expr *e2 = (ssl_expr *)node->node_arg2;
-            return (ssl_expr_eval_strcmplex(ssl_expr_eval_word(r, e1, err), ssl_expr_eval_word(r, e2, err), err) >  0);
+            const ap_expr *e1 = node->node_arg1;
+            const ap_expr *e2 = node->node_arg2;
+            return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >  0);
         }
         case op_GE: {
-            ssl_expr *e1 = (ssl_expr *)node->node_arg1;
-            ssl_expr *e2 = (ssl_expr *)node->node_arg2;
-            return (ssl_expr_eval_strcmplex(ssl_expr_eval_word(r, e1, err), ssl_expr_eval_word(r, e2, err), err) >= 0);
+            const ap_expr *e1 = node->node_arg1;
+            const ap_expr *e2 = node->node_arg2;
+            return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >= 0);
+        }
+        case op_STR_EQ: {
+            const ap_expr *e1 = node->node_arg1;
+            const ap_expr *e2 = node->node_arg2;
+            return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) == 0);
+        }
+        case op_STR_NE: {
+            const ap_expr *e1 = node->node_arg1;
+            const ap_expr *e2 = node->node_arg2;
+            return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) != 0);
+        }
+        case op_STR_LT: {
+            const ap_expr *e1 = node->node_arg1;
+            const ap_expr *e2 = node->node_arg2;
+            return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <  0);
+        }
+        case op_STR_LE: {
+            const ap_expr *e1 = node->node_arg1;
+            const ap_expr *e2 = node->node_arg2;
+            return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <= 0);
+        }
+        case op_STR_GT: {
+            const ap_expr *e1 = node->node_arg1;
+            const ap_expr *e2 = node->node_arg2;
+            return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >  0);
+        }
+        case op_STR_GE: {
+            const ap_expr *e1 = node->node_arg1;
+            const ap_expr *e2 = node->node_arg2;
+            return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >= 0);
         }
         case op_IN: {
-            ssl_expr *e1 = (ssl_expr *)node->node_arg1;
-            ssl_expr *e2 = (ssl_expr *)node->node_arg2;
-            ssl_expr *e3;
-            char *w1 = ssl_expr_eval_word(r, e1, err);
-            BOOL found = FALSE;
-            do {
-                ssl_expr_node_op op = e2->node_op;
-                e3 = (ssl_expr *)e2->node_arg1;
-                e2 = (ssl_expr *)e2->node_arg2;
-
-                if (op == op_PeerExtElement) {
-                    char *w3 = ssl_expr_eval_word(r, e3, err);
-
-                    found = ssl_expr_eval_oid(r, w1, w3, err);
-
-                    /* There will be no more nodes on the list, so the result is authoritative */
-                    break;
-                }
-
-                if (strcmp(w1, ssl_expr_eval_word(r, e3, err)) == 0) {
-                    found = TRUE;
-                    break;
+            const ap_expr *e1 = node->node_arg1;
+            const ap_expr *e2 = node->node_arg2;
+            const char *needle = ap_expr_eval_word(ctx, e1);
+            if (e2->node_op == op_ListElement) {
+                do {
+                    const ap_expr *val = e2->node_arg1;
+                    AP_DEBUG_ASSERT(e2->node_op == op_ListElement);
+                    if (strcmp(needle, ap_expr_eval_word(ctx, val)) == 0) {
+                        return 1;
+                        break;
+                    }
+                    e2 = e2->node_arg2;
+                } while (e2 != NULL);
+            }
+            else if (e2->node_op == op_ListFuncCall) {
+                const ap_expr *info = e2->node_arg1;
+                const ap_expr *arg = e2->node_arg2;
+                ap_expr_list_func_t *func = info->node_arg1;
+                apr_array_header_t *haystack;
+                int i = 0;
+                AP_DEBUG_ASSERT(func != NULL);
+                AP_DEBUG_ASSERT(info->node_op == op_ListFuncInfo);
+                haystack = (*func)(ctx, info->node_arg2, ap_expr_eval_word(ctx, arg));
+                if (haystack == NULL)
+                    return 0;
+                for (; i < haystack->nelts; i++) {
+                    if (strcmp(needle, APR_ARRAY_IDX(haystack,i,char *)) == 0)
+                        return 1;
                 }
-            } while (e2 != NULL);
-            return found;
+            }
+            return 0;
         }
         case op_REG: {
-            ssl_expr *e1;
-            ssl_expr *e2;
-            char *word;
-            ap_regex_t *regex;
-
-            e1 = (ssl_expr *)node->node_arg1;
-            e2 = (ssl_expr *)node->node_arg2;
-            word = ssl_expr_eval_word(r, e1, err);
-            regex = (ap_regex_t *)(e2->node_arg1);
+            const ap_expr *e1;
+            const ap_expr *e2;
+            const char *word;
+            const ap_regex_t *regex;
+
+            e1 = node->node_arg1;
+            e2 = node->node_arg2;
+            word = ap_expr_eval_word(ctx, e1);
+            regex = e2->node_arg1;
             return (ap_regexec(regex, word, 0, NULL, 0) == 0);
         }
         case op_NRE: {
-            ssl_expr *e1;
-            ssl_expr *e2;
-            char *word;
-            ap_regex_t *regex;
-
-            e1 = (ssl_expr *)node->node_arg1;
-            e2 = (ssl_expr *)node->node_arg2;
-            word = ssl_expr_eval_word(r, e1, err);
-            regex = (ap_regex_t *)(e2->node_arg1);
+            const ap_expr *e1;
+            const ap_expr *e2;
+            const char *word;
+            const ap_regex_t *regex;
+
+            e1 = node->node_arg1;
+            e2 = node->node_arg2;
+            word = ap_expr_eval_word(ctx, e1);
+            regex = e2->node_arg1;
             return !(ap_regexec(regex, word, 0, NULL, 0) == 0);
         }
         default: {
-            *err = "Internal evaluation error: Unknown expression node";
-            return FALSE;
+            *ctx->err = "Internal evaluation error: Unknown expression node";
+            return -1;
         }
     }
 }
 
-static char *ssl_expr_eval_word(request_rec *r, ssl_expr *node, const char **err)
+/* combined string/int comparison for compatibility with ssl_expr */
+static int strcmplex(const char *str1, const char *str2)
 {
+    int i, n1, n2;
+
+    if (str1 == NULL)
+        return -1;
+    if (str2 == NULL)
+        return +1;
+    n1 = strlen(str1);
+    n2 = strlen(str2);
+    if (n1 > n2)
+        return 1;
+    if (n1 < n2)
+        return -1;
+    for (i = 0; i < n1; i++) {
+        if (str1[i] > str2[i])
+            return 1;
+        if (str1[i] < str2[i])
+            return -1;
+    }
+    return 0;
+}
+
+static int ssl_expr_eval_comp(ap_expr_eval_ctx *ctx, const ap_expr *node)
+{
+    const ap_expr *e1 = node->node_arg1;
+    const ap_expr *e2 = node->node_arg2;
     switch (node->node_op) {
-        case op_Digit: {
-            char *string = (char *)node->node_arg1;
-            return string;
-        }
-        case op_String: {
-            char *string = (char *)node->node_arg1;
-            return string;
-        }
-        case op_Var: {
-            char *var = (char *)node->node_arg1;
-            char *val = ssl_var_lookup(r->pool, r->server, r->connection, r, var);
-            return (val == NULL ? "" : val);
-        }
-        case op_Func: {
-            char *name = (char *)node->node_arg1;
-            ssl_expr *args = (ssl_expr *)node->node_arg2;
-            if (strEQ(name, "file"))
-                return ssl_expr_eval_func_file(r, (char *)(args->node_arg1), err);
-            else {
-                *err = "Internal evaluation error: Unknown function name";
-                return "";
+    case op_EQ:
+    case op_STR_EQ:
+        return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) == 0);
+    case op_NE:
+    case op_STR_NE:
+        return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) != 0);
+    case op_LT:
+    case op_STR_LT:
+        return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <  0);
+    case op_LE:
+    case op_STR_LE:
+        return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <= 0);
+    case op_GT:
+    case op_STR_GT:
+        return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >  0);
+    case op_GE:
+    case op_STR_GE:
+        return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >= 0);
+    default:
+        return ap_expr_eval_comp(ctx, node);
+    }
+}
+
+
+AP_DECLARE(const char *) ap_expr_parse(apr_pool_t *pool, apr_pool_t *ptemp,
+                                       ap_expr_info_t *info, const char *expr,
+                                       ap_expr_lookup_fn *lookup_fn)
+{
+    ap_expr_parse_ctx ctx;
+    int rc;
+
+    ctx.pool     = pool;
+    ctx.ptemp    = ptemp;
+    ctx.inputbuf = expr;
+    ctx.inputlen = strlen(expr);
+    ctx.inputptr = ctx.inputbuf;
+    ctx.expr     = NULL;
+    ctx.error    = NULL;        /* generic bison error message (usually not very useful) */
+    ctx.error2   = NULL;        /* additional error message */
+    ctx.flags    = info->flags;
+    ctx.scan_del    = '\0';
+    ctx.scan_buf[0] = '\0';
+    ctx.scan_ptr    = ctx.scan_buf;
+    ctx.lookup_fn   = lookup_fn ? lookup_fn : ap_run_expr_lookup;
+
+    ap_expr_yylex_init(&ctx.scanner);
+    ap_expr_yyset_extra(&ctx, ctx.scanner);
+    rc = ap_expr_yyparse(&ctx);
+    ap_expr_yylex_destroy(ctx.scanner);
+    if (ctx.error) {
+        if (ctx.error2)
+            return apr_psprintf(pool, "%s: %s", ctx.error, ctx.error2);
+        else
+            return ctx.error;
+    }
+    else if (ctx.error2) {
+        return ctx.error2;
+    }
+
+    if (rc) /* XXX can this happen? */
+        return "syntax error";
+
+    /* XXX Make this properly depend on the loglevel, which requires
+     * XXX having a server_rec
+     */
+    /*
+    if (ctx.expr)
+        expr_dump_tree(ctx.expr, NULL, APLOG_NOTICE, 2);
+    */
+
+    info->root_node = ctx.expr;
+
+    return NULL;
+}
+
+AP_DECLARE(ap_expr_info_t*) ap_expr_parse_cmd(const cmd_parms *cmd,
+                                              const char *expr,
+                                              const char **err,
+                                              ap_expr_lookup_fn *lookup_fn)
+{
+    ap_expr_info_t *info = apr_pcalloc(cmd->pool, sizeof(ap_expr_info_t));
+    info->filename = cmd->directive->filename;
+    info->line_number = cmd->directive->line_num;
+    *err = ap_expr_parse(cmd->pool, cmd->temp_pool, info, expr, lookup_fn);
+
+    if (*err)
+        return NULL;
+
+    return info;
+}
+
+ap_expr *ap_expr_make(ap_expr_node_op op, const void *a1, const void *a2,
+                      ap_expr_parse_ctx *ctx)
+{
+    ap_expr *node = apr_palloc(ctx->pool, sizeof(ap_expr));
+    node->node_op   = op;
+    node->node_arg1 = a1;
+    node->node_arg2 = a2;
+    return node;
+}
+
+
+static ap_expr *ap_expr_info_make(int type, const char *name, ap_expr_parse_ctx *ctx)
+{
+    ap_expr *info = apr_palloc(ctx->pool, sizeof(ap_expr));
+    ap_expr_lookup_parms parms;
+    parms.type  = type;
+    parms.flags = 0;
+    parms.pool  = ctx->pool;
+    parms.ptemp = ctx->ptemp;
+    parms.name  = name;
+    parms.func  = &info->node_arg1;
+    parms.data  = &info->node_arg2;
+    parms.err   = &ctx->error2;
+    if (ctx->lookup_fn(&parms) != OK)
+        return NULL;
+    return info;
+}
+
+ap_expr *ap_expr_str_func_make(const char *name, const ap_expr *arg,
+                               ap_expr_parse_ctx *ctx)
+{
+    ap_expr *info = ap_expr_info_make(AP_EXPR_FUNC_STRING, name, ctx);
+    if (!info)
+        return NULL;
+
+    info->node_op = op_StringFuncInfo;
+    return ap_expr_make(op_StringFuncCall, info, arg, ctx);
+}
+
+ap_expr *ap_expr_list_func_make(const char *name, const ap_expr *arg,
+                                ap_expr_parse_ctx *ctx)
+{
+    ap_expr *info = ap_expr_info_make(AP_EXPR_FUNC_LIST, name, ctx);
+    if (!info)
+        return NULL;
+
+    info->node_op = op_ListFuncInfo;
+    return ap_expr_make(op_ListFuncCall, info, arg, ctx);
+}
+
+ap_expr *ap_expr_unary_op_make(const char *name, const ap_expr *arg,
+                               ap_expr_parse_ctx *ctx)
+{
+    ap_expr *info = ap_expr_info_make(AP_EXPR_FUNC_OP_UNARY, name, ctx);
+    if (!info)
+        return NULL;
+
+    info->node_op = op_UnaryOpInfo;
+    return ap_expr_make(op_UnaryOpCall, info, arg, ctx);
+}
+
+ap_expr *ap_expr_binary_op_make(const char *name, const ap_expr *arg1,
+                                const ap_expr *arg2, ap_expr_parse_ctx *ctx)
+{
+    ap_expr *args;
+    ap_expr *info = ap_expr_info_make(AP_EXPR_FUNC_OP_UNARY, name, ctx);
+    if (!info)
+        return NULL;
+
+    info->node_op = op_BinaryOpInfo;
+    args = ap_expr_make(op_BinaryOpArgs, arg1, arg2, ctx);
+    return ap_expr_make(op_BinaryOpCall, info, args, ctx);
+}
+
+
+ap_expr *ap_expr_var_make(const char *name, ap_expr_parse_ctx *ctx)
+{
+    ap_expr *node = ap_expr_info_make(AP_EXPR_FUNC_VAR, name, ctx);
+    if (!node)
+        return NULL;
+
+    node->node_op = op_Var;
+    return node;
+}
+
+
+#define MARK                        APLOG_MARK,loglevel,0,s
+#define DUMP_E_E(op, e1, e2)                                                \
+    do { ap_log_error(MARK,"%*s%s: %pp %pp", indent, " ", op, e1, e2);      \
+         if (e1) expr_dump_tree(e1, s, loglevel, indent + 2);               \
+         if (e2) expr_dump_tree(e2, s, loglevel, indent + 2);               \
+    } while (0)
+#define DUMP_S_E(op, s1, e1)                                                    \
+    do { ap_log_error(MARK,"%*s%s: '%s' %pp", indent, " ", op, (char *)s1, e1); \
+         if (e1) expr_dump_tree(e1, s, loglevel, indent + 2);                   \
+    } while (0)
+#define DUMP_S_P(op, s1, p1)                                                \
+    ap_log_error(MARK,"%*s%s: '%s' %pp", indent, " ", op, (char *)s1, p1);
+#define DUMP_P_P(op, p1, p2)                                                \
+    ap_log_error(MARK,"%*s%s: %pp %pp", indent, " ", op, p1, p2);
+#define DUMP_S_S(op, s1, s2)                                                       \
+    ap_log_error(MARK,"%*s%s: '%s' '%s'", indent, " ", op, (char *)s1, (char *)s2)
+#define DUMP_P(op, p1)                                                      \
+    ap_log_error(MARK,"%*s%s: %pp", indent, " ", op, p1);
+#define DUMP_S(op, s1)                                                      \
+    ap_log_error(MARK,"%*s%s: '%s'", indent, " ", op, (char *)s1)
+
+#define CASE_OP(op)                  case op: name = #op ; break;
+
+static void expr_dump_tree(const ap_expr *e, const server_rec *s, int loglevel, int indent)
+{
+    switch (e->node_op) {
+    /* no arg */
+    case op_NOP:
+    case op_True:
+    case op_False:
+        {
+            char *name;
+            switch (e->node_op) {
+            CASE_OP(op_NOP);
+            CASE_OP(op_True);
+            CASE_OP(op_False);
+            default:
+                ap_assert(0);
+            }
+            ap_log_error(MARK, "%*s%s", indent, " ", name);
+        }
+        break;
+
+    /* arg1: string, arg2: expr */
+    case op_UnaryOpCall:
+    case op_BinaryOpCall:
+    case op_BinaryOpArgs:
+        {
+            char *name;
+            switch (e->node_op) {
+            CASE_OP(op_BinaryOpCall);
+            CASE_OP(op_UnaryOpCall);
+            CASE_OP(op_BinaryOpArgs);
+            default:
+                ap_assert(0);
+            }
+            DUMP_S_E(name, e->node_arg1, e->node_arg2);
+        }
+        break;
+
+    /* arg1: expr, arg2: expr */
+    case op_Comp:
+    case op_Not:
+    case op_Or:
+    case op_And:
+    case op_EQ:
+    case op_NE:
+    case op_LT:
+    case op_LE:
+    case op_GT:
+    case op_GE:
+    case op_STR_EQ:
+    case op_STR_NE:
+    case op_STR_LT:
+    case op_STR_LE:
+    case op_STR_GT:
+    case op_STR_GE:
+    case op_IN:
+    case op_REG:
+    case op_NRE:
+    case op_Concat:
+    case op_StringFuncCall:
+    case op_ListFuncCall:
+    case op_ListElement:
+        {
+            char *name;
+            switch (e->node_op) {
+            CASE_OP(op_Comp);
+            CASE_OP(op_Not);
+            CASE_OP(op_Or);
+            CASE_OP(op_And);
+            CASE_OP(op_EQ);
+            CASE_OP(op_NE);
+            CASE_OP(op_LT);
+            CASE_OP(op_LE);
+            CASE_OP(op_GT);
+            CASE_OP(op_GE);
+            CASE_OP(op_STR_EQ);
+            CASE_OP(op_STR_NE);
+            CASE_OP(op_STR_LT);
+            CASE_OP(op_STR_LE);
+            CASE_OP(op_STR_GT);
+            CASE_OP(op_STR_GE);
+            CASE_OP(op_IN);
+            CASE_OP(op_REG);
+            CASE_OP(op_NRE);
+            CASE_OP(op_Concat);
+            CASE_OP(op_StringFuncCall);
+            CASE_OP(op_ListFuncCall);
+            CASE_OP(op_ListElement);
+            default:
+                ap_assert(0);
             }
+            DUMP_E_E(name, e->node_arg1, e->node_arg2);
+        }
+        break;
+    /* arg1: string */
+    case op_Digit:
+    case op_String:
+        {
+            char *name;
+            switch (e->node_op) {
+            CASE_OP(op_Digit);
+            CASE_OP(op_String);
+            default:
+                ap_assert(0);
+            }
+            DUMP_S(name, e->node_arg1);
+        }
+        break;
+    /* arg1: pointer, arg2: pointer */
+    case op_Var:
+    case op_StringFuncInfo:
+    case op_UnaryOpInfo:
+    case op_BinaryOpInfo:
+    case op_ListFuncInfo:
+        {
+            char *name;
+            switch (e->node_op) {
+            CASE_OP(op_Var);
+            CASE_OP(op_StringFuncInfo);
+            CASE_OP(op_UnaryOpInfo);
+            CASE_OP(op_BinaryOpInfo);
+            CASE_OP(op_ListFuncInfo);
+            default:
+                ap_assert(0);
+            }
+            DUMP_P_P(name, e->node_arg1, e->node_arg2);
+        }
+        break;
+    /* arg1: pointer */
+    case op_Regex:
+        DUMP_P("op_Regex", e->node_arg1);
+        break;
+    default:
+        ap_log_error(MARK, "%*sERROR: INVALID OP %d", indent, " ", e->node_op);
+        break;
+    }
+}
+static int ap_expr_eval_unary_op(ap_expr_eval_ctx *ctx, const ap_expr *info,
+                                 const ap_expr *arg)
+{
+    const ap_expr_op_unary_t *op_func = info->node_arg1;
+    const void *data = info->node_arg2;
+
+    AP_DEBUG_ASSERT(info->node_op == op_UnaryOpInfo);
+    AP_DEBUG_ASSERT(op_func != NULL);
+    AP_DEBUG_ASSERT(data != NULL);
+    return (*op_func)(ctx, data, ap_expr_eval_word(ctx, arg));
+}
+
+static int ap_expr_eval_binary_op(ap_expr_eval_ctx *ctx, const ap_expr *info,
+                                  const ap_expr *args)
+{
+    const ap_expr_op_binary_t *op_func = info->node_arg1;
+    const void *data = info->node_arg2;
+    const ap_expr *a1 = args->node_arg1;
+    const ap_expr *a2 = args->node_arg2;
+
+    AP_DEBUG_ASSERT(info->node_op == op_BinaryOpInfo);
+    AP_DEBUG_ASSERT(args->node_op == op_BinaryOpArgs);
+    AP_DEBUG_ASSERT(op_func != NULL);
+    AP_DEBUG_ASSERT(data != NULL);
+    return (*op_func)(ctx, data, ap_expr_eval_word(ctx, a1),
+                      ap_expr_eval_word(ctx, a2));
+}
+
+
+static int ap_expr_eval(ap_expr_eval_ctx *ctx, const ap_expr *node)
+{
+    switch (node->node_op) {
+        case op_True: {
+            return 1;
+        }
+        case op_False: {
+            return 0;
+        }
+        case op_Not: {
+            const ap_expr *e = node->node_arg1;
+            return (!ap_expr_eval(ctx, e));
+        }
+        case op_Or: {
+            const ap_expr *e1 = node->node_arg1;
+            const ap_expr *e2 = node->node_arg2;
+            return (ap_expr_eval(ctx, e1) || ap_expr_eval(ctx, e2));
+        }
+        case op_And: {
+            const ap_expr *e1 = node->node_arg1;
+            const ap_expr *e2 = node->node_arg2;
+            return (ap_expr_eval(ctx, e1) && ap_expr_eval(ctx, e2));
+        }
+        case op_UnaryOpCall: {
+            const ap_expr *info = node->node_arg1;
+            const ap_expr *args = node->node_arg2;
+            return ap_expr_eval_unary_op(ctx, info, args);
+        }
+        case op_BinaryOpCall: {
+            const ap_expr *info = node->node_arg1;
+            const ap_expr *args = node->node_arg2;
+            return ap_expr_eval_binary_op(ctx, info, args);
+        }
+        case op_Comp: {
+            const ap_expr *e = node->node_arg1;
+            if (ctx->info->flags & AP_EXPR_FLAGS_SSL_EXPR_COMPAT)
+                return ssl_expr_eval_comp(ctx, e);
+            else
+                return ap_expr_eval_comp(ctx, e);
         }
         default: {
-            *err = "Internal evaluation error: Unknown expression node";
+            *ctx->err = "Internal evaluation error: Unknown expression node";
             return FALSE;
         }
     }
 }
 
-static BOOL ssl_expr_eval_oid(request_rec *r, const char *word,
-                              const char *oidstr, const char **err)
+
+AP_DECLARE(int) ap_expr_exec(request_rec *r, const ap_expr_info_t *info, const char **err)
 {
-    int j;
-    BOOL result = FALSE;
-    apr_array_header_t *oid_array;
-    char **oid_value;
-
-    if (NULL == (oid_array = ssl_ext_list(r->pool, r->connection, 1, oidstr))) {
-        return FALSE;
-    }
-
-    oid_value = (char **) oid_array->elts;
-    for (j = 0; j < oid_array->nelts; j++) {
-        if (strcmp(word, oid_value[j]) == 0) {
-            result = TRUE;
-            break;
-        }
+    ap_expr_eval_ctx ctx;
+    int rc;
+    ctx.r = r;
+    ctx.c = r->connection;
+    ctx.s = r->server;
+    ctx.p = r->pool;
+    ctx.err  = err;
+    ctx.info = info;
+
+    *err = NULL;
+    rc = ap_expr_eval(&ctx, info->root_node);
+    if (*err != NULL)
+        return (-1);
+    else
+        return (rc ? 1 : 0);
+}
+
+static const char *req_func(ap_expr_eval_ctx *ctx, const char *name,
+                            const char *arg)
+{
+    if (ctx->r)
+        return apr_table_get(ctx->r->headers_in, arg);
+    else
+        return "";
+}
+
+static const char *resp_func(ap_expr_eval_ctx *ctx, const char *name,
+                             const char *arg)
+{
+    if (ctx->r)
+        return apr_table_get(ctx->r->headers_out, arg);
+    else
+        return "";
+}
+
+static const char *env_func(ap_expr_eval_ctx *ctx, const char *name,
+                            const char *arg)
+{
+    if (ctx->r)
+        return apr_table_get(ctx->r->subprocess_env, arg);
+    else
+        return "";
+}
+
+static const char *osenv_func(ap_expr_eval_ctx *ctx, const char *name, const char *arg)
+{
+    return getenv(arg);
+}
+
+static const char *tolower_func(ap_expr_eval_ctx *ctx, const char *name, const char *arg)
+{
+    char *result = apr_pstrdup(ctx->p, arg);
+    ap_str_tolower(result);
+    return result;
+}
+
+static const char *toupper_func(ap_expr_eval_ctx *ctx, const char *name, const char *arg)
+{
+    char *p;
+    char *result = apr_pstrdup(ctx->p, arg);
+
+    for (p = result; *p; ++p) {
+         *p = apr_toupper(*p);
     }
+
     return result;
 }
 
+static const char *escape_func(ap_expr_eval_ctx *ctx, const char *name, const char *arg)
+{
+    return ap_escape_uri(ctx->p, arg);
+}
 
-static char *ssl_expr_eval_func_file(request_rec *r, char *filename, const char **err)
+static const char *unescape_func(ap_expr_eval_ctx *ctx, const char *name, const char *arg)
 {
-    apr_file_t *fp;
-    char *buf;
-    apr_off_t offset;
-    apr_size_t len;
-    apr_finfo_t finfo;
-
-    if (apr_file_open(&fp, filename, APR_READ|APR_BUFFERED,
-                      APR_OS_DEFAULT, r->pool) != APR_SUCCESS) {
-        *err = "Cannot open file";
+    char *result = apr_pstrdup(ctx->p, arg);
+    if (ap_unescape_url(result))
         return "";
+    else
+        return result;
+
+}
+
+static const char *request_var_names[] = {
+    "REQUEST_METHOD",           /*  0 */
+    "REQUEST_SCHEME",           /*  1 */
+    "REQUEST_URI",              /*  2 */
+    "REQUEST_FILENAME",         /*  3 */
+    "REMOTE_HOST",              /*  4 */
+    "REMOTE_IDENT",             /*  5 */
+    "REMOTE_USER",              /*  6 */
+    "SERVER_ADMIN",             /*  7 */
+    "SERVER_NAME",              /*  8 */
+    "SERVER_PORT",              /*  9 */
+    "SERVER_PROTOCOL",          /* 10 */
+    "SCRIPT_FILENAME",          /* 11 */
+    "PATH_INFO",                /* 12 */
+    "QUERY_STRING",             /* 13 */
+    "IS_SUBREQ",                /* 14 */
+    "DOCUMENT_ROOT",            /* 15 */
+    "AUTH_TYPE",                /* 16 */
+    "THE_REQUEST",              /* 17 */
+    "REMOTE_ADDR",              /* 18 */
+    "CONTENT_TYPE",             /* 19 */
+    NULL
+};
+
+static const char *request_var_fn(ap_expr_eval_ctx *ctx, const void *data)
+{
+    int index = ((const char **)data - request_var_names);
+    request_rec *r = ctx->r;
+    if (!r)
+        return "";
+
+    switch (index) {
+    case 0:
+        return r->method;
+    case 1:
+        return ap_http_scheme(r);
+    case 2:
+        return r->uri;
+    case 3:
+        return r->filename;
+    case 4:
+        return ap_get_remote_host(r->connection, r->per_dir_config,
+                                  REMOTE_NAME, NULL);
+    case 5:
+        return ap_get_remote_logname(r);
+    case 6:
+        return r->user;
+    case 7:
+        return r->server->server_admin;
+    case 8:
+        return ap_get_server_name(r);
+    case 9:
+        return apr_psprintf(ctx->p, "%u", ap_get_server_port(r));
+    case 10:
+        return r->protocol;
+    case 11:
+        return r->filename;
+    case 12:
+        return r->path_info;
+    case 13:
+        return r->args;
+    case 14:
+        return (r->main != NULL ? "true" : "false");
+    case 15:
+        return ap_document_root(r);
+    case 16:
+        return r->ap_auth_type;
+    case 17:
+        return r->the_request;
+    case 18:
+        return ctx->c->remote_ip;
+    case 19:
+        return r->content_type;
+    default:
+        ap_assert(0);
+        return NULL;
     }
-    apr_file_info_get(&finfo, APR_FINFO_SIZE, fp);
-    if ((finfo.size + 1) != ((apr_size_t)finfo.size + 1)) {
-        *err = "Huge file cannot be read";
-        apr_file_close(fp);
+}
+
+static const char *req_header_var_names[] = {
+    "HTTP_USER_AGENT",          /* 0 */
+    "HTTP_PROXY_CONNECTION",    /* 1 */
+    "HTTP_REFERER",
+    "HTTP_COOKIE",
+    "HTTP_FORWARDED",
+    "HTTP_HOST",
+    "HTTP_ACCEPT",
+    NULL
+};
+
+static const char *req_header_var_fn(ap_expr_eval_ctx *ctx, const void *data)
+{
+    const char **name = (const char **)data;
+    int index = (name - req_header_var_names);
+    if (!ctx->r)
         return "";
+
+    switch (index) {
+    case 0:
+        return apr_table_get(ctx->r->headers_in, "User-Agent");
+    case 1:
+        return apr_table_get(ctx->r->headers_in, "Proxy-Connection");
+    default:
+        /* apr_table_get is case insensitive, just skip leading "HTTP_" */
+        return apr_table_get(ctx->r->headers_in, *name + 5);
+    }
+}
+
+static const char *misc_var_names[] = {
+    "TIME_YEAR",        /* 0 */
+    "TIME_MON",         /* 1 */
+    "TIME_DAY",         /* 2 */
+    "TIME_HOUR",        /* 3 */
+    "TIME_MIN",         /* 4 */
+    "TIME_SEC",         /* 5 */
+    "TIME_WDAY",        /* 6 */
+    "TIME",             /* 7 */
+    "SERVER_SOFTWARE",  /* 8 */
+    "API_VERSION",      /* 9 */
+    NULL
+};
+
+static const char *misc_var_fn(ap_expr_eval_ctx *ctx, const void *data)
+{
+    apr_time_exp_t tm;
+    apr_time_exp_lt(&tm, apr_time_now());
+    int index = ((const char **)data - misc_var_names);
+
+    switch (index) {
+    case 0:
+        return apr_psprintf(ctx->p, "%02d%02d", (tm.tm_year / 100) + 19,
+                            tm.tm_year % 100);
+    case 1:
+        return apr_psprintf(ctx->p, "%02d", tm.tm_mon+1);
+    case 2:
+        return apr_psprintf(ctx->p, "%02d", tm.tm_mday);
+    case 3:
+        return apr_psprintf(ctx->p, "%02d", tm.tm_hour);
+    case 4:
+        return apr_psprintf(ctx->p, "%02d", tm.tm_min);
+    case 5:
+        return apr_psprintf(ctx->p, "%02d", tm.tm_sec);
+    case 6:
+        return apr_psprintf(ctx->p, "%d", tm.tm_wday);
+    case 7:
+        return apr_psprintf(ctx->p, "%02d%02d%02d%02d%02d%02d%02d",
+                            (tm.tm_year / 100) + 19, (tm.tm_year % 100),
+                            tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min,
+                            tm.tm_sec);
+    case 8:
+        return ap_get_server_banner();
+    case 9:
+        return apr_itoa(ctx->p, MODULE_MAGIC_NUMBER);
+    default:
+        ap_assert(0);
+    }
+
+    return NULL;
+}
+
+struct expr_provider_single {
+    const void *func;
+    const char *name;
+};
+struct expr_provider_multi {
+    const void *func;
+    const char **names;
+};
+
+static const struct expr_provider_multi var_providers[] = {
+    { misc_var_fn, misc_var_names },
+    { req_header_var_fn, req_header_var_names },
+    { request_var_fn, request_var_names },
+    { NULL, NULL }
+};
+
+static const struct expr_provider_single string_func_providers[] = {
+    { osenv_func, "osenv" },
+    { env_func, "env" },
+    { resp_func, "resp" },
+    { req_func, "req" },
+    /* 'http' as alias for 'req' for compatibility with ssl_expr */
+    { req_func, "http" },
+    { tolower_func, "tolower" },
+    { toupper_func, "toupper" },
+    { escape_func, "escape" },
+    { unescape_func, "unescape" },
+    { NULL, NULL}
+};
+/* XXX: base64 encode/decode ? */
+
+static int core_expr_lookup(ap_expr_lookup_parms *parms)
+{
+    switch (parms->type) {
+    case AP_EXPR_FUNC_VAR: {
+        const struct expr_provider_multi *prov = var_providers;
+        while (prov->func) {
+            const char **name = prov->names;
+            while (*name) {
+                if (strcasecmp(*name, parms->name) == 0) {
+                    *parms->func = prov->func;
+                    *parms->data = name;
+                    return OK;
+                }
+		name++;
+            }
+            prov++;
+        }
+        break;
     }
-    len = (apr_size_t)finfo.size;
-    if (len == 0) {
-        buf = (char *)apr_palloc(r->pool, sizeof(char) * 1);
-        *buf = NUL;
-    }
-    else {
-        if ((buf = (char *)apr_palloc(r->pool, sizeof(char)*(len+1))) == NULL) {
-            *err = "Cannot allocate memory";
-            apr_file_close(fp);
-            return "";
-        }
-        offset = 0;
-        apr_file_seek(fp, APR_SET, &offset);
-        if (apr_file_read(fp, buf, &len) != APR_SUCCESS) {
-            *err = "Cannot read from file";
-            apr_file_close(fp);
-            return "";
+    case AP_EXPR_FUNC_STRING: {
+        const struct expr_provider_single *prov = string_func_providers;
+        while (prov->func) {
+            if (strcasecmp(prov->name, parms->name) == 0) {
+                *parms->func = prov->func;
+                *parms->data = prov->name;
+                return OK;
+            }
+            prov++;
         }
-        buf[len] = NUL;
+        break;
     }
-    apr_file_close(fp);
-    return buf;
+    default:
+        break;
+    }
+    return DECLINED;
 }
 
-/* a variant of strcmp(3) which works correctly also for number strings */
-static int ssl_expr_eval_strcmplex(char *cpNum1, char *cpNum2, const char **err)
+static int expr_lookup_not_found(ap_expr_lookup_parms *parms)
 {
-    int i, n1, n2;
+    const char *type;
 
-    if (cpNum1 == NULL)
-        return -1;
-    if (cpNum2 == NULL)
-        return +1;
-    n1 = strlen(cpNum1);
-    n2 = strlen(cpNum2);
-    if (n1 > n2)
-        return 1;
-    if (n1 < n2)
-        return -1;
-    for (i = 0; i < n1; i++) {
-        if (cpNum1[i] > cpNum2[i])
-            return 1;
-        if (cpNum1[i] < cpNum2[i])
-            return -1;
+    switch (parms->type) {
+    case AP_EXPR_FUNC_VAR:
+        type = "Variable";
+        break;
+    case AP_EXPR_FUNC_STRING:
+        type = "Function";
+        break;
+    case AP_EXPR_FUNC_LIST:
+        type = "List-returning function";
+        break;
+    case AP_EXPR_FUNC_OP_UNARY:
+        type = "Unary operator";
+        break;
+    case AP_EXPR_FUNC_OP_BINARY:
+        type = "Binary operator";
+        break;
+    default:
+        *parms->err = "Inavalid expression type in expr_lookup";
+        return !OK;
     }
-    return 0;
+    *parms->err = apr_psprintf(parms->ptemp, "%s '%s' does not exist", type,
+                               parms->name);
+    return !OK;
+}
+
+void ap_expr_init(apr_pool_t *p)
+{
+    ap_hook_expr_lookup(core_expr_lookup, NULL, NULL, APR_HOOK_MIDDLE);
+    ap_hook_expr_lookup(expr_lookup_not_found, NULL, NULL, APR_HOOK_REALLY_LAST);
 }
+



Mime
View raw message