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