You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ni...@apache.org on 2008/03/31 14:17:00 UTC

svn commit: r642971 - in /httpd/httpd/trunk: include/ap_expr.h include/ap_mmn.h server/main.c server/util_expr.c

Author: niq
Date: Mon Mar 31 05:16:58 2008
New Revision: 642971

URL: http://svn.apache.org/viewvc?rev=642971&view=rev
Log:
Flesh out ap_expr with:
 * Re-usable parse trees
 * Canonical string parser function (candidate)

Modified:
    httpd/httpd/trunk/include/ap_expr.h
    httpd/httpd/trunk/include/ap_mmn.h
    httpd/httpd/trunk/server/main.c
    httpd/httpd/trunk/server/util_expr.c

Modified: httpd/httpd/trunk/include/ap_expr.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/include/ap_expr.h?rev=642971&r1=642970&r2=642971&view=diff
==============================================================================
--- httpd/httpd/trunk/include/ap_expr.h (original)
+++ httpd/httpd/trunk/include/ap_expr.h Mon Mar 31 05:16:58 2008
@@ -23,6 +23,7 @@
 #define AP_EXPR_H
 
 #include "httpd.h"
+#include "ap_regex.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -65,7 +66,7 @@
 #ifdef DEBUG_INCLUDE
     int dump_done;
 #endif
-} parse_node_t;
+} ap_parse_node_t;
 
 typedef struct {
     const char *source;
@@ -74,8 +75,8 @@
     ap_regmatch_t match[AP_MAX_REG_MATCH];
 } backref_t;
 
-typedef char *(*string_func_t)(request_rec*, const char*);
-typedef int (*opt_func_t)(request_rec*, parse_node_t*, string_func_t);
+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
@@ -84,8 +85,8 @@
  * @param was_error On return, set to zero if parse successful, nonzero on error
  * @return The parse tree
  */
-AP_DECLARE(parse_node_t*) ap_expr_parse(apr_pool_t *pool, const char *expr,
-                                        int *was_error);
+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
@@ -93,10 +94,11 @@
  * @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, parse_node_t *root,
+AP_DECLARE(int) ap_expr_eval(request_rec *r, ap_parse_node_t *root,
                              int *was_error, backref_t **reptr,
                              string_func_t string_func, opt_func_t eval_func);
 /**
@@ -106,6 +108,7 @@
  * @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
  */
@@ -113,6 +116,43 @@
                                    int *was_error, backref_t **reptr,
                                    string_func_t string_func,
                                    opt_func_t eval_func);
+
+/**
+ * Internal initialisation of ap_expr (for httpd)
+ * @param pool Pool
+ * @return APR_SUCCESS or error
+ */
+AP_DECLARE(apr_status_t) ap_expr_init(apr_pool_t *pool);
+
+/**
+ * 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
+ */
+AP_DECLARE(const char*) ap_expr_string(request_rec *r, const char *str);
+
+/**
+ * Clone a parse tree.  This is required if you create a parse tree
+ * using ap_expr_parse, and wish to re-use it many times in ap_expr_eval.
+ * It is not required if you need to use it just once.
+ * @param pool Pool
+ * @param node The parse tree to clone
+ * @param parent Parent node (for internal use when recursing - pass in NULL)
+ * @return The cloned tree
+ */
+AP_DECLARE(ap_parse_node_t*) ap_expr_clone_tree(apr_pool_t *pool,
+                                                ap_parse_node_t *node,
+                                                ap_parse_node_t *parent);
 
 #ifdef __cplusplus
 }

Modified: httpd/httpd/trunk/include/ap_mmn.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/include/ap_mmn.h?rev=642971&r1=642970&r2=642971&view=diff
==============================================================================
--- httpd/httpd/trunk/include/ap_mmn.h (original)
+++ httpd/httpd/trunk/include/ap_mmn.h Mon Mar 31 05:16:58 2008
@@ -150,6 +150,7 @@
  * 20071108.8 (2.3.0-dev)  Add optional function ap_logio_add_bytes_in() to mog_logio
  * 20071108.9 (2.3.0-dev)  Add chroot support to unixd_config
  * 20071108.10(2.3.0-dev)  Introduce new ap_expr API
+ * 20071108.11(2.3.0-dev)  Revise/Expand new ap_expr API
  */
 
 #define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */
@@ -157,7 +158,7 @@
 #ifndef MODULE_MAGIC_NUMBER_MAJOR
 #define MODULE_MAGIC_NUMBER_MAJOR 20071108
 #endif
