You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by jk...@apache.org on 2014/11/27 14:46:12 UTC

svn commit: r1642154 - in /httpd/httpd/trunk: docs/manual/expr.xml include/ap_expr.h server/util_expr_eval.c server/util_expr_parse.y

Author: jkaluza
Date: Thu Nov 27 13:46:11 2014
New Revision: 1642154

URL: http://svn.apache.org/r1642154
Log:
* ap_exr: Add replace(string, from, to) function.

Modified:
    httpd/httpd/trunk/docs/manual/expr.xml
    httpd/httpd/trunk/include/ap_expr.h
    httpd/httpd/trunk/server/util_expr_eval.c
    httpd/httpd/trunk/server/util_expr_parse.y

Modified: httpd/httpd/trunk/docs/manual/expr.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/manual/expr.xml?rev=1642154&r1=1642153&r2=1642154&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/manual/expr.xml (original)
+++ httpd/httpd/trunk/docs/manual/expr.xml Thu Nov 27 13:46:11 2014
@@ -136,7 +136,7 @@ variable    ::= "<strong>%{</strong>" va
 
 rebackref   ::= "<strong>$</strong>" [0-9]
 
-function     ::= funcname "<strong>(</strong>" word "<strong>)</strong>"
+function     ::= funcname "<strong>(</strong>" wordlist "<strong>)</strong>"
 
 listfunction ::= listfuncname "<strong>(</strong>" word "<strong>)</strong>"
 </pre>
@@ -526,6 +526,9 @@ listfunction ::= listfuncname "<strong>(
     <tr><td><code>ldap</code></td>
         <td>Escape characters as required by LDAP distinguished name escaping
             (RFC4514) and LDAP filter escaping (RFC4515).</td><td></td></tr>
+    <tr><td><code>replace</code></td>
+        <td>replace(string, "from", "to") replaces all occurences of "from"
+            in the string with "to".</td><td></td></tr>
 
     </table>
 

Modified: httpd/httpd/trunk/include/ap_expr.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/include/ap_expr.h?rev=1642154&r1=1642153&r2=1642154&view=diff
==============================================================================
--- httpd/httpd/trunk/include/ap_expr.h (original)
+++ httpd/httpd/trunk/include/ap_expr.h Thu Nov 27 13:46:11 2014
@@ -232,6 +232,16 @@ typedef const char *(ap_expr_string_func
                                             const void *data,
                                             const char *arg);
 
+/** String valued function, takes a list argument and returns a string
+ * @param ctx The evaluation context
+ * @param data An opaque context provided by the lookup hook function
+ * @param args The list of string arguments
+ * @return The functions result string, may be NULL for 'empty string'
+ */
+typedef const char *(ap_expr_string_list_func_t)(ap_expr_eval_ctx_t *ctx,
+                                            const void *data,
+                                            const apr_array_header_t *args);
+
 /** 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
@@ -276,7 +286,9 @@ typedef struct {
     const char **err;
 
     /** arg for pre-parsing (only if a simple string).
-     *  For binary ops, this is the right argument. */
+     *  For binary ops, this is the right argument.
+     *  For functions with more arguments, this is the first string
+     *  argument. */
     const char *arg;
 } ap_expr_lookup_parms;
 

Modified: httpd/httpd/trunk/server/util_expr_eval.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/util_expr_eval.c?rev=1642154&r1=1642153&r2=1642154&view=diff
==============================================================================
--- httpd/httpd/trunk/server/util_expr_eval.c (original)
+++ httpd/httpd/trunk/server/util_expr_eval.c Thu Nov 27 13:46:11 2014
@@ -24,6 +24,7 @@
 #include "http_protocol.h"
 #include "http_request.h"
 #include "ap_provider.h"
+#include "util_varbuf.h"
 #include "util_expr_private.h"
 #include "util_md5.h"
 
@@ -32,6 +33,8 @@
 #include "apr_base64.h"
 #include "apr_sha1.h"
 #include "apr_version.h"
+#include "apr_strings.h"
+#include "apr_strmatch.h"
 #if APR_VERSION_AT_LEAST(1,5,0)
 #include "apr_escape.h"
 #endif
@@ -183,13 +186,29 @@ static const char *ap_expr_eval_string_f
                                             const ap_expr_t *info,
                                             const ap_expr_t *arg)
 {
-    ap_expr_string_func_t *func = (ap_expr_string_func_t *)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(info->node_arg1 != NULL);
     AP_DEBUG_ASSERT(data != NULL);
-    return (*func)(ctx, data, ap_expr_eval_word(ctx, arg));
+    if (arg->node_op == op_ListElement) {
+        /* Evaluate the list elements and store them in apr_array_header. */
+        ap_expr_string_list_func_t *func = (ap_expr_string_list_func_t *)info->node_arg1;
+        apr_array_header_t *args = apr_array_make(ctx->p, 1, sizeof(char *));
+        do {
+            const ap_expr_t *val = arg->node_arg1;
+            const char **new = apr_array_push(args);
+            *new = ap_expr_eval_word(ctx, val);
+
+            arg = arg->node_arg2;
+        } while (arg != NULL);
+
+        return (*func)(ctx, data, args);
+    }
+    else {
+        ap_expr_string_func_t *func = (ap_expr_string_func_t *)info->node_arg1;
+        return (*func)(ctx, data, ap_expr_eval_word(ctx, arg));
+    }
 }
 
 static int intstrcmp(const char *s1, const char *s2)
