From bd41584fcbf32708980227497941399da9ac3e5d Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jan=20Kalu=C5=BEa?= Date: Thu, 27 Nov 2014 13:46:11 +0000 Subject: [PATCH] * ap_exr: Add replace(string, from, to) function. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1642154 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/expr.xml | 5 +- include/ap_expr.h | 14 +++++- server/util_expr_eval.c | 101 +++++++++++++++++++++++++++++++++++++-- server/util_expr_parse.y | 1 + 4 files changed, 115 insertions(+), 6 deletions(-) diff --git a/docs/manual/expr.xml b/docs/manual/expr.xml index e386ff51ac..abf6fd917b 100644 --- a/docs/manual/expr.xml +++ b/docs/manual/expr.xml @@ -136,7 +136,7 @@ variable ::= "%{" varname "}" rebackref ::= "$" [0-9] -function ::= funcname "(" word ")" +function ::= funcname "(" wordlist ")" listfunction ::= listfuncname "(" word ")" @@ -526,6 +526,9 @@ listfunction ::= listfuncname "(" word ")" ldap Escape characters as required by LDAP distinguished name escaping (RFC4514) and LDAP filter escaping (RFC4515). + replace + replace(string, "from", "to") replaces all occurences of "from" + in the string with "to". diff --git a/include/ap_expr.h b/include/ap_expr.h index 55fff36317..a961193f13 100644 --- a/include/ap_expr.h +++ b/include/ap_expr.h @@ -232,6 +232,16 @@ typedef const char *(ap_expr_string_func_t)(ap_expr_eval_ctx_t *ctx, 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; diff --git a/server/util_expr_eval.c b/server/util_expr_eval.c index f7c439c627..7e914b720d 100644 --- a/server/util_expr_eval.c +++ b/server/util_expr_eval.c @@ -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_func(ap_expr_eval_ctx_t *ctx, 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 type, const char *name, 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_eval_ctx_t *ctx, const void *data, } #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 string_func_providers[] = { #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} }; diff --git a/server/util_expr_parse.y b/server/util_expr_parse.y index a389410b7f..9e02602139 100644 --- a/server/util_expr_parse.y +++ b/server/util_expr_parse.y @@ -205,6 +205,7 @@ lstfunccall : T_ID '(' word ')' { $$ = ap_expr_list_func_make($1, $3, ctx); } ; strfunccall : T_ID '(' word ')' { $$ = ap_expr_str_func_make($1, $3, ctx); } + | T_ID '(' words ')' { $$ = ap_expr_str_func_make($1, $3, ctx); } ; %% -- 2.40.0