-#define MODULE_MAGIC_NUMBER_MINOR 10                    /* 0...n */
+#define MODULE_MAGIC_NUMBER_MINOR 11                    /* 0...n */
 
 /**
  * Determine if the server's current MODULE_MAGIC_NUMBER is at least a

Modified: httpd/httpd/trunk/server/main.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/main.c?rev=642971&r1=642970&r2=642971&view=diff
==============================================================================
--- httpd/httpd/trunk/server/main.c (original)
+++ httpd/httpd/trunk/server/main.c Mon Mar 31 05:16:58 2008
@@ -40,6 +40,7 @@
 #include "util_ebcdic.h"
 #include "ap_mpm.h"
 #include "mpm_common.h"
+#include "ap_expr.h"
 
 #if APR_HAVE_UNISTD_H
 #include <unistd.h>
@@ -492,6 +493,9 @@
         destroy_and_exit_process(process, 1);
     }
 #endif
+    if (ap_expr_init(pglobal) != APR_SUCCESS) {
+        destroy_and_exit_process(process, 1);
+    }
 
     apr_pool_create(&pcommands, pglobal);
     apr_pool_tag(pcommands, "pcommands");

Modified: httpd/httpd/trunk/server/util_expr.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/util_expr.c?rev=642971&r1=642970&r2=642971&view=diff
==============================================================================
--- httpd/httpd/trunk/server/util_expr.c (original)
+++ httpd/httpd/trunk/server/util_expr.c Mon Mar 31 05:16:58 2008
@@ -26,6 +26,7 @@
 #include "http_log.h"
 
 #include "ap_expr.h"
+#include <assert.h>
 #if 1
 /*
  * +-------------------------------------------------------+
@@ -43,10 +44,7 @@
 } while(0)
 
 #define CREATE_NODE(pool,name) do {                          \
-    (name) = apr_palloc(pool, sizeof(*(name)));      \
-    (name)->parent = (name)->left = (name)->right = NULL; \
-    (name)->done = 0;                                     \
-    (name)->dump_done = 0;                                \
+    (name) = apr_pcalloc(pool, sizeof(*(name)));
 } while(0)
 
 static void debug_printf(request_rec *r, const char *fmt, ...)
@@ -65,7 +63,7 @@
 }
 
 #define DUMP__CHILD(ctx, is, node, child) if (1) {                           \
-    parse_node_t *d__c = node->child;                                        \
+    ap_parse_node_t *d__c = node->child;                                     \
     if (d__c) {                                                              \
         if (!d__c->dump_done) {                                              \
             if (d__c->parent != node) {                                      \
@@ -90,9 +88,9 @@
     }                                                                        \
 }
 
-static void debug_dump_tree(include_ctx_t *ctx, parse_node_t *root)
+static void debug_dump_tree(include_ctx_t *ctx, ap_parse_node_t *root)
 {
-    parse_node_t *current;
+    ap_parse_node_t *current;
     char *is;
 
     if (!root) {
@@ -240,9 +238,7 @@
 #define TYPE_TOKEN(token, ttype) (token)->type = ttype
 
 #define CREATE_NODE(pool,name) do {                       \
-    (name) = apr_palloc(pool, sizeof(*(name)));   \
-    (name)->parent = (name)->left = (name)->right = NULL; \
-    (name)->done = 0;                                     \
+    (name) = apr_pcalloc(pool, sizeof(*(name)));	\
 } while(0)
 
 #define DEBUG_INIT(ctx, f, bb)
@@ -269,7 +265,7 @@
                                const char *rexp, backref_t **reptr)
 {
     ap_regex_t *compiled;
-    backref_t *re = *reptr;
+    backref_t *re = reptr ? *reptr : NULL;
     int rc;
 
     compiled = ap_pregcomp(r->pool, rexp, AP_REG_EXTENDED);
@@ -280,7 +276,10 @@
     }
 
     if (!re) {
-        re = *reptr = apr_palloc(r->pool, sizeof(*re));
+        re = apr_palloc(r->pool, sizeof(*re));
+        if (reptr) {
+            *reptr = re;
+        }
     }
 
     re->source = apr_pstrdup(r->pool, string);
@@ -473,10 +472,10 @@
 }
 
 /* This is what we export.  We can split it in two. */