@@ -443,7 +462,27 @@ static ap_expr_t *ap_expr_info_make(int 
     parms.func  = &info->node_arg1;
     parms.data  = &info->node_arg2;
     parms.err   = &ctx->error2;
-    parms.arg   = (arg && arg->node_op == op_String) ? arg->node_arg1 : NULL;
+    parms.arg   = NULL;
+    if (arg) {
+        switch(arg->node_op) {
+            case op_String:
+                parms.arg = arg->node_arg1;
+                break;
+            case op_ListElement:
+                do {
+                    const ap_expr_t *val = arg->node_arg1;
+                    if (val->node_op == op_String) {
+                        parms.arg = val->node_arg1;
+                    }
+                    arg = arg->node_arg2;
+                } while (arg != NULL);
+                break;
+            default:
+                break;
+        }
+    }
+                        ap_log_error(APLOG_MARK, APLOG_ERR, 0, 0,
+                                    "sss %s", parms.arg);
     if (ctx->lookup_fn(&parms) != OK)
         return NULL;
     return info;
@@ -1071,6 +1110,59 @@ static const char *ldap_func(ap_expr_eva
 }
 #endif
 
+static int replace_func_parse_arg(ap_expr_lookup_parms *parms)
+{
+    const char *original = parms->arg;
+    const apr_strmatch_pattern *pattern;
+
+    if (!parms->arg) {
+        *parms->err = apr_psprintf(parms->ptemp, "replace() function needs "
+                                   "exactly 3 arguments");
+        return !OK;
+    }
+    pattern = apr_strmatch_precompile(parms->pool, original, 0);
+    *parms->data = pattern;
+    return OK;
+}
+
+static const char *replace_func(ap_expr_eval_ctx_t *ctx, const void *data,
+                               const apr_array_header_t *args)
+{
+    char *buff, *original, *replacement;
+    struct ap_varbuf vb;
+    apr_size_t repl_len;
+    const char *repl;
+    apr_size_t bytes;
+    apr_size_t len;
+    const apr_strmatch_pattern *pattern = data;
+    if (args->nelts != 3) {
+        *ctx->err = apr_psprintf(ctx->p, "replace() function needs "
+                                 "exactly 3 arguments");
+        return "";
+    }
+
+    buff = APR_ARRAY_IDX(args, 2, char *);
+    original = APR_ARRAY_IDX(args, 1, char *);
+    replacement = APR_ARRAY_IDX(args, 0, char *);
+    repl_len = strlen(replacement);
+    bytes = strlen(buff);
+
+    ap_varbuf_init(ctx->p, &vb, 0);
+    vb.strlen = 0;
+    
+    while ((repl = apr_strmatch(pattern, buff, bytes))) {
+        len = (apr_size_t) (repl - buff);
+        ap_varbuf_strmemcat(&vb, buff, len);
+        ap_varbuf_strmemcat(&vb, replacement, repl_len);
+
+        len += repl_len;
+        bytes -= len;
+        buff += len;
+    }
+
+    return ap_varbuf_pdup(ctx->p, &vb, NULL, 0, buff, bytes, &len);
+}
+
 #define MAX_FILE_SIZE 10*1024*1024
 static const char *file_func(ap_expr_eval_ctx_t *ctx, const void *data,
                              char *arg)
@@ -1657,6 +1749,7 @@ static const struct expr_provider_single
 #if APR_VERSION_AT_LEAST(1,6,0)
     { ldap_func,            "ldap",           NULL, 0 },
 #endif
+    { replace_func,         "replace",        replace_func_parse_arg, 0 },
     { NULL, NULL, NULL}
 };
 

