Mailing List Archive

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
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 <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);
> 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 [ In reply to ]
On Tue, Aug 3, 2021 at 11:43 AM Eric Covener <covener@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 [ In reply to ]
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 <covener@gmail.com> wrote:
>
> On Tue, Aug 3, 2021 at 11:43 AM Eric Covener <covener@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