-AP_DECLARE(parse_node_t*) ap_expr_parse(apr_pool_t* pool, const char *expr,
-                                        int *was_error)
+AP_DECLARE(ap_parse_node_t*) ap_expr_parse(apr_pool_t* pool, const char *expr,
+                                           int *was_error)
 {
-    parse_node_t *new, *root = NULL, *current = NULL;
+    ap_parse_node_t *new, *root = NULL, *current = NULL;
     const char *error = "Invalid expression \"%s\" in file %s";
     const char *parse = expr;
     int was_unmatched = 0;
@@ -671,21 +670,40 @@
     return root;
 }
 
+AP_DECLARE(ap_parse_node_t*) ap_expr_clone_tree(apr_pool_t *pool,
+                                                ap_parse_node_t *pnode,
+		                                ap_parse_node_t *parent)
+{
+    ap_parse_node_t *ret;
+    ret = apr_pmemdup(pool, pnode, sizeof(ap_parse_node_t));
+    if (pnode->left) {
+        ret->left = ap_expr_clone_tree(pool, pnode->left, ret);
+    }
+    if (pnode->right) {
+        ret->right = ap_expr_clone_tree(pool, pnode->right, ret);
+    }
+    ret->parent = parent;
+    return ret;
+}
+
 #define PARSE_STRING(r,s) (string_func ? string_func((r),(s)) : (s))