Modified: httpd/httpd/trunk/server/util_expr_parse.y
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/util_expr_parse.y?rev=1642154&r1=1642153&r2=1642154&view=diff
==============================================================================
--- httpd/httpd/trunk/server/util_expr_parse.y (original)
+++ httpd/httpd/trunk/server/util_expr_parse.y Thu Nov 27 13:46:11 2014
@@ -205,6 +205,7 @@ lstfunccall : T_ID '(' word ')' { $$ = a
             ;
 
 strfunccall : T_ID '(' word ')' { $$ = ap_expr_str_func_make($1, $3, ctx); }
+            | T_ID '(' words ')' { $$ = ap_expr_str_func_make($1, $3, ctx); }
             ;
 
 %%



Re: svn commit: r1642154 - in /httpd/httpd/trunk: docs/manual/expr.xml include/ap_expr.h server/util_expr_eval.c server/util_expr_parse.y

Posted by Eric Covener <co...@gmail.com>.
http://svn.apache.org/viewvc?rev=1891989&view=rev
http://svn.apache.org/viewvc?rev=1891990&view=rev

On Tue, Aug 3, 2021 at 1:14 PM Eric Covener <co...@gmail.com> wrote:
>
> On Tue, Aug 3, 2021 at 11:43 AM Eric Covener <co...@gmail.com> wrote:
> >
> > It looks like replace() was broken somewhere after it was committed,
> > but I can't tell how.
> > Does it work for anyone?
> >
> > There seems to be some confusion about the arguments.
> >
> > 1. During parsing, a weird loop in ap_expr_info_make causes the final
> > list argument to be parsed as the strmatch pattern, but the last
> > element is the replacement string not the pattern (from). The 2nd
> > argument is the pattern.
> > Jan's example was:
> > Require expr replace(%{REQUEST_METHOD},  "E", "O") == "GOT"
> > and trace confirms that the pattern is "O"
> >
> > 2. During evaluation, The remaining arguments are passed in an array
> > that skips over the first value, but it still expects three arguments
> > in the array.
> > [Tue Aug 03 15:32:40.807613 2021] [authz_core:error] [pid 33929:tid
> > 123145531994112] [client 127.0.0.1:64195] AH03299: Evaluation of
> > expression from
> > /Users/covener/SRC/httpd-trunk/built/conf/httpd.conf:544 failed:
> > replace() function needs exactly 3 arguments
> >
> > Unfortunately I think these same quirks are passed on to any
> > list-based string function registered dynamically by a module.  But
> > fortunately they are trunk-only.
> >
>
> Looks like some of the confusion comes from the type of the args, some
> of my testing was with literal strings and some not.



-- 
Eric Covener
covener@gmail.com

Re: svn commit: r1642154 - in /httpd/httpd/trunk: docs/manual/expr.xml include/ap_expr.h server/util_expr_eval.c server/util_expr_parse.y

Posted by Eric Covener <co...@gmail.com>.
On Tue, Aug 3, 2021 at 11:43 AM Eric Covener <co...@gmail.com> wrote:
>
> It looks like replace() was broken somewhere after it was committed,
> but I can't tell how.
> Does it work for anyone?
>
> There seems to be some confusion about the arguments.
>
> 1. During parsing, a weird loop in ap_expr_info_make causes the final
> list argument to be parsed as the strmatch pattern, but the last
> element is the replacement string not the pattern (from). The 2nd
> argument is the pattern.
> Jan's example was:
> Require expr replace(%{REQUEST_METHOD},  "E", "O") == "GOT"
> and trace confirms that the pattern is "O"
>
> 2. During evaluation, The remaining arguments are passed in an array
> that skips over the first value, but it still expects three arguments
> in the array.
> [Tue Aug 03 15:32:40.807613 2021] [authz_core:error] [pid 33929:tid
> 123145531994112] [client 127.0.0.1:64195] AH03299: Evaluation of
> expression from
> /Users/covener/SRC/httpd-trunk/built/conf/httpd.conf:544 failed:
> replace() function needs exactly 3 arguments
>
> Unfortunately I think these same quirks are passed on to any
> list-based string function registered dynamically by a module.  But
> fortunately they are trunk-only.
>

Looks like some of the confusion comes from the type of the args, some
of my testing was with literal strings and some not.

Re: svn commit: r1642154 - in /httpd/httpd/trunk: docs/manual/expr.xml include/ap_expr.h server/util_expr_eval.c server/util_expr_parse.y

Posted by Eric Covener <co...@gmail.com>.
It looks like replace() was broken somewhere after it was committed,
but I can't tell how.
Does it work for anyone?

There seems to be some confusion about the arguments.

1. During parsing, a weird loop in ap_expr_info_make causes the final
list argument to be parsed as the strmatch pattern, but the last
element is the replacement string not the pattern (from). The 2nd
argument is the pattern.
Jan's example was:
Require expr replace(%{REQUEST_METHOD},  "E", "O") == "GOT"
and trace confirms that the pattern is "O"

2. During evaluation, The remaining arguments are passed in an array
that skips over the first value, but it still expects three arguments
in the array.
[Tue Aug 03 15:32:40.807613 2021] [authz_core:error] [pid 33929:tid
123145531994112] [client 127.0.0.1:64195] AH03299: Evaluation of
expression from
/Users/covener/SRC/httpd-trunk/built/conf/httpd.conf:544 failed:
replace() function needs exactly 3 arguments

Unfortunately I think these same quirks are passed on to any
list-based string function registered dynamically by a module.  But
fortunately they are trunk-only.


On Thu, Nov 27, 2014 at 8:47 AM <jk...@apache.org> wrote:
>
> Author: jkaluza
> Date: Thu Nov 27 13:46:11 2014
> New Revision: 1642154
>
> URL: http://svn.apache.org/r1642154
> Log:
> * ap_exr: Add replace(string, from, to) function.
>
> Modified:
>     httpd/httpd/trunk/docs/manual/expr.xml
>     httpd/httpd/trunk/include/ap_expr.h
>     httpd/httpd/trunk/server/util_expr_eval.c
>     httpd/httpd/trunk/server/util_expr_parse.y
>
> Modified: httpd/httpd/trunk/docs/manual/expr.xml
> URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/manual/expr.xml?rev=1642154&r1=1642153&r2=1642154&view=diff
> ==============================================================================
> --- httpd/httpd/trunk/docs/manual/expr.xml (original)
> +++ httpd/httpd/trunk/docs/manual/expr.xml Thu Nov 27 13:46:11 2014
> @@ -136,7 +136,7 @@ variable    ::= "<strong>%{</strong>" va
>
>  rebackref   ::= "<strong>$</strong>" [0-9]
>
> -function     ::= funcname "<strong>(</strong>" word "<strong>)</strong>"
> +function     ::= funcname "<strong>(</strong>" wordlist "<strong>)</strong>"
>
>  listfunction ::= listfuncname "<strong>(</strong>" word "<strong>)</strong>"
>  </pre>
> @@ -526,6 +526,9 @@ listfunction ::= listfuncname "<strong>(
>      <tr><td><code>ldap</code></td>
>          <td>Escape characters as required by LDAP distinguished name escaping
>              (RFC4514) and LDAP filter escaping (RFC4515).</td><td></td></tr>
> +    <tr><td><code>replace</code></td>
> +        <td>replace(string, "from", "to") replaces all occurences of "from"
> +            in the string with "to".</td><td></td></tr>
>
>      </table>
>
>
> Modified: httpd/httpd/trunk/include/ap_expr.h
> URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/include/ap_expr.h?rev=1642154&r1=1642153&r2=1642154&view=diff
> ==============================================================================
> --- httpd/httpd/trunk/include/ap_expr.h (original)
> +++ httpd/httpd/trunk/include/ap_expr.h Thu Nov 27 13:46:11 2014
> @@ -232,6 +232,16 @@ typedef const char *(ap_expr_string_func
>                                              const void *data,
>                                              const char *arg);
>
> +/** String valued function, takes a list argument and returns a string
> + * @param ctx The evaluation context
> + * @param data An opaque context provided by the lookup hook function
> + * @param args The list of string arguments
> + * @return The functions result string, may be NULL for 'empty string'
> + */
> +typedef const char *(ap_expr_string_list_func_t)(ap_expr_eval_ctx_t *ctx,
> +                                            const void *data,
> +                                            const apr_array_header_t *args);
> +
>  /** 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
> @@ -276,7 +286,9 @@ typedef struct {
>      const char **err;
>
>      /** arg for pre-parsing (only if a simple string).
> -     *  For binary ops, this is the right argument. */
> +     *  For binary ops, this is the right argument.
> +     *  For functions with more arguments, this is the first string
> +     *  argument. */
>      const char *arg;
>  } ap_expr_lookup_parms;
>
>
> Modified: httpd/httpd/trunk/server/util_expr_eval.c
> URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/util_expr_eval.c?rev=1642154&r1=1642153&r2=1642154&view=diff
> ==============================================================================
> --- httpd/httpd/trunk/server/util_expr_eval.c (original)
> +++ httpd/httpd/trunk/server/util_expr_eval.c Thu Nov 27 13:46:11 2014
> @@ -24,6 +24,7 @@
>  #include "http_protocol.h"
>  #include "http_request.h"
>  #include "ap_provider.h"
> +#include "util_varbuf.h"
>  #include "util_expr_private.h"
>  #include "util_md5.h"
>
> @@ -32,6 +33,8 @@
>  #include "apr_base64.h"
>  #include "apr_sha1.h"
>  #include "apr_version.h"
> +#include "apr_strings.h"
> +#include "apr_strmatch.h"
>  #if APR_VERSION_AT_LEAST(1,5,0)
>  #include "apr_escape.h"
>  #endif
> @@ -183,13 +186,29 @@ static const char *ap_expr_eval_string_f
>                                              const ap_expr_t *info,
>                                              const ap_expr_t *arg)
>  {
> -    ap_expr_string_func_t *func = (ap_expr_string_func_t *)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(info->node_arg1 != NULL);
>      AP_DEBUG_ASSERT(data != NULL);
> -    return (*func)(ctx, data, ap_expr_eval_word(ctx, arg));
> +    if (arg->node_op == op_ListElement) {
> +        /* Evaluate the list elements and store them in apr_array_header. */
> +        ap_expr_string_list_func_t *func = (ap_expr_string_list_func_t *)info->node_arg1;
> +        apr_array_header_t *args = apr_array_make(ctx->p, 1, sizeof(char *));
> +        do {
> +            const ap_expr_t *val = arg->node_arg1;
> +            const char **new = apr_array_push(args);
> +            *new = ap_expr_eval_word(ctx, val);
> +
> +            arg = arg->node_arg2;
> +        } while (arg != NULL);
> +
> +        return (*func)(ctx, data, args);
> +    }
> +    else {
> +        ap_expr_string_func_t *func = (ap_expr_string_func_t *)info->node_arg1;
> +        return (*func)(ctx, data, ap_expr_eval_word(ctx, arg));
> +    }
>  }
>
>  static int intstrcmp(const char *s1, const char *s2)
> @@ -443,7 +462,27 @@ static ap_expr_t *ap_expr_info_make(int
>      parms.func  = &info->node_arg1;
>      parms.data  = &info->node_arg2;
>      parms.err   = &ctx->error2;
> -    parms.arg   = (arg && arg->node_op == op_String) ? arg->node_arg1 : NULL;
> +    parms.arg   = NULL;
> +    if (arg) {
> +        switch(arg->node_op) {
> +            case op_String:
> +                parms.arg = arg->node_arg1;
> +                break;
> +            case op_ListElement:
> +                do {
> +                    const ap_expr_t *val = arg->node_arg1;
> +                    if (val->node_op == op_String) {
> +                        parms.arg = val->node_arg1;
> +                    }
> +                    arg = arg->node_arg2;
> +                } while (arg != NULL);
> +                break;
> +            default:
> +                break;
> +        }
> +    }
> +                        ap_log_error(APLOG_MARK, APLOG_ERR, 0, 0,
> +                                    "sss %s", parms.arg);
>      if (ctx->lookup_fn(&parms) != OK)
>          return NULL;
>      return info;
> @@ -1071,6 +1110,59 @@ static const char *ldap_func(ap_expr_eva
>  }
>  #endif
>
> +static int replace_func_parse_arg(ap_expr_lookup_parms *parms)
> +{
> +    const char *original = parms->arg;
> +    const apr_strmatch_pattern *pattern;
> +
> +    if (!parms->arg) {
> +        *parms->err = apr_psprintf(parms->ptemp, "replace() function needs "
> +                                   "exactly 3 arguments");
> +        return !OK;
> +    }
> +    pattern = apr_strmatch_precompile(parms->pool, original, 0);
> +    *parms->data = pattern;
> +    return OK;
> +}
> +
> +static const char *replace_func(ap_expr_eval_ctx_t *ctx, const void *data,
> +                               const apr_array_header_t *args)
> +{
> +    char *buff, *original, *replacement;
> +    struct ap_varbuf vb;
> +    apr_size_t repl_len;
> +    const char *repl;
> +    apr_size_t bytes;
> +    apr_size_t len;
> +    const apr_strmatch_pattern *pattern = data;
> +    if (args->nelts != 3) {
> +        *ctx->err = apr_psprintf(ctx->p, "replace() function needs "
> +                                 "exactly 3 arguments");
> +        return "";
> +    }
> +
> +    buff = APR_ARRAY_IDX(args, 2, char *);
> +    original = APR_ARRAY_IDX(args, 1, char *);
> +    replacement = APR_ARRAY_IDX(args, 0, char *);
> +    repl_len = strlen(replacement);
> +    bytes = strlen(buff);
> +
> +    ap_varbuf_init(ctx->p, &vb, 0);
> +    vb.strlen = 0;
> +
> +    while ((repl = apr_strmatch(pattern, buff, bytes))) {
> +        len = (apr_size_t) (repl - buff);
> +        ap_varbuf_strmemcat(&vb, buff, len);
> +        ap_varbuf_strmemcat(&vb, replacement, repl_len);
> +
> +        len += repl_len;
> +        bytes -= len;
> +        buff += len;
> +    }
> +
> +    return ap_varbuf_pdup(ctx->p, &vb, NULL, 0, buff, bytes, &len);
> +}
> +
>  #define MAX_FILE_SIZE 10*1024*1024
>  static const char *file_func(ap_expr_eval_ctx_t *ctx, const void *data,
>                               char *arg)
> @@ -1657,6 +1749,7 @@ static const struct expr_provider_single
>  #if APR_VERSION_AT_LEAST(1,6,0)
>      { ldap_func,            "ldap",           NULL, 0 },
>  #endif
> +    { replace_func,         "replace",        replace_func_parse_arg, 0 },
>      { NULL, NULL, NULL}
>  };
>
>
> Modified: httpd/httpd/trunk/server/util_expr_parse.y
> URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/util_expr_parse.y?rev=1642154&r1=1642153&r2=1642154&view=diff
> ==============================================================================
> --- httpd/httpd/trunk/server/util_expr_parse.y (original)
> +++ httpd/httpd/trunk/server/util_expr_parse.y Thu Nov 27 13:46:11 2014
> @@ -205,6 +205,7 @@ lstfunccall : T_ID '(' word ')' { $$ = a
>              ;
>
>  strfunccall : T_ID '(' word ')' { $$ = ap_expr_str_func_make($1, $3, ctx); }
> +            | T_ID '(' words ')' { $$ = ap_expr_str_func_make($1, $3, ctx); }
>              ;
>
>  %%
>
>


--
Eric Covener
covener@gmail.com

Re: svn commit: r1642154 - in /httpd/httpd/trunk: docs/manual/expr.xml include/ap_expr.h server/util_expr_eval.c server/util_expr_parse.y

Posted by Jan Kaluža <jk...@redhat.com>.
On 12/05/2014 05:09 PM, Eric Covener wrote:
> On Fri, Dec 5, 2014 at 11:01 AM, Jan Kaluža <jk...@redhat.com> wrote:
>> On 12/05/2014 02:26 PM, Eric Covener wrote:
>>>
>>> On Thu, Nov 27, 2014 at 8:46 AM,  <jk...@apache.org> wrote:
>>>>
>>>> * ap_exr: Add replace(string, from, to) function.
>>>
>>>
>>> Is it possible to evaluate this from ap_expr_str_exec()?
>>
>>
>> Hm, it worked for me like this:
>>
>> Require expr replace(%{REQUEST_METHOD},  "E", "O") == "GOT"
>
> I think this uses ap_expr_exec / aka boolean result:
>
> static authz_status expr_check_authorization(request_rec *r,
>                                               const char *require_line,
>                                               const void *parsed_require_line)
> {
>      const char *err = NULL;
>      const struct require_expr_info *info = parsed_require_line;
>      int rc = ap_expr_exec(r, info->expr, &err);
>
>      if (rc < 0) {
>          ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02320)
>                        "Error evaluating expression in 'Require expr': %s",
>                        err);
>          return AUTHZ_GENERAL_ERROR;
>      }
>      else if (rc == 0) {
>          if (info->want_user)
>              return AUTHZ_DENIED_NO_USER;
>          else
>              return AUTHZ_DENIED;
>      }
>      else {
>          return AUTHZ_GRANTED;
>      }
> }
>
>>
>> This internally uses ap_expr_str_exec().
>>
>>> I am stuck on trying to get it to work. I think we cannot get to
>>> multi-valued
>>> functions from  the %{func:arg} syntax used when starting at string.
>>
>>
>> I think I'm lost here. Checking for ap_expr documentation, I don't see this
>> syntax. Can you describe this more. I'm sorry, but was checking ap_expr for
>> first time while doing this patch, so there might be things I overlooked.
>
> I think it is the first function of its kind so it may not be easy.
>
> When you actually want a string as the net result of an expression,
> you start at "string" in ap_expr doc.
>
> string      ::= stringpart
>                | string stringpart
>
> stringpart  ::= cstring
>                | variable
>                | rebackref
>
> variable    ::= "%{" varname "}"
>                | "%{" funcname ":" funcargs "}"
>
> Full disclosure -- I don't understand this stuff so well, but I have
> been learning on the job trying to make a dent in documenting some
> different flavors of expressions in at least <if> and header set Foo
> expr= so there is a starting point.

