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
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;
#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"
#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
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)
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;
}
#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)
#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}
};