-AP_DECLARE(int) ap_expr_eval(request_rec *r, parse_node_t *root,
+AP_DECLARE(int) ap_expr_eval(request_rec *r, ap_parse_node_t *root,
                              int *was_error, backref_t **reptr,
                              string_func_t string_func, opt_func_t eval_func)
 {
-    parse_node_t *current = root;
+    ap_parse_node_t *current = root;
     const char *error = NULL;
     unsigned int regex = 0;
+    const char *val;
+    const char *lval;
+    const char *rval;
 
     /* Evaluate Parse Tree */
     while (current) {
         switch (current->token.type) {
         case TOKEN_STRING:
-            current->token.value = PARSE_STRING(r, current->token.value);
-            current->value = !!*current->token.value;
+            val = PARSE_STRING(r, current->token.value);
+            current->value = !!*val;
             break;
 
         case TOKEN_AND:
@@ -700,9 +718,8 @@
             if (!current->left->done) {
                 switch (current->left->token.type) {
                 case TOKEN_STRING:
-                    current->left->token.value =
-                        PARSE_STRING(r, current->left->token.value);
-                    current->left->value = !!*current->left->token.value;
+                    lval = PARSE_STRING(r, current->left->token.value);
+                    current->left->value = !!*lval;
                     DEBUG_DUMP_EVAL(ctx, current->left);
                     current->left->done = 1;
                     break;
@@ -723,9 +740,8 @@
                 if (!current->right->done) {
                     switch (current->right->token.type) {
                     case TOKEN_STRING:
-                        current->right->token.value =
-                            PARSE_STRING(r,current->right->token.value);
-                        current->right->value = !!*current->right->token.value;
+                        rval = PARSE_STRING(r,current->right->token.value);
+                        current->right->value = !!*rval;
                         DEBUG_DUMP_EVAL(r, current->right);
                         current->right->done = 1;
                         break;
@@ -758,19 +774,15 @@
                 *was_error = 1;
                 return 0;
             }
-            current->left->token.value =
-                PARSE_STRING(r, current->left->token.value);
-            current->right->token.value =
-                PARSE_STRING(r, current->right->token.value);
+            lval = PARSE_STRING(r, current->left->token.value);
+            rval = PARSE_STRING(r, current->right->token.value);
 
             if (current->right->token.type == TOKEN_RE) {
-                current->value = re_check(r, current->left->token.value,
-                                          current->right->token.value, reptr);
+                current->value = re_check(r, lval, rval, reptr);
                 --regex;
             }
             else {
-                current->value = !strcmp(current->left->token.value,
-                                         current->right->token.value);
+                current->value = !strcmp(lval, rval);
             }
 
             if (current->token.type == TOKEN_NE) {
@@ -791,13 +803,10 @@
                 return 0;
             }
 
-            current->left->token.value =
-                PARSE_STRING(r, current->left->token.value);
-            current->right->token.value =
-                PARSE_STRING(r, current->right->token.value);
+            lval = PARSE_STRING(r, current->left->token.value);
+            rval = PARSE_STRING(r, current->right->token.value);
 
-            current->value = strcmp(current->left->token.value,
-                                    current->right->token.value);
+            current->value = strcmp(lval, rval);
 
             switch (current->token.type) {
             case TOKEN_GE: current->value = current->value >= 0; break;
@@ -864,11 +873,73 @@
                                    string_func_t string_func,
                                    opt_func_t eval_func)
 {
-    parse_node_t *root = ap_expr_parse(r->pool, expr, was_error);
+    ap_parse_node_t *root = ap_expr_parse(r->pool, expr, was_error);
     if (*was_error || !root) {
         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                       "Error parsing expression in %s", r->filename);   
         return 0;
     }
     return ap_expr_eval(r, root, was_error, reptr, string_func, eval_func);
+}
+
+
+static ap_regex_t *isvar = NULL;
+AP_DECLARE(const char*) ap_expr_string(request_rec *r, const char *str)
+{
+    /* a default string evaluator: support headers and env */
+    ap_regmatch_t match[3];
+    assert(isvar != NULL);
+    if (ap_regexec(isvar, str, 3, match, 0) == 0) {
+        apr_table_t *table = NULL;
+        int len = match[1].rm_eo-match[1].rm_so;
+        const char *name = str+match[1].rm_so;
+        if (!strncasecmp("req", name, len)) {
+            table = r->headers_in;
+        }
+        else if (!strncasecmp("resp", name, len)) {
+            table = r->headers_out;
+        }
+        else if (!strncasecmp("env", name, len)) {
+            table = r->subprocess_env;
+        }
+        if (table != NULL) {
+            char *key = apr_pstrndup(r->pool, str+match[2].rm_so,
+                                     match[2].rm_eo-match[2].rm_so);
+            return apr_table_get(table, key);
+        }
+    }
+    else if (str[0] == '$') {
+        if (!strcasecmp(str, "$handler")) {
+            return r->handler;
+        }
+        else if (!strcasecmp(str, "$content-type")) {
+            return r->content_type;
+        }
+    }
+    /* TODO: provide a hook so modules can interpret other patterns */
+    /* OhBugger, where's the regexp for backreferences ? */
+    return str;  /* default - literal string as-is */
+}
+static apr_status_t ap_expr_term(void *expr)
+{
+    if (isvar) {
+        ap_regfree(isvar);
+        isvar = NULL;
+    }
+    return APR_SUCCESS;
+}
+AP_DECLARE(apr_status_t) ap_expr_init(apr_pool_t *pool)
+{
+    static ap_regex_t var;
+    if (!isvar) {
+        isvar = &var;
+        if (ap_regcomp(isvar, "\\$([A-Za-z0-9]+)\\{([^\\}]+)\\}", 0)) {
+            isvar = NULL;
+        }
+        else {
+            apr_pool_cleanup_register(pool, isvar, ap_expr_term,
+                                      apr_pool_cleanup_null);
+        }
+    }
+    return isvar ? APR_SUCCESS : APR_EGENERAL;
 }



Re: svn commit: r642971 - in /httpd/httpd/trunk: include/ap_expr.h include/ap_mmn.h server/main.c server/util_expr.c

Posted by André Malo <nd...@perlig.de>.
* Nick Kew wrote:

> On Mon, 31 Mar 2008 22:24:50 +0200
>
> Ruediger Pluem <rp...@apache.org> wrote:

> > >  #define CREATE_NODE(pool,name) do {                          \
> > > -    (name) = apr_palloc(pool, sizeof(*(name)));      \
> > > -    (name)->parent = (name)->left = (name)->right = NULL; \
> > > -    (name)->done = 0;                                     \
> > > -    (name)->dump_done = 0;
> >
> > Why removing this initializations?
> >
> >                               \
> >
> > > +    (name) = apr_pcalloc(pool, sizeof(*(name)));
>
> apr_pcalloc is a more concise equivalent:-)

Really? Maybe I'm too theoretical here, but what happens if NULL != (int)0?

nd
-- 
>kann mir jemand sagen, was genau @-Domains sind?
Ein Mythos. Ein Werbetrick. Verarsche. Nenn es wie du willst...

                 -- Alexandra Buss und Björn Höhrmann in dciwam

Re: svn commit: r642971 - in /httpd/httpd/trunk: include/ap_expr.h include/ap_mmn.h server/main.c server/util_expr.c

Posted by Nick Kew <ni...@webthing.com>.
On Mon, 31 Mar 2008 22:24:50 +0200
Ruediger Pluem <rp...@apache.org> wrote:

> I don't like exposing internals to a public API. If the API user
> always calls it with NULL we should hide this from the API users by
> using a thin wrapper.

Indeed, I think clone needs to be hidden altogether, and plan to do so
(make it automatic when parse and eval are called separately).

> >  #include "ap_expr.h"
> > +#include <assert.h>
> 
> Are we sure that assert.h is available on all platforms?

Hmmm.

I thought we had an assert function, but failed to find apr_assert.
Turns out it's ap_assert, so I'll change it to that.

Thanks for that.

> >  #define CREATE_NODE(pool,name) do {                          \
> > -    (name) = apr_palloc(pool, sizeof(*(name)));      \
> > -    (name)->parent = (name)->left = (name)->right = NULL; \
> > -    (name)->done = 0;                                     \
> > -    (name)->dump_done = 0;   
> 
> Why removing this initializations?
> 
>                               \
> > +    (name) = apr_pcalloc(pool, sizeof(*(name)));

apr_pcalloc is a more concise equivalent:-)

I changed the macro when I started hacking a solution that
would have changed the parse_node struct.  That was before
resorting to the path of least resistance with clone().

-- 
Nick Kew

Application Development with Apache - the Apache Modules Book
http://www.apachetutor.org/

Re: svn commit: r642971 - in /httpd/httpd/trunk: include/ap_expr.h include/ap_mmn.h server/main.c server/util_expr.c

Posted by Ruediger Pluem <rp...@apache.org>.

On 03/31/2008 02:17 PM, niq@apache.org wrote:
> Author: niq
> Date: Mon Mar 31 05:16:58 2008
> New Revision: 642971
> 
> URL: http://svn.apache.org/viewvc?rev=642971&view=rev
> Log:
> Flesh out ap_expr with:
>  * Re-usable parse trees
>  * Canonical string parser function (candidate)
> 
> Modified:
>     httpd/httpd/trunk/include/ap_expr.h
>     httpd/httpd/trunk/include/ap_mmn.h
>     httpd/httpd/trunk/server/main.c
>     httpd/httpd/trunk/server/util_expr.c
> 
> Modified: httpd/httpd/trunk/include/ap_expr.h
> URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/include/ap_expr.h?rev=642971&r1=642970&r2=642971&view=diff
> ==============================================================================
> --- httpd/httpd/trunk/include/ap_expr.h (original)
> +++ httpd/httpd/trunk/include/ap_expr.h Mon Mar 31 05:16:58 2008

> @@ -113,6 +116,43 @@
>                                     int *was_error, backref_t **reptr,
>                                     string_func_t string_func,
>                                     opt_func_t eval_func);
> +
> +/**
> + * Internal initialisation of ap_expr (for httpd)
> + * @param pool Pool
> + * @return APR_SUCCESS or error
> + */
> +AP_DECLARE(apr_status_t) ap_expr_init(apr_pool_t *pool);
> +
> +/**
> + * 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
> + */
> +AP_DECLARE(const char*) ap_expr_string(request_rec *r, const char *str);
> +
> +/**
> + * Clone a parse tree.  This is required if you create a parse tree
> + * using ap_expr_parse, and wish to re-use it many times in ap_expr_eval.
> + * It is not required if you need to use it just once.
> + * @param pool Pool
> + * @param node The parse tree to clone
> + * @param parent Parent node (for internal use when recursing - pass in NULL)

I don't like exposing internals to a public API. If the API user always calls
it with NULL we should hide this from the API users by using a thin wrapper.


> Modified: httpd/httpd/trunk/server/util_expr.c
> URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/util_expr.c?rev=642971&r1=642970&r2=642971&view=diff
> ==============================================================================
> --- httpd/httpd/trunk/server/util_expr.c (original)
> +++ httpd/httpd/trunk/server/util_expr.c Mon Mar 31 05:16:58 2008
> @@ -26,6 +26,7 @@
>  #include "http_log.h"
>  
>  #include "ap_expr.h"
> +#include <assert.h>

Are we sure that assert.h is available on all platforms?

>  #if 1
>  /*
>   * +-------------------------------------------------------+
> @@ -43,10 +44,7 @@
>  } while(0)
>  
>  #define CREATE_NODE(pool,name) do {                          \
> -    (name) = apr_palloc(pool, sizeof(*(name)));      \
> -    (name)->parent = (name)->left = (name)->right = NULL; \
> -    (name)->done = 0;                                     \
> -    (name)->dump_done = 0;   

Why removing this initializations?

                              \
> +    (name) = apr_pcalloc(pool, sizeof(*(name)));
>  } while(0)
>  
>  static void debug_printf(request_rec *r, const char *fmt, ...)


Regards

Rüdiger