I see what you mean now, thanks. I will need some time to actually think 
about possible solutions.

Right now, I'm curious why we can't add:

stringpart  ::= function

But there may be some problem with that I don't see right now. Well, I 
will try to play with it and let you know.

Jan Kaluza


Re: svn commit: r1642154 - in /httpd/httpd/trunk: docs/manual/expr.xml include/ap_expr.h server/util_expr_eval.c server/util_expr_parse.y

Posted by Eric Covener <co...@gmail.com>.
On Fri, Dec 5, 2014 at 11:01 AM, Jan Kaluža <jk...@redhat.com> wrote:
> On 12/05/2014 02:26 PM, Eric Covener wrote:
>>
>> On Thu, Nov 27, 2014 at 8:46 AM,  <jk...@apache.org> wrote:
>>>
>>> * ap_exr: Add replace(string, from, to) function.
>>
>>
>> Is it possible to evaluate this from ap_expr_str_exec()?
>
>
> Hm, it worked for me like this:
>
> Require expr replace(%{REQUEST_METHOD},  "E", "O") == "GOT"

I think this uses ap_expr_exec / aka boolean result:

static authz_status expr_check_authorization(request_rec *r,
                                             const char *require_line,
                                             const void *parsed_require_line)
{
    const char *err = NULL;
    const struct require_expr_info *info = parsed_require_line;
    int rc = ap_expr_exec(r, info->expr, &err);

    if (rc < 0) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02320)
                      "Error evaluating expression in 'Require expr': %s",
                      err);
        return AUTHZ_GENERAL_ERROR;
    }
    else if (rc == 0) {
        if (info->want_user)
            return AUTHZ_DENIED_NO_USER;
        else
            return AUTHZ_DENIED;
    }
    else {
        return AUTHZ_GRANTED;
    }
}

>
> This internally uses ap_expr_str_exec().
>
>> I am stuck on trying to get it to work. I think we cannot get to
>> multi-valued
>> functions from  the %{func:arg} syntax used when starting at string.
>
>
> I think I'm lost here. Checking for ap_expr documentation, I don't see this
> syntax. Can you describe this more. I'm sorry, but was checking ap_expr for
> first time while doing this patch, so there might be things I overlooked.

I think it is the first function of its kind so it may not be easy.

When you actually want a string as the net result of an expression,
you start at "string" in ap_expr doc.

string      ::= stringpart
              | string stringpart

stringpart  ::= cstring
              | variable
              | rebackref

variable    ::= "%{" varname "}"
              | "%{" funcname ":" funcargs "}"

Full disclosure -- I don't understand this stuff so well, but I have
been learning on the job trying to make a dent in documenting some
different flavors of expressions in at least <if> and header set Foo
expr= so there is a starting point.

Re: svn commit: r1642154 - in /httpd/httpd/trunk: docs/manual/expr.xml include/ap_expr.h server/util_expr_eval.c server/util_expr_parse.y

Posted by Jan Kaluža <jk...@redhat.com>.
On 12/05/2014 02:26 PM, Eric Covener wrote:
> On Thu, Nov 27, 2014 at 8:46 AM,  <jk...@apache.org> wrote:
>> * ap_exr: Add replace(string, from, to) function.
>
> Is it possible to evaluate this from ap_expr_str_exec()?

Hm, it worked for me like this:

Require expr replace(%{REQUEST_METHOD},  "E", "O") == "GOT"

This internally uses ap_expr_str_exec().

> I am stuck on trying to get it to work. I think we cannot get to multi-valued
> functions from  the %{func:arg} syntax used when starting at string.

I think I'm lost here. Checking for ap_expr documentation, I don't see 
this syntax. Can you describe this more. I'm sorry, but was checking 
ap_expr for first time while doing this patch, so there might be things 
I overlooked.

Regards,
Jan Kaluza


Re: svn commit: r1642154 - in /httpd/httpd/trunk: docs/manual/expr.xml include/ap_expr.h server/util_expr_eval.c server/util_expr_parse.y

Posted by Eric Covener <co...@gmail.com>.
On Thu, Nov 27, 2014 at 8:46 AM,  <jk...@apache.org> wrote:
> * ap_exr: Add replace(string, from, to) function.

Is it possible to evaluate this from ap_expr_str_exec()? I am stuck on
trying to get it to work. I think we cannot get to multi-valued
functions from  the %{func:arg} syntax used when starting at string.

Re: svn commit: r1642154 - in /httpd/httpd/trunk: docs/manual/expr.xml include/ap_expr.h server/util_expr_eval.c server/util_expr_parse.y

Posted by Yann Ylavic <yl...@gmail.com>.
On Fri, Dec 5, 2014 at 5:51 PM, Yann Ylavic <yl...@gmail.com> wrote:
> replace("abc*def",  "c*", "gh") is "abgh", and not "abghef" as one may expect.

s/"abghef"/"abghdef"/ above.

Re: svn commit: r1642154 - in /httpd/httpd/trunk: docs/manual/expr.xml include/ap_expr.h server/util_expr_eval.c server/util_expr_parse.y

Posted by Yann Ylavic <yl...@gmail.com>.
On Fri, Dec 5, 2014 at 9:05 PM, Ruediger Pluem <rp...@apache.org> wrote:
> On 12/05/2014 05:51 PM, Yann Ylavic wrote:
>> Maybe it is worth noting (doc?) that "from" is a ap_strmatch() pattern
>> (with wildcards [*?]), hence eg.
>
> Are you sure you aren't assuming apr_fnmatch instead of apr_strmatch?

Doh! Absolutely.
I did not know apr_strmatch() actually, and read it as ap_strcmp_match()...
Nice function though, will use it more often :p

Just grep'ing "strmatch" now, I find this :

# server/util_expr_eval.c
static int op_strmatch(ap_expr_eval_ctx_t *ctx, const void *data,
                       const char *arg1, const char *arg2)
{
    return (APR_SUCCESS == apr_fnmatch(arg2, arg1, 0));
}

Quite confusing :)

Sorry for the noise,
regards,
Yann.

Re: svn commit: r1642154 - in /httpd/httpd/trunk: docs/manual/expr.xml include/ap_expr.h server/util_expr_eval.c server/util_expr_parse.y

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

On 12/05/2014 05:51 PM, Yann Ylavic wrote:
> On Thu, Nov 27, 2014 at 2:46 PM,  <jk...@apache.org> wrote:
>> Author: jkaluza
>> Date: Thu Nov 27 13:46:11 2014
>> New Revision: 1642154
>>
>> URL: http://svn.apache.org/r1642154
>> Log:
>> * ap_exr: Add replace(string, from, to) function.
> 
> Maybe it is worth noting (doc?) that "from" is a ap_strmatch() pattern
> (with wildcards [*?]), hence eg.

Are you sure you aren't assuming apr_fnmatch instead of apr_strmatch?

Regards

Rüdiger


Re: svn commit: r1642154 - in /httpd/httpd/trunk: docs/manual/expr.xml include/ap_expr.h server/util_expr_eval.c server/util_expr_parse.y

Posted by Yann Ylavic <yl...@gmail.com>.
On Thu, Nov 27, 2014 at 2:46 PM,  <jk...@apache.org> wrote:
> Author: jkaluza
> Date: Thu Nov 27 13:46:11 2014
> New Revision: 1642154
>
> URL: http://svn.apache.org/r1642154
> Log:
> * ap_exr: Add replace(string, from, to) function.

Maybe it is worth noting (doc?) that "from" is a ap_strmatch() pattern
(with wildcards [*?]), hence eg.
replace("abc*def",  "c*", "gh") is "abgh", and not "abghef" as one may expect.

Maybe then we should name this one replace_match(), and have replace()
(or replace_string) working on pure string patterns.
Likewise replace_regex(string, capture, substitution) would be nice to have.

Regards,
Yann.

Re: svn commit: r1642154 - in /httpd/httpd/trunk: docs/manual/expr.xml include/ap_expr.h server/util_expr_eval.c server/util_expr_parse.y

Posted by Jan Kaluža <jk...@redhat.com>.
Thanks for reviewing that commit. I've fixed both issues in r1643094.

Regards,
Jan Kaluza

On 12/02/2014 09:55 PM, Ruediger Pluem wrote:
>
>
> On 11/27/2014 02:46 PM, jkaluza@apache.org wrote:
>> Author: jkaluza
>> Date: Thu Nov 27 13:46:11 2014
>> New Revision: 1642154
>>
>> URL: http://svn.apache.org/r1642154
>> Log:
>> * ap_exr: Add replace(string, from, to) function.
>>
>> Modified:
>>      httpd/httpd/trunk/docs/manual/expr.xml
>>      httpd/httpd/trunk/include/ap_expr.h
>>      httpd/httpd/trunk/server/util_expr_eval.c
>>      httpd/httpd/trunk/server/util_expr_parse.y
>>
>
>> Modified: httpd/httpd/trunk/server/util_expr_eval.c
>> URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/util_expr_eval.c?rev=1642154&r1=1642153&r2=1642154&view=diff
>> ==============================================================================
>> --- httpd/httpd/trunk/server/util_expr_eval.c (original)
>> +++ httpd/httpd/trunk/server/util_expr_eval.c Thu Nov 27 13:46:11 2014
>
>> @@ -183,13 +186,29 @@ static const char *ap_expr_eval_string_f
>>                                               const ap_expr_t *info,
>>                                               const ap_expr_t *arg)
>>   {
>> -    ap_expr_string_func_t *func = (ap_expr_string_func_t *)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(info->node_arg1 != NULL);
>>       AP_DEBUG_ASSERT(data != NULL);
>> -    return (*func)(ctx, data, ap_expr_eval_word(ctx, arg));
>> +    if (arg->node_op == op_ListElement) {
>> +        /* Evaluate the list elements and store them in apr_array_header. */
>> +        ap_expr_string_list_func_t *func = (ap_expr_string_list_func_t *)info->node_arg1;
>> +        apr_array_header_t *args = apr_array_make(ctx->p, 1, sizeof(char *));
>
> Shouldn't we use at least 2 instead of 1? I guess we expect at least 2 elements.
>
>> +        do {
>> +            const ap_expr_t *val = arg->node_arg1;
>> +            const char **new = apr_array_push(args);
>> +            *new = ap_expr_eval_word(ctx, val);
>> +
>> +            arg = arg->node_arg2;
>> +        } while (arg != NULL);
>> +
>> +        return (*func)(ctx, data, args);
>> +    }
>> +    else {
>> +        ap_expr_string_func_t *func = (ap_expr_string_func_t *)info->node_arg1;
>> +        return (*func)(ctx, data, ap_expr_eval_word(ctx, arg));
>> +    }
>>   }
>>
>>   static int intstrcmp(const char *s1, const char *s2)
>
>> @@ -1071,6 +1110,59 @@ static const char *ldap_func(ap_expr_eva
>>   }
>>   #endif
>>
>> +static int replace_func_parse_arg(ap_expr_lookup_parms *parms)
>> +{
>> +    const char *original = parms->arg;
>> +    const apr_strmatch_pattern *pattern;
>> +
>> +    if (!parms->arg) {
>> +        *parms->err = apr_psprintf(parms->ptemp, "replace() function needs "
>> +                                   "exactly 3 arguments");
>> +        return !OK;
>> +    }
>> +    pattern = apr_strmatch_precompile(parms->pool, original, 0);
>> +    *parms->data = pattern;
>> +    return OK;
>> +}
>> +
>> +static const char *replace_func(ap_expr_eval_ctx_t *ctx, const void *data,
>> +                               const apr_array_header_t *args)
>> +{
>> +    char *buff, *original, *replacement;
>> +    struct ap_varbuf vb;
>> +    apr_size_t repl_len;
>> +    const char *repl;
>> +    apr_size_t bytes;
>> +    apr_size_t len;
>> +    const apr_strmatch_pattern *pattern = data;
>> +    if (args->nelts != 3) {
>> +        *ctx->err = apr_psprintf(ctx->p, "replace() function needs "
>> +                                 "exactly 3 arguments");
>> +        return "";
>> +    }
>> +
>> +    buff = APR_ARRAY_IDX(args, 2, char *);
>> +    original = APR_ARRAY_IDX(args, 1, char *);
>> +    replacement = APR_ARRAY_IDX(args, 0, char *);
>> +    repl_len = strlen(replacement);
>> +    bytes = strlen(buff);
>> +
>> +    ap_varbuf_init(ctx->p, &vb, 0);
>> +    vb.strlen = 0;
>> +
>> +    while ((repl = apr_strmatch(pattern, buff, bytes))) {
>> +        len = (apr_size_t) (repl - buff);
>> +        ap_varbuf_strmemcat(&vb, buff, len);
>> +        ap_varbuf_strmemcat(&vb, replacement, repl_len);
>> +
>> +        len += repl_len;
>
> This goes wrong if replacement string and original string are of different size. IMHO you need to add strlen(original)
> to len above.
>
>> +        bytes -= len;
>> +        buff += len;
>> +    }
>> +
>> +    return ap_varbuf_pdup(ctx->p, &vb, NULL, 0, buff, bytes, &len);
>> +}
>> +
>>   #define MAX_FILE_SIZE 10*1024*1024
>>   static const char *file_func(ap_expr_eval_ctx_t *ctx, const void *data,
>>                                char *arg)
>> @@ -1657,6 +1749,7 @@ static const struct expr_provider_single
>
> Regards
>
> Rüdiger
>


Re: svn commit: r1642154 - in /httpd/httpd/trunk: docs/manual/expr.xml include/ap_expr.h server/util_expr_eval.c server/util_expr_parse.y

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

On 11/27/2014 02:46 PM, jkaluza@apache.org wrote:
> Author: jkaluza
> Date: Thu Nov 27 13:46:11 2014
> New Revision: 1642154
> 
> URL: http://svn.apache.org/r1642154
> Log:
> * ap_exr: Add replace(string, from, to) function.
> 
> Modified:
>     httpd/httpd/trunk/docs/manual/expr.xml
>     httpd/httpd/trunk/include/ap_expr.h
>     httpd/httpd/trunk/server/util_expr_eval.c
>     httpd/httpd/trunk/server/util_expr_parse.y
> 

> Modified: httpd/httpd/trunk/server/util_expr_eval.c
> URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/util_expr_eval.c?rev=1642154&r1=1642153&r2=1642154&view=diff
> ==============================================================================
> --- httpd/httpd/trunk/server/util_expr_eval.c (original)
> +++ httpd/httpd/trunk/server/util_expr_eval.c Thu Nov 27 13:46:11 2014

> @@ -183,13 +186,29 @@ static const char *ap_expr_eval_string_f
>                                              const ap_expr_t *info,
>                                              const ap_expr_t *arg)
>  {
> -    ap_expr_string_func_t *func = (ap_expr_string_func_t *)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(info->node_arg1 != NULL);
>      AP_DEBUG_ASSERT(data != NULL);
> -    return (*func)(ctx, data, ap_expr_eval_word(ctx, arg));
> +    if (arg->node_op == op_ListElement) {
> +        /* Evaluate the list elements and store them in apr_array_header. */
> +        ap_expr_string_list_func_t *func = (ap_expr_string_list_func_t *)info->node_arg1;
> +        apr_array_header_t *args = apr_array_make(ctx->p, 1, sizeof(char *));

Shouldn't we use at least 2 instead of 1? I guess we expect at least 2 elements.

> +        do {
> +            const ap_expr_t *val = arg->node_arg1;
> +            const char **new = apr_array_push(args);
> +            *new = ap_expr_eval_word(ctx, val);
> +
> +            arg = arg->node_arg2;
> +        } while (arg != NULL);
> +
> +        return (*func)(ctx, data, args);
> +    }
> +    else {
> +        ap_expr_string_func_t *func = (ap_expr_string_func_t *)info->node_arg1;
> +        return (*func)(ctx, data, ap_expr_eval_word(ctx, arg));
> +    }
>  }
>  
>  static int intstrcmp(const char *s1, const char *s2)

> @@ -1071,6 +1110,59 @@ static const char *ldap_func(ap_expr_eva
>  }
>  #endif
>  
> +static int replace_func_parse_arg(ap_expr_lookup_parms *parms)
> +{
> +    const char *original = parms->arg;
> +    const apr_strmatch_pattern *pattern;
> +
> +    if (!parms->arg) {
> +        *parms->err = apr_psprintf(parms->ptemp, "replace() function needs "
> +                                   "exactly 3 arguments");
> +        return !OK;
> +    }
> +    pattern = apr_strmatch_precompile(parms->pool, original, 0);
> +    *parms->data = pattern;
> +    return OK;
> +}
> +
> +static const char *replace_func(ap_expr_eval_ctx_t *ctx, const void *data,
> +                               const apr_array_header_t *args)
> +{
> +    char *buff, *original, *replacement;
> +    struct ap_varbuf vb;
> +    apr_size_t repl_len;
> +    const char *repl;
> +    apr_size_t bytes;
> +    apr_size_t len;
> +    const apr_strmatch_pattern *pattern = data;
> +    if (args->nelts != 3) {
> +        *ctx->err = apr_psprintf(ctx->p, "replace() function needs "
> +                                 "exactly 3 arguments");
> +        return "";
> +    }
> +
> +    buff = APR_ARRAY_IDX(args, 2, char *);
> +    original = APR_ARRAY_IDX(args, 1, char *);
> +    replacement = APR_ARRAY_IDX(args, 0, char *);
> +    repl_len = strlen(replacement);
> +    bytes = strlen(buff);
> +
> +    ap_varbuf_init(ctx->p, &vb, 0);
> +    vb.strlen = 0;
> +    
> +    while ((repl = apr_strmatch(pattern, buff, bytes))) {
> +        len = (apr_size_t) (repl - buff);
> +        ap_varbuf_strmemcat(&vb, buff, len);
> +        ap_varbuf_strmemcat(&vb, replacement, repl_len);
> +
> +        len += repl_len;

This goes wrong if replacement string and original string are of different size. IMHO you need to add strlen(original)
to len above.

> +        bytes -= len;
> +        buff += len;
> +    }
> +
> +    return ap_varbuf_pdup(ctx->p, &vb, NULL, 0, buff, bytes, &len);
> +}
> +
>  #define MAX_FILE_SIZE 10*1024*1024
>  static const char *file_func(ap_expr_eval_ctx_t *ctx, const void *data,
>                               char *arg)
> @@ -1657,6 +1749,7 @@ static const struct expr_provider_single

Regards

Rüdiger


Re: svn commit: r1642154 - in /httpd/httpd/trunk: docs/manual/expr.xml include/ap_expr.h server/util_expr_eval.c server/util_expr_parse.y

Posted by Eric Covener <co...@gmail.com>.
On Sun, Dec 21, 2014 at 6:37 AM, Graham Leggett <mi...@sharp.fm> wrote:
> I am currently getting the error “sss” (not sure what that means?) when attempting to use named regex variables in LocationMatch - can you confirm this works as expected?

When I saw this I was sure it was my own mis-committted debug, but it
looks like it really did come from here (r1642154). I removed  t
anyway.

Re: svn commit: r1642154 - in /httpd/httpd/trunk: docs/manual/expr.xml include/ap_expr.h server/util_expr_eval.c server/util_expr_parse.y

Posted by Graham Leggett <mi...@sharp.fm>.
On 27 Nov 2014, at 3:46 PM, jkaluza@apache.org wrote:

> Author: jkaluza
> Date: Thu Nov 27 13:46:11 2014
> New Revision: 1642154
> 
> URL: http://svn.apache.org/r1642154
> Log:
> * ap_exr: Add replace(string, from, to) function.
> 
> Modified:
>    httpd/httpd/trunk/docs/manual/expr.xml
>    httpd/httpd/trunk/include/ap_expr.h
>    httpd/httpd/trunk/server/util_expr_eval.c
>    httpd/httpd/trunk/server/util_expr_parse.y
> 
> Modified: httpd/httpd/trunk/docs/manual/expr.xml
> URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/manual/expr.xml?rev=1642154&r1=1642153&r2=1642154&view=diff
> ==============================================================================
> --- httpd/httpd/trunk/docs/manual/expr.xml (original)
> +++ httpd/httpd/trunk/docs/manual/expr.xml Thu Nov 27 13:46:11 2014
> @@ -136,7 +136,7 @@ variable    ::= "<strong>%{</strong>" va
> 
> rebackref   ::= "<strong>$</strong>" [0-9]
> 
> -function     ::= funcname "<strong>(</strong>" word "<strong>)</strong>"
> +function     ::= funcname "<strong>(</strong>" wordlist "<strong>)</strong>"
> 
> listfunction ::= listfuncname "<strong>(</strong>" word "<strong>)</strong>"
> </pre>
> @@ -526,6 +526,9 @@ listfunction ::= listfuncname "<strong>(
>     <tr><td><code>ldap</code></td>
>         <td>Escape characters as required by LDAP distinguished name escaping
>             (RFC4514) and LDAP filter escaping (RFC4515).</td><td></td></tr>
> +    <tr><td><code>replace</code></td>
> +        <td>replace(string, "from", "to") replaces all occurences of "from"
> +            in the string with "to".</td><td></td></tr>
> 
>     </table>
> 
> 
> Modified: httpd/httpd/trunk/include/ap_expr.h
> URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/include/ap_expr.h?rev=1642154&r1=1642153&r2=1642154&view=diff
> ==============================================================================
> --- httpd/httpd/trunk/include/ap_expr.h (original)
> +++ httpd/httpd/trunk/include/ap_expr.h Thu Nov 27 13:46:11 2014
> @@ -232,6 +232,16 @@ typedef const char *(ap_expr_string_func
>                                             const void *data,
>                                             const char *arg);
> 
> +/** String valued function, takes a list argument and returns a string
> + * @param ctx The evaluation context
> + * @param data An opaque context provided by the lookup hook function
> + * @param args The list of string arguments
> + * @return The functions result string, may be NULL for 'empty string'
> + */
> +typedef const char *(ap_expr_string_list_func_t)(ap_expr_eval_ctx_t *ctx,
> +                                            const void *data,
> +                                            const apr_array_header_t *args);
> +
> /** 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
> @@ -276,7 +286,9 @@ typedef struct {
>     const char **err;
> 
>     /** arg for pre-parsing (only if a simple string).
> -     *  For binary ops, this is the right argument. */
> +     *  For binary ops, this is the right argument.
> +     *  For functions with more arguments, this is the first string
> +     *  argument. */
>     const char *arg;
> } ap_expr_lookup_parms;
> 
> 
> Modified: httpd/httpd/trunk/server/util_expr_eval.c
> URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/util_expr_eval.c?rev=1642154&r1=1642153&r2=1642154&view=diff
> ==============================================================================
> --- httpd/httpd/trunk/server/util_expr_eval.c (original)
> +++ httpd/httpd/trunk/server/util_expr_eval.c Thu Nov 27 13:46:11 2014
> @@ -24,6 +24,7 @@
> #include "http_protocol.h"
> #include "http_request.h"
> #include "ap_provider.h"
> +#include "util_varbuf.h"
> #include "util_expr_private.h"
> #include "util_md5.h"
> 
> @@ -32,6 +33,8 @@
> #include "apr_base64.h"
> #include "apr_sha1.h"
> #include "apr_version.h"
> +#include "apr_strings.h"
> +#include "apr_strmatch.h"
> #if APR_VERSION_AT_LEAST(1,5,0)
> #include "apr_escape.h"
> #endif
> @@ -183,13 +186,29 @@ static const char *ap_expr_eval_string_f
>                                             const ap_expr_t *info,
>                                             const ap_expr_t *arg)
> {
> -    ap_expr_string_func_t *func = (ap_expr_string_func_t *)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(info->node_arg1 != NULL);
>     AP_DEBUG_ASSERT(data != NULL);
> -    return (*func)(ctx, data, ap_expr_eval_word(ctx, arg));
> +    if (arg->node_op == op_ListElement) {
> +        /* Evaluate the list elements and store them in apr_array_header. */
> +        ap_expr_string_list_func_t *func = (ap_expr_string_list_func_t *)info->node_arg1;
> +        apr_array_header_t *args = apr_array_make(ctx->p, 1, sizeof(char *));
> +        do {
> +            const ap_expr_t *val = arg->node_arg1;
> +            const char **new = apr_array_push(args);
> +            *new = ap_expr_eval_word(ctx, val);
> +
> +            arg = arg->node_arg2;
> +        } while (arg != NULL);
> +
> +        return (*func)(ctx, data, args);
> +    }
> +    else {
> +        ap_expr_string_func_t *func = (ap_expr_string_func_t *)info->node_arg1;
> +        return (*func)(ctx, data, ap_expr_eval_word(ctx, arg));
> +    }
> }
> 
> static int intstrcmp(const char *s1, const char *s2)
> @@ -443,7 +462,27 @@ static ap_expr_t *ap_expr_info_make(int 
>     parms.func  = &info->node_arg1;
>     parms.data  = &info->node_arg2;
>     parms.err   = &ctx->error2;
> -    parms.arg   = (arg && arg->node_op == op_String) ? arg->node_arg1 : NULL;
> +    parms.arg   = NULL;
> +    if (arg) {
> +        switch(arg->node_op) {
> +            case op_String:
> +                parms.arg = arg->node_arg1;
> +                break;
> +            case op_ListElement:
> +                do {
> +                    const ap_expr_t *val = arg->node_arg1;
> +                    if (val->node_op == op_String) {
> +                        parms.arg = val->node_arg1;
> +                    }
> +                    arg = arg->node_arg2;
> +                } while (arg != NULL);
> +                break;
> +            default:
> +                break;
> +        }
> +    }
> +                        ap_log_error(APLOG_MARK, APLOG_ERR, 0, 0,
> +                                    "sss %s", parms.arg);

I am currently getting the error “sss” (not sure what that means?) when attempting to use named regex variables in LocationMatch - can you confirm this works as expected?

[Sun Dec 21 11:16:49.894286 2014] [core:error] [pid 42903:tid 140735132574464] sss MATCH_NUMBER
[Sun Dec 21 11:16:49.894359 2014] [core:error] [pid 42903:tid 140735132574464] sss MATCH_SUFFIX
[Sun Dec 21 11:16:49.894386 2014] [core:error] [pid 42903:tid 140735132574464] sss MATCH_NUMBER
[Sun Dec 21 11:16:49.894408 2014] [core:error] [pid 42903:tid 140735132574464] sss MATCH_NUMBER
[Sun Dec 21 11:16:49.894480 2014] [core:error] [pid 42903:tid 140735132574464] sss MATCH_NUMBER

Config looks like this:

    <LocationMatch /expr/ali(?<number>[0-9])>
        [DirectiveSupportingExpressions] /%{env:MATCH_NUMBER}.html
    </LocationMatch>

From the subsequent discussion, it looks like this patch breaks ap_expr_str_exec().

(Or perhaps this is noise and I am chasing something else - any idea what the error “sss” means?)

Regards,
Graham
—