1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * ap_expr_eval.c, based on ssl_expr_eval.c from mod_ssl
23 #include "http_core.h"
24 #include "http_protocol.h"
25 #include "http_request.h"
26 #include "ap_provider.h"
27 #include "util_varbuf.h"
28 #include "util_expr_private.h"
30 #include "util_varbuf.h"
33 #include "apr_fnmatch.h"
34 #include "apr_base64.h"
36 #include "apr_version.h"
37 #include "apr_strings.h"
38 #include "apr_strmatch.h"
39 #if APR_VERSION_AT_LEAST(1,5,0)
40 #include "apr_escape.h"
43 #include <limits.h> /* for INT_MAX */
45 /* we know core's module_index is 0 */
46 #undef APLOG_MODULE_INDEX
47 #define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
50 APR_HOOK_LINK(expr_lookup)
53 AP_IMPLEMENT_HOOK_RUN_FIRST(int, expr_lookup, (ap_expr_lookup_parms *parms),
56 #define LOG_MARK(info) __FILE__, __LINE__, (info)->module_index
58 static int ap_expr_eval_cond(ap_expr_eval_ctx_t *ctx, const ap_expr_t *node);
60 static const char *ap_expr_eval_string_func(ap_expr_eval_ctx_t *ctx,
61 const ap_expr_t *info,
62 const ap_expr_t *args);
63 static const char *ap_expr_eval_re_backref(ap_expr_eval_ctx_t *ctx,
65 static const char *ap_expr_eval_var(ap_expr_eval_ctx_t *ctx,
66 ap_expr_var_func_t *func,
71 const ap_expr_t *subst;
74 static const char *ap_expr_regexec(const char *subject,
76 apr_array_header_t *list,
77 ap_expr_eval_ctx_t *ctx);
79 static apr_array_header_t *ap_expr_list_make(ap_expr_eval_ctx_t *ctx,
80 const ap_expr_t *node);
82 /* define AP_EXPR_DEBUG to log the parse tree when parsing an expression */
84 static void expr_dump_tree(const ap_expr_t *e, const server_rec *s,
85 int loglevel, int indent);
89 * To reduce counting overhead, we only count calls to
90 * ap_expr_eval_word() and ap_expr_eval_cond(). The max number of
91 * stack frames is larger by some factor.
93 #define AP_EXPR_MAX_RECURSION 20
94 static int inc_rec(ap_expr_eval_ctx_t *ctx)
96 if (ctx->reclvl < AP_EXPR_MAX_RECURSION) {
100 *ctx->err = "Recursion limit reached";
101 /* short circuit further evaluation */
102 ctx->reclvl = INT_MAX;
106 static const char *ap_expr_list_pstrcat(apr_pool_t *p,
107 const apr_array_header_t *list,
110 if (list->nelts <= 0) {
113 else if (list->nelts == 1) {
114 return APR_ARRAY_IDX(list, 0, const char*);
118 int n = list->nelts - 1, i;
119 apr_size_t slen = strlen(sep), vlen;
122 ap_varbuf_init(p, &vb, 0);
123 for (i = 0; i < n; ++i) {
124 val = APR_ARRAY_IDX(list, i, const char*);
126 ap_varbuf_grow(&vb, vlen + slen + 1);
127 ap_varbuf_strmemcat(&vb, val, vlen);
128 ap_varbuf_strmemcat(&vb, sep, slen);
130 val = APR_ARRAY_IDX(list, n, const char*);
131 ap_varbuf_strmemcat(&vb, val, strlen(val));
137 static const char *ap_expr_eval_word(ap_expr_eval_ctx_t *ctx,
138 const ap_expr_t *node)
140 const char *result = "";
143 switch (node->node_op) {
146 result = node->node_arg1;
149 result = ap_expr_eval_word(ctx, node->node_arg1);
152 result = ap_expr_eval_cond(ctx, node->node_arg1) ? "true" : "false";
155 result = ap_expr_eval_var(ctx, (ap_expr_var_func_t *)node->node_arg1,
159 if (((ap_expr_t *)node->node_arg2)->node_op != op_Concat &&
160 ((ap_expr_t *)node->node_arg1)->node_op != op_Concat) {
161 const char *s1 = ap_expr_eval_word(ctx, node->node_arg1);
162 const char *s2 = ap_expr_eval_word(ctx, node->node_arg2);
168 result = apr_pstrcat(ctx->p, s1, s2, NULL);
170 else if (((ap_expr_t *)node->node_arg1)->node_op == op_Concat) {
171 const ap_expr_t *nodep = node;
176 nodep = nodep->node_arg1;
178 } while (nodep->node_op == op_Concat);
179 vec = apr_palloc(ctx->p, i * sizeof(struct iovec));
184 vec[i].iov_base = (void *)ap_expr_eval_word(ctx,
186 vec[i].iov_len = strlen(vec[i].iov_base);
188 nodep = nodep->node_arg1;
189 } while (nodep->node_op == op_Concat);
190 vec[i].iov_base = (void *)ap_expr_eval_word(ctx, nodep);
191 vec[i].iov_len = strlen(vec[i].iov_base);
192 result = apr_pstrcatv(ctx->p, vec, n, NULL);
195 const ap_expr_t *nodep = node;
199 nodep = nodep->node_arg2;
201 } while (nodep->node_op == op_Concat);
202 vec = apr_palloc(ctx->p, i * sizeof(struct iovec));
206 vec[i].iov_base = (void *)ap_expr_eval_word(ctx,
208 vec[i].iov_len = strlen(vec[i].iov_base);
210 nodep = nodep->node_arg2;
211 } while (nodep->node_op == op_Concat);
212 vec[i].iov_base = (void *)ap_expr_eval_word(ctx, nodep);
213 vec[i].iov_len = strlen(vec[i].iov_base);
215 result = apr_pstrcatv(ctx->p, vec, i, NULL);
218 case op_StringFuncCall: {
219 const ap_expr_t *info = node->node_arg1;
220 const ap_expr_t *args = node->node_arg2;
221 result = ap_expr_eval_string_func(ctx, info, args);
226 apr_array_header_t *list = ap_expr_list_make(ctx, node->node_arg1);
227 sep = node->node_arg2 ? ap_expr_eval_word(ctx, node->node_arg2) : "";
228 result = ap_expr_list_pstrcat(ctx->p, list, sep);
232 const ap_expr_t *reg = node->node_arg2;
233 const char *subject = ap_expr_eval_word(ctx, node->node_arg1);
234 result = ap_expr_regexec(subject, reg, NULL, ctx);
238 const unsigned int *np = node->node_arg1;
239 result = ap_expr_eval_re_backref(ctx, *np);
243 *ctx->err = "Internal evaluation error: Unknown word expression node";
252 static const char *ap_expr_eval_var(ap_expr_eval_ctx_t *ctx,
253 ap_expr_var_func_t *func,
256 AP_DEBUG_ASSERT(func != NULL);
257 AP_DEBUG_ASSERT(data != NULL);
258 return (*func)(ctx, data);
261 static const char *ap_expr_eval_re_backref(ap_expr_eval_ctx_t *ctx, unsigned int n)
265 if (!ctx->re_pmatch || !ctx->re_source || !*ctx->re_source
266 || **ctx->re_source == '\0' || ctx->re_nmatch < n + 1)
269 len = ctx->re_pmatch[n].rm_eo - ctx->re_pmatch[n].rm_so;
273 return apr_pstrndup(ctx->p, *ctx->re_source + ctx->re_pmatch[n].rm_so, len);
276 static const char *ap_expr_eval_string_func(ap_expr_eval_ctx_t *ctx,
277 const ap_expr_t *info,
278 const ap_expr_t *arg)
280 const void *data = info->node_arg2;
282 AP_DEBUG_ASSERT(info->node_op == op_StringFuncInfo);
283 AP_DEBUG_ASSERT(info->node_arg1 != NULL);
284 AP_DEBUG_ASSERT(data != NULL);
285 if (arg->node_op == op_ListElement) {
286 /* Evaluate the list elements and store them in apr_array_header. */
287 ap_expr_string_list_func_t *func = (ap_expr_string_list_func_t *)info->node_arg1;
288 apr_array_header_t *args = ap_expr_list_make(ctx, arg->node_arg1);
289 return (*func)(ctx, data, args);
292 ap_expr_string_func_t *func = (ap_expr_string_func_t *)info->node_arg1;
293 return (*func)(ctx, data, ap_expr_eval_word(ctx, arg));
297 static int intstrcmp(const char *s1, const char *s2)
299 apr_int64_t i1 = apr_atoi64(s1);
300 apr_int64_t i2 = apr_atoi64(s2);
310 static const char *ap_expr_regexec(const char *subject,
311 const ap_expr_t *reg,
312 apr_array_header_t *list,
313 ap_expr_eval_ctx_t *ctx)
316 const char *val = subject;
317 const ap_regex_t *regex = reg->node_arg1;
318 const ap_expr_regctx_t *regctx = reg->node_arg2;
319 ap_regmatch_t *pmatch = NULL, match0;
320 apr_size_t nmatch = 0;
321 const char *str = "";
325 ap_varbuf_init(ctx->p, &vb, 0);
326 if (ctx->re_nmatch > 0) {
327 nmatch = ctx->re_nmatch;
328 pmatch = ctx->re_pmatch;
330 else if (regctx->subst) {
335 /* If previous match was empty, we can't issue the exact same one or
336 * we'd loop indefinitively. So let's instead ask for an anchored and
337 * non-empty match (i.e. something not empty at the start of the value)
338 * and if nothing is found advance by one character below.
340 rv = ap_regexec(regex, val, nmatch, pmatch,
341 empty ? AP_REG_ANCHORED | AP_REG_NOTEMPTY : 0);
343 int pos = pmatch[0].rm_so,
344 end = pmatch[0].rm_eo;
345 AP_DEBUG_ASSERT(pos >= 0 && pos <= end);
348 *ctx->re_source = val;
349 str = ap_expr_eval_word(ctx, regctx->subst);
353 char *tmp = apr_palloc(ctx->p, pos + len + 1);
354 memcpy(tmp, val, pos);
355 memcpy(tmp + pos, str, len + 1);
356 APR_ARRAY_PUSH(list, const char*) = tmp;
359 ap_varbuf_grow(&vb, pos + len + 1);
360 ap_varbuf_strmemcat(&vb, val, pos);
361 ap_varbuf_strmemcat(&vb, str, len);
362 if (!(regctx->flags & AP_REG_MULTI)) {
363 /* Single substitution, preserve remaining data */
364 ap_varbuf_strmemcat(&vb, val + end, strlen(val) - end);
368 /* Note an empty match */
373 /* Skip this non-matching character (or full CRLF) and restart
374 * another "normal" match (possibly empty) from there.
376 if (val[0] == '\r' && val[1] == '\n') {
386 APR_ARRAY_PUSH(list, const char*) = val;
389 ap_varbuf_strmemcat(&vb, val, strlen(val));
401 static apr_array_header_t *ap_expr_list_make(ap_expr_eval_ctx_t *ctx,
402 const ap_expr_t *node)
404 apr_array_header_t *list = NULL;
406 if (node->node_op == op_Split) {
407 const ap_expr_t *arg = node->node_arg1;
408 const ap_expr_t *reg = node->node_arg2;
409 const apr_array_header_t *source = ap_expr_list_make(ctx, arg);
412 list = apr_array_make(ctx->p, source->nelts, sizeof(const char*));
413 for (i = 0; i < source->nelts; ++i) {
414 const char *val = APR_ARRAY_IDX(source, i, const char*);
415 (void)ap_expr_regexec(val, reg, list, ctx);
418 else if (node->node_op == op_ListElement) {
420 const ap_expr_t *elem;
421 for (elem = node; elem; elem = elem->node_arg2) {
422 AP_DEBUG_ASSERT(elem->node_op == op_ListElement);
426 list = apr_array_make(ctx->p, n, sizeof(const char*));
427 for (elem = node; elem; elem = elem->node_arg2) {
428 APR_ARRAY_PUSH(list, const char*) =
429 ap_expr_eval_word(ctx, elem->node_arg1);
432 else if (node->node_op == op_ListFuncCall) {
433 const ap_expr_t *info = node->node_arg1;
434 ap_expr_list_func_t *func = info->node_arg1;
436 AP_DEBUG_ASSERT(func != NULL);
437 AP_DEBUG_ASSERT(info->node_op == op_ListFuncInfo);
438 list = (*func)(ctx, info->node_arg2,
439 ap_expr_eval_word(ctx, node->node_arg2));
442 list = apr_array_make(ctx->p, 1, sizeof(const char*));
443 APR_ARRAY_PUSH(list, const char*) = ap_expr_eval_word(ctx, node);
449 static int ap_expr_eval_comp(ap_expr_eval_ctx_t *ctx, const ap_expr_t *node)
451 const ap_expr_t *e1 = node->node_arg1;
452 const ap_expr_t *e2 = node->node_arg2;
453 switch (node->node_op) {
455 return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) == 0);
457 return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) != 0);
459 return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) < 0);
461 return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <= 0);
463 return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) > 0);
465 return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >= 0);
467 return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) == 0);
469 return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) != 0);
471 return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) < 0);
473 return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <= 0);
475 return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) > 0);
477 return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >= 0);
480 const char *needle, *subject;
481 apr_array_header_t *haystack;
482 haystack = ap_expr_list_make(ctx, e2);
484 needle = ap_expr_eval_word(ctx, e1);
485 for (n = 0; n < haystack->nelts; ++n) {
486 subject = APR_ARRAY_IDX(haystack, n, const char*);
487 if (strcmp(needle, subject) == 0) {
496 const char *word = ap_expr_eval_word(ctx, e1);
497 const ap_regex_t *regex = e2->node_arg1;
501 * $0 ... $9 may contain stuff the user wants to keep. Therefore
502 * we only set them if there are capturing parens in the regex.
504 if (regex->re_nsub > 0) {
505 result = (0 == ap_regexec(regex, word, ctx->re_nmatch,
507 *ctx->re_source = result ? word : NULL;
510 result = (0 == ap_regexec(regex, word, 0, NULL, 0));
513 return result ^ (node->node_op == op_NRE);
516 *ctx->err = "Internal evaluation error: Unknown comp expression node";
521 /* combined string/int comparison for compatibility with ssl_expr */
522 static int strcmplex(const char *str1, const char *str2)
536 for (i = 0; i < n1; i++) {
537 if (str1[i] > str2[i])
539 if (str1[i] < str2[i])
545 static int ssl_expr_eval_comp(ap_expr_eval_ctx_t *ctx, const ap_expr_t *node)
547 const ap_expr_t *e1 = node->node_arg1;
548 const ap_expr_t *e2 = node->node_arg2;
549 switch (node->node_op) {
552 return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) == 0);
555 return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) != 0);
558 return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) < 0);
561 return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <= 0);
564 return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) > 0);
567 return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >= 0);
569 return ap_expr_eval_comp(ctx, node);
573 AP_DECLARE_NONSTD(int) ap_expr_lookup_default(ap_expr_lookup_parms *parms)
575 return ap_run_expr_lookup(parms);
578 AP_DECLARE(const char *) ap_expr_parse(apr_pool_t *pool, apr_pool_t *ptemp,
579 ap_expr_info_t *info, const char *expr,
580 ap_expr_lookup_fn_t *lookup_fn)
582 ap_expr_parse_ctx_t ctx;
585 memset(&ctx, 0, sizeof ctx);
589 ctx.inputlen = strlen(expr);
590 ctx.inputptr = ctx.inputbuf;
591 ctx.flags = info->flags;
592 ctx.lookup_fn = lookup_fn ? lookup_fn : ap_expr_lookup_default;
595 ap_expr_yylex_init(&ctx.scanner);
596 ap_expr_yyset_extra(&ctx, ctx.scanner);
597 rc = ap_expr_yyparse(&ctx);
598 ap_expr_yylex_destroy(ctx.scanner);
600 /* ctx.error: the generic bison error message
601 * (XXX: usually not very useful, should be axed)
602 * ctx.error2: an additional error message
606 return apr_psprintf(pool, "%s: %s", ctx.error, ctx.error2);
610 else if (ctx.error2) {
614 if (rc) /* XXX can this happen? */
615 return "syntax error";
619 expr_dump_tree(ctx.expr, NULL, APLOG_NOTICE, 2);
622 info->root_node = ctx.expr;
627 AP_DECLARE(ap_expr_info_t*) ap_expr_parse_cmd_mi(const cmd_parms *cmd,
631 ap_expr_lookup_fn_t *lookup_fn,
634 ap_expr_info_t *info = apr_pcalloc(cmd->pool, sizeof(ap_expr_info_t));
635 info->filename = cmd->directive->filename;
636 info->line_number = cmd->directive->line_num;
638 info->module_index = module_index;
639 *err = ap_expr_parse(cmd->pool, cmd->temp_pool, info, expr, lookup_fn);
647 ap_expr_t *ap_expr_make(ap_expr_node_op_e op, const void *a1, const void *a2,
648 ap_expr_parse_ctx_t *ctx)
650 ap_expr_t *node = apr_palloc(ctx->pool, sizeof(ap_expr_t));
652 node->node_arg1 = a1;
653 node->node_arg2 = a2;
657 ap_expr_t *ap_expr_concat_make(const void *a1, const void *a2,
658 ap_expr_parse_ctx_t *ctx)
660 const ap_expr_t *node;
662 /* Optimize out empty string(s) concatenation */
664 && node->node_op == op_String
665 && !*(const char *)node->node_arg1) {
666 return (ap_expr_t *)a2;
669 && node->node_op == op_String
670 && !*(const char *)node->node_arg1) {
671 return (ap_expr_t *)a1;
674 return ap_expr_make(op_Concat, a1, a2, ctx);
677 ap_expr_t *ap_expr_regex_make(const char *pattern, const ap_expr_t *subst,
678 const char *flags, ap_expr_parse_ctx_t *ctx)
680 ap_expr_t *node = NULL;
681 ap_expr_regctx_t *regctx;
684 regctx = apr_pcalloc(ctx->pool, sizeof *regctx);
685 regctx->subst = subst;
687 for (; *flags; ++flags) {
690 regctx->flags |= AP_REG_ICASE;
693 regctx->flags |= AP_REG_NEWLINE;
696 regctx->flags |= AP_REG_DOTALL;
699 regctx->flags |= AP_REG_MULTI;
704 regex = ap_pregcomp(ctx->pool, pattern, regctx->flags);
709 node = apr_palloc(ctx->pool, sizeof(ap_expr_t));
710 node->node_op = op_Regex;
711 node->node_arg1 = regex;
712 node->node_arg2 = regctx;
716 static ap_expr_t *ap_expr_info_make(int type, const char *name,
717 ap_expr_parse_ctx_t *ctx,
718 const ap_expr_t *arg)
720 ap_expr_t *info = apr_palloc(ctx->pool, sizeof(ap_expr_t));
721 ap_expr_lookup_parms parms;
723 parms.flags = ctx->flags;
724 parms.pool = ctx->pool;
725 parms.ptemp = ctx->ptemp;
727 parms.func = &info->node_arg1;
728 parms.data = &info->node_arg2;
729 parms.err = &ctx->error2;
732 switch(arg->node_op) {
734 parms.arg = arg->node_arg1;
738 const ap_expr_t *val = arg->node_arg1;
739 if (val->node_op == op_String) {
740 parms.arg = val->node_arg1;
742 arg = arg->node_arg2;
743 } while (arg != NULL);
749 if (ctx->lookup_fn(&parms) != OK)
754 ap_expr_t *ap_expr_str_func_make(const char *name, const ap_expr_t *arg,
755 ap_expr_parse_ctx_t *ctx)
757 ap_expr_t *info = ap_expr_info_make(AP_EXPR_FUNC_STRING, name, ctx, arg);
761 info->node_op = op_StringFuncInfo;
762 return ap_expr_make(op_StringFuncCall, info, arg, ctx);
765 ap_expr_t *ap_expr_list_func_make(const char *name, const ap_expr_t *arg,
766 ap_expr_parse_ctx_t *ctx)
768 ap_expr_t *info = ap_expr_info_make(AP_EXPR_FUNC_LIST, name, ctx, arg);
772 info->node_op = op_ListFuncInfo;
773 return ap_expr_make(op_ListFuncCall, info, arg, ctx);
776 ap_expr_t *ap_expr_unary_op_make(const char *name, const ap_expr_t *arg,
777 ap_expr_parse_ctx_t *ctx)
779 ap_expr_t *info = ap_expr_info_make(AP_EXPR_FUNC_OP_UNARY, name, ctx, arg);
783 info->node_op = op_UnaryOpInfo;
784 return ap_expr_make(op_UnaryOpCall, info, arg, ctx);
787 ap_expr_t *ap_expr_binary_op_make(const char *name, const ap_expr_t *arg1,
788 const ap_expr_t *arg2, ap_expr_parse_ctx_t *ctx)
791 ap_expr_t *info = ap_expr_info_make(AP_EXPR_FUNC_OP_BINARY, name, ctx,
796 info->node_op = op_BinaryOpInfo;
797 args = ap_expr_make(op_BinaryOpArgs, arg1, arg2, ctx);
798 return ap_expr_make(op_BinaryOpCall, info, args, ctx);
802 ap_expr_t *ap_expr_var_make(const char *name, ap_expr_parse_ctx_t *ctx)
804 ap_expr_t *node = ap_expr_info_make(AP_EXPR_FUNC_VAR, name, ctx, NULL);
808 node->node_op = op_Var;
812 ap_expr_t *ap_expr_backref_make(int num, ap_expr_parse_ctx_t *ctx)
814 int *n = apr_pmemdup(ctx->pool, &num, sizeof(num));
815 return ap_expr_make(op_Backref, n, NULL, ctx);
820 #define MARK APLOG_MARK,loglevel,0,s
821 #define DUMP_E_E(op, e1, e2) \
822 do { ap_log_error(MARK,"%*s%s: %pp %pp", indent, " ", op, e1, e2); \
823 if (e1) expr_dump_tree(e1, s, loglevel, indent + 2); \
824 if (e2) expr_dump_tree(e2, s, loglevel, indent + 2); \
826 #define DUMP_S_E(op, s1, e1) \
827 do { ap_log_error(MARK,"%*s%s: '%s' %pp", indent, " ", op, (char *)s1, e1); \
828 if (e1) expr_dump_tree(e1, s, loglevel, indent + 2); \
830 #define DUMP_S_P(op, s1, p1) \
831 ap_log_error(MARK,"%*s%s: '%s' %pp", indent, " ", op, (char *)s1, p1);
832 #define DUMP_P_P(op, p1, p2) \
833 ap_log_error(MARK,"%*s%s: %pp %pp", indent, " ", op, p1, p2);
834 #define DUMP_S_S(op, s1, s2) \
835 ap_log_error(MARK,"%*s%s: '%s' '%s'", indent, " ", op, (char *)s1, (char *)s2)
836 #define DUMP_P(op, p1) \
837 ap_log_error(MARK,"%*s%s: %pp", indent, " ", op, p1);
838 #define DUMP_IP(op, p1) \
839 ap_log_error(MARK,"%*s%s: %d", indent, " ", op, *(int *)p1);
840 #define DUMP_S(op, s1) \
841 ap_log_error(MARK,"%*s%s: '%s'", indent, " ", op, (char *)s1)
843 #define CASE_OP(op) case op: name = #op ; break;
845 static void expr_dump_tree(const ap_expr_t *e, const server_rec *s,
846 int loglevel, int indent)
848 switch (e->node_op) {
855 switch (e->node_op) {
862 ap_log_error(MARK, "%*s%s", indent, " ", name);
866 /* arg1: string, arg2: expr */
868 case op_BinaryOpCall:
869 case op_BinaryOpArgs:
872 switch (e->node_op) {
873 CASE_OP(op_BinaryOpCall);
874 CASE_OP(op_UnaryOpCall);
875 CASE_OP(op_BinaryOpArgs);
879 DUMP_S_E(name, e->node_arg1, e->node_arg2);
883 /* arg1: expr, arg2: expr */
909 case op_StringFuncCall:
910 case op_ListFuncCall:
914 switch (e->node_op) {
940 CASE_OP(op_StringFuncCall);
941 CASE_OP(op_ListFuncCall);
942 CASE_OP(op_ListElement);
946 DUMP_E_E(name, e->node_arg1, e->node_arg2);
954 switch (e->node_op) {
960 DUMP_S(name, e->node_arg1);
963 /* arg1: pointer, arg2: pointer */
965 case op_StringFuncInfo:
967 case op_BinaryOpInfo:
968 case op_ListFuncInfo:
971 switch (e->node_op) {
973 CASE_OP(op_StringFuncInfo);
974 CASE_OP(op_UnaryOpInfo);
975 CASE_OP(op_BinaryOpInfo);
976 CASE_OP(op_ListFuncInfo);
980 DUMP_P_P(name, e->node_arg1, e->node_arg2);
985 DUMP_P("op_Regex", e->node_arg1);
987 /* arg1: pointer to int */
989 DUMP_IP("op_Backref", e->node_arg1);
992 ap_log_error(MARK, "%*sERROR: INVALID OP %d", indent, " ", e->node_op);
996 #endif /* AP_EXPR_DEBUG */
998 static int ap_expr_eval_unary_op(ap_expr_eval_ctx_t *ctx, const ap_expr_t *info,
999 const ap_expr_t *arg)
1001 ap_expr_op_unary_t *op_func = (ap_expr_op_unary_t *)info->node_arg1;
1002 const void *data = info->node_arg2;
1004 AP_DEBUG_ASSERT(info->node_op == op_UnaryOpInfo);
1005 AP_DEBUG_ASSERT(op_func != NULL);
1006 AP_DEBUG_ASSERT(data != NULL);
1007 return (*op_func)(ctx, data, ap_expr_eval_word(ctx, arg));
1010 static int ap_expr_eval_binary_op(ap_expr_eval_ctx_t *ctx,
1011 const ap_expr_t *info,
1012 const ap_expr_t *args)
1014 ap_expr_op_binary_t *op_func = (ap_expr_op_binary_t *)info->node_arg1;
1015 const void *data = info->node_arg2;
1016 const ap_expr_t *a1 = args->node_arg1;
1017 const ap_expr_t *a2 = args->node_arg2;
1019 AP_DEBUG_ASSERT(info->node_op == op_BinaryOpInfo);
1020 AP_DEBUG_ASSERT(args->node_op == op_BinaryOpArgs);
1021 AP_DEBUG_ASSERT(op_func != NULL);
1022 AP_DEBUG_ASSERT(data != NULL);
1023 return (*op_func)(ctx, data, ap_expr_eval_word(ctx, a1),
1024 ap_expr_eval_word(ctx, a2));
1028 static int ap_expr_eval_cond(ap_expr_eval_ctx_t *ctx, const ap_expr_t *node)
1030 const ap_expr_t *e1 = node->node_arg1;
1031 const ap_expr_t *e2 = node->node_arg2;
1036 switch (node->node_op) {
1049 if (e1->node_op == op_Not) {
1050 if (!ap_expr_eval_cond(ctx, e1->node_arg1)) {
1056 if (ap_expr_eval_cond(ctx, e1)) {
1061 node = node->node_arg2;
1062 e1 = node->node_arg1;
1063 } while (node->node_op == op_Or);
1067 if (e1->node_op == op_Not) {
1068 if (ap_expr_eval_cond(ctx, e1->node_arg1)) {
1074 if (!ap_expr_eval_cond(ctx, e1)) {
1079 node = node->node_arg2;
1080 e1 = node->node_arg1;
1081 } while (node->node_op == op_And);
1083 case op_UnaryOpCall:
1084 result ^= ap_expr_eval_unary_op(ctx, e1, e2);
1086 case op_BinaryOpCall:
1087 result ^= ap_expr_eval_binary_op(ctx, e1, e2);
1090 if (ctx->info->flags & AP_EXPR_FLAG_SSL_EXPR_COMPAT)
1091 result ^= ssl_expr_eval_comp(ctx, e1);
1093 result ^= ap_expr_eval_comp(ctx, e1);
1096 *ctx->err = "Internal evaluation error: Unknown expression node";
1099 e1 = node->node_arg1;
1100 e2 = node->node_arg2;
1107 AP_DECLARE(int) ap_expr_exec(request_rec *r, const ap_expr_info_t *info,
1110 return ap_expr_exec_re(r, info, 0, NULL, NULL, err);
1113 AP_DECLARE(int) ap_expr_exec_ctx(ap_expr_eval_ctx_t *ctx)
1117 AP_DEBUG_ASSERT(ctx->p != NULL);
1118 /* XXX: allow r, c == NULL */
1119 AP_DEBUG_ASSERT(ctx->r != NULL);
1120 AP_DEBUG_ASSERT(ctx->c != NULL);
1121 AP_DEBUG_ASSERT(ctx->s != NULL);
1122 AP_DEBUG_ASSERT(ctx->err != NULL);
1123 AP_DEBUG_ASSERT(ctx->info != NULL);
1124 if (ctx->re_pmatch) {
1125 AP_DEBUG_ASSERT(ctx->re_source != NULL);
1126 AP_DEBUG_ASSERT(ctx->re_nmatch > 0);
1131 if (ctx->info->flags & AP_EXPR_FLAG_STRING_RESULT) {
1132 *ctx->result_string = ap_expr_eval_word(ctx, ctx->info->root_node);
1133 if (*ctx->err != NULL) {
1134 ap_log_rerror(LOG_MARK(ctx->info), APLOG_ERR, 0, ctx->r,
1136 "Evaluation of string expression from %s:%d failed: %s",
1137 ctx->info->filename, ctx->info->line_number, *ctx->err);
1140 ap_log_rerror(LOG_MARK(ctx->info), APLOG_TRACE4, 0, ctx->r,
1141 "Evaluation of string expression from %s:%d gave: %s",
1142 ctx->info->filename, ctx->info->line_number,
1143 *ctx->result_string);
1148 rc = ap_expr_eval_cond(ctx, ctx->info->root_node);
1149 if (*ctx->err != NULL) {
1150 ap_log_rerror(LOG_MARK(ctx->info), APLOG_ERR, 0, ctx->r,
1152 "Evaluation of expression from %s:%d failed: %s",
1153 ctx->info->filename, ctx->info->line_number, *ctx->err);
1157 ap_log_rerror(LOG_MARK(ctx->info), APLOG_TRACE4, 0, ctx->r,
1158 "Evaluation of expression from %s:%d gave: %d",
1159 ctx->info->filename, ctx->info->line_number, rc);
1161 if (ctx->vary_this && *ctx->vary_this)
1162 apr_table_merge(ctx->r->headers_out, "Vary", *ctx->vary_this);
1169 AP_DECLARE(int) ap_expr_exec_re(request_rec *r, const ap_expr_info_t *info,
1170 apr_size_t nmatch, ap_regmatch_t *pmatch,
1171 const char **source, const char **err)
1173 ap_expr_eval_ctx_t ctx;
1174 int dont_vary = (info->flags & AP_EXPR_FLAG_DONT_VARY);
1175 const char *tmp_source = NULL, *vary_this = NULL;
1176 ap_regmatch_t tmp_pmatch[AP_MAX_REG_MATCH];
1178 AP_DEBUG_ASSERT((info->flags & AP_EXPR_FLAG_STRING_RESULT) == 0);
1181 ctx.c = r->connection;
1186 ctx.re_nmatch = nmatch;
1187 ctx.re_pmatch = pmatch;
1188 ctx.re_source = source;
1189 ctx.vary_this = dont_vary ? NULL : &vary_this;
1193 ctx.re_nmatch = AP_MAX_REG_MATCH;
1194 ctx.re_pmatch = tmp_pmatch;
1195 ctx.re_source = &tmp_source;
1198 return ap_expr_exec_ctx(&ctx);
1201 AP_DECLARE(const char *) ap_expr_str_exec_re(request_rec *r,
1202 const ap_expr_info_t *info,
1204 ap_regmatch_t *pmatch,
1205 const char **source,
1208 ap_expr_eval_ctx_t ctx;
1210 const char *tmp_source, *vary_this;
1211 ap_regmatch_t tmp_pmatch[AP_MAX_REG_MATCH];
1214 AP_DEBUG_ASSERT(info->flags & AP_EXPR_FLAG_STRING_RESULT);
1216 if (info->root_node->node_op == op_String) {
1217 /* short-cut for constant strings */
1219 return (const char *)info->root_node->node_arg1;
1225 dont_vary = (info->flags & AP_EXPR_FLAG_DONT_VARY);
1228 ctx.c = r->connection;
1233 ctx.re_nmatch = nmatch;
1234 ctx.re_pmatch = pmatch;
1235 ctx.re_source = source;
1236 ctx.vary_this = dont_vary ? NULL : &vary_this;
1238 ctx.result_string = &result;
1241 ctx.re_nmatch = AP_MAX_REG_MATCH;
1242 ctx.re_pmatch = tmp_pmatch;
1243 ctx.re_source = &tmp_source;
1246 rc = ap_expr_exec_ctx(&ctx);
1257 AP_DECLARE(const char *) ap_expr_str_exec(request_rec *r,
1258 const ap_expr_info_t *info,
1261 return ap_expr_str_exec_re(r, info, 0, NULL, NULL, err);
1265 static void add_vary(ap_expr_eval_ctx_t *ctx, const char *name)
1267 if (!ctx->vary_this)
1270 if (*ctx->vary_this) {
1271 *ctx->vary_this = apr_pstrcat(ctx->p, *ctx->vary_this, ", ", name,
1275 *ctx->vary_this = name;
1279 static const char *req_table_func(ap_expr_eval_ctx_t *ctx, const void *data,
1282 const char *name = (const char *)data;
1287 if (name[2] == 's') { /* resp */
1288 /* Try r->headers_out first, fall back on err_headers_out. */
1289 const char *v = apr_table_get(ctx->r->headers_out, arg);
1293 t = ctx->r->err_headers_out;
1295 else if (name[0] == 'n') /* notes */
1297 else if (name[3] == 'e') /* reqenv */
1298 t = ctx->r->subprocess_env;
1299 else if (name[3] == '_') /* req_novary */
1300 t = ctx->r->headers_in;
1301 else { /* req, http */
1302 t = ctx->r->headers_in;
1303 /* Skip the 'Vary: Host' header combination
1304 * as indicated in rfc7231 section-7.1.4
1306 if (strcasecmp(arg, "Host")){
1310 return apr_table_get(t, arg);
1313 static const char *env_func(ap_expr_eval_ctx_t *ctx, const void *data,
1317 /* this order is for ssl_expr compatibility */
1319 if ((res = apr_table_get(ctx->r->notes, arg)) != NULL)
1321 else if ((res = apr_table_get(ctx->r->subprocess_env, arg)) != NULL)
1327 static const char *osenv_func(ap_expr_eval_ctx_t *ctx, const void *data,
1333 static const char *tolower_func(ap_expr_eval_ctx_t *ctx, const void *data,
1336 char *result = apr_pstrdup(ctx->p, arg);
1337 ap_str_tolower(result);
1341 static const char *toupper_func(ap_expr_eval_ctx_t *ctx, const void *data,
1344 char *result = apr_pstrdup(ctx->p, arg);
1345 ap_str_toupper(result);
1349 static const char *escape_func(ap_expr_eval_ctx_t *ctx, const void *data,
1352 return ap_escape_uri(ctx->p, arg);
1355 static const char *base64_func(ap_expr_eval_ctx_t *ctx, const void *data,
1358 return ap_pbase64encode(ctx->p, (char *)arg);
1361 static const char *unbase64_func(ap_expr_eval_ctx_t *ctx, const void *data,
1364 return ap_pbase64decode(ctx->p, arg);
1367 static const char *sha1_func(ap_expr_eval_ctx_t *ctx, const void *data,
1370 apr_sha1_ctx_t context;
1371 apr_byte_t sha1[APR_SHA1_DIGESTSIZE];
1374 out = apr_palloc(ctx->p, APR_SHA1_DIGESTSIZE*2+1);
1376 apr_sha1_init(&context);
1377 apr_sha1_update(&context, arg, strlen(arg));
1378 apr_sha1_final(sha1, &context);
1380 ap_bin2hex(sha1, APR_SHA1_DIGESTSIZE, out);
1385 static const char *md5_func(ap_expr_eval_ctx_t *ctx, const void *data,
1388 return ap_md5(ctx->p, (const unsigned char *)arg);
1391 #if APR_VERSION_AT_LEAST(1,6,0)
1392 static const char *ldap_func(ap_expr_eval_ctx_t *ctx, const void *data,
1395 return apr_pescape_ldap(ctx->p, arg, APR_ESCAPE_STRING, APR_ESCAPE_LDAP_ALL);
1399 static int replace_func_parse_arg(ap_expr_lookup_parms *parms)
1401 const char *original = parms->arg;
1402 const apr_strmatch_pattern *pattern;
1405 *parms->err = apr_psprintf(parms->ptemp, "replace() function needs "
1406 "exactly 3 arguments");
1409 pattern = apr_strmatch_precompile(parms->pool, original, 0);
1410 *parms->data = pattern;
1414 static const char *replace_func(ap_expr_eval_ctx_t *ctx, const void *data,
1415 const apr_array_header_t *args)
1417 char *buff, *original, *replacement;
1418 struct ap_varbuf vb;
1419 apr_size_t repl_len, orig_len;
1423 const apr_strmatch_pattern *pattern = data;
1424 if (args->nelts != 3) {
1425 *ctx->err = apr_psprintf(ctx->p, "replace() function needs "
1426 "exactly 3 arguments");
1430 buff = APR_ARRAY_IDX(args, 2, char *);
1431 original = APR_ARRAY_IDX(args, 1, char *);
1432 replacement = APR_ARRAY_IDX(args, 0, char *);
1433 repl_len = strlen(replacement);
1434 orig_len = strlen(original);
1435 bytes = strlen(buff);
1437 ap_varbuf_init(ctx->p, &vb, 0);
1440 while ((repl = apr_strmatch(pattern, buff, bytes))) {
1441 len = (apr_size_t) (repl - buff);
1442 ap_varbuf_strmemcat(&vb, buff, len);
1443 ap_varbuf_strmemcat(&vb, replacement, repl_len);
1450 return ap_varbuf_pdup(ctx->p, &vb, NULL, 0, buff, bytes, &len);
1453 #define MAX_FILE_SIZE 10*1024*1024
1454 static const char *file_func(ap_expr_eval_ctx_t *ctx, const void *data,
1463 if (apr_file_open(&fp, arg, APR_READ|APR_BUFFERED,
1464 APR_OS_DEFAULT, ctx->p) != APR_SUCCESS) {
1465 *ctx->err = apr_psprintf(ctx->p, "Cannot open file %s", arg);
1468 apr_file_info_get(&finfo, APR_FINFO_SIZE, fp);
1469 if (finfo.size > MAX_FILE_SIZE) {
1470 *ctx->err = apr_psprintf(ctx->p, "File %s too large", arg);
1474 len = (apr_size_t)finfo.size;
1480 if ((buf = (char *)apr_palloc(ctx->p, sizeof(char)*(len+1))) == NULL) {
1481 *ctx->err = "Cannot allocate memory";
1486 apr_file_seek(fp, APR_SET, &offset);
1487 if (apr_file_read(fp, buf, &len) != APR_SUCCESS) {
1488 *ctx->err = apr_psprintf(ctx->p, "Cannot read from file %s", arg);
1498 static const char *filesize_func(ap_expr_eval_ctx_t *ctx, const void *data,
1502 if (apr_stat(&sb, arg, APR_FINFO_MIN, ctx->p) == APR_SUCCESS
1503 && sb.filetype == APR_REG && sb.size > 0)
1504 return apr_psprintf(ctx->p, "%" APR_OFF_T_FMT, sb.size);
1509 static const char *filemod_func(ap_expr_eval_ctx_t *ctx, const void *data,
1513 if (apr_stat(&sb, arg, APR_FINFO_MIN, ctx->p) == APR_SUCCESS
1514 && sb.filetype == APR_REG && sb.mtime > 0)
1515 return apr_psprintf(ctx->p, "%" APR_OFF_T_FMT, (apr_off_t)sb.mtime);
1521 static const char *unescape_func(ap_expr_eval_ctx_t *ctx, const void *data,
1524 char *result = apr_pstrdup(ctx->p, arg);
1525 int ret = ap_unescape_url_keep2f(result, 0);
1528 ap_log_rerror(LOG_MARK(ctx->info), APLOG_DEBUG, 0, ctx->r, APLOGNO(00538)
1529 "%s %% escape in unescape('%s') at %s:%d",
1530 ret == HTTP_BAD_REQUEST ? "Bad" : "Forbidden", arg,
1531 ctx->info->filename, ctx->info->line_number);
1535 static int op_nz(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1537 const char *name = (const char *)data;
1539 return (arg[0] == '\0');
1541 return (arg[0] != '\0');
1544 static int op_file_min(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1547 const char *name = (const char *)data;
1548 if (apr_stat(&sb, arg, APR_FINFO_MIN, ctx->p) != APR_SUCCESS)
1552 return (sb.filetype == APR_DIR);
1556 return (sb.filetype == APR_REG);
1558 return (sb.filetype == APR_REG && sb.size > 0);
1565 static int op_file_link(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1569 if (apr_stat(&sb, arg, APR_FINFO_MIN | APR_FINFO_LINK, ctx->p) == APR_SUCCESS
1570 && sb.filetype == APR_LNK) {
1577 static int op_file_xbit(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1580 if (apr_stat(&sb, arg, APR_FINFO_PROT| APR_FINFO_LINK, ctx->p) == APR_SUCCESS
1581 && (sb.protection & (APR_UEXECUTE | APR_GEXECUTE | APR_WEXECUTE))) {
1587 static int op_url_subr(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1590 request_rec *rsub, *r = ctx->r;
1593 /* avoid some infinite recursions */
1594 if (r->main && r->main->uri && r->uri && strcmp(r->main->uri, r->uri) == 0)
1597 rsub = ap_sub_req_lookup_uri(arg, r, NULL);
1598 if (rsub->status < 400) {
1601 ap_log_rerror(LOG_MARK(ctx->info), APLOG_TRACE5, 0, r,
1602 "Subrequest for -U %s at %s:%d gave status: %d",
1603 arg, ctx->info->filename, ctx->info->line_number,
1605 ap_destroy_sub_req(rsub);
1609 static int op_file_subr(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1613 request_rec *rsub, *r = ctx->r;
1616 rsub = ap_sub_req_lookup_file(arg, r, NULL);
1617 if (rsub->status < 300 &&
1618 /* double-check that file exists since default result is 200 */
1619 apr_stat(&sb, rsub->filename, APR_FINFO_MIN, ctx->p) == APR_SUCCESS) {
1622 ap_log_rerror(LOG_MARK(ctx->info), APLOG_TRACE5, 0, r,
1623 "Subrequest for -F %s at %s:%d gave status: %d",
1624 arg, ctx->info->filename, ctx->info->line_number,
1626 ap_destroy_sub_req(rsub);
1631 APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *));
1632 static APR_OPTIONAL_FN_TYPE(ssl_is_https) *is_https = NULL;
1634 APR_DECLARE_OPTIONAL_FN(int, http2_is_h2, (conn_rec *));
1635 static APR_OPTIONAL_FN_TYPE(http2_is_h2) *is_http2 = NULL;
1637 static const char *conn_var_names[] = {
1640 "CONN_LOG_ID", /* 2 */
1641 "CONN_REMOTE_ADDR", /* 3 */
1646 static const char *conn_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
1648 int index = ((const char **)data - conn_var_names);
1649 conn_rec *c = ctx->c;
1655 if (is_https && is_https(c))
1662 apr_sockaddr_t *addr = c->client_addr;
1663 if (addr->family == AF_INET6
1664 && !IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addr->ipaddr_ptr))
1675 return c->client_ip;
1677 if (is_http2 && is_http2(c))
1687 static const char *request_var_names[] = {
1688 "REQUEST_METHOD", /* 0 */
1689 "REQUEST_SCHEME", /* 1 */
1690 "REQUEST_URI", /* 2 */
1691 "REQUEST_FILENAME", /* 3 */
1692 "REMOTE_HOST", /* 4 */
1693 "REMOTE_IDENT", /* 5 */
1694 "REMOTE_USER", /* 6 */
1695 "SERVER_ADMIN", /* 7 */
1696 "SERVER_NAME", /* 8 */
1697 "SERVER_PORT", /* 9 */
1698 "SERVER_PROTOCOL", /* 10 */
1699 "SCRIPT_FILENAME", /* 11 */
1700 "PATH_INFO", /* 12 */
1701 "QUERY_STRING", /* 13 */
1702 "IS_SUBREQ", /* 14 */
1703 "DOCUMENT_ROOT", /* 15 */
1704 "AUTH_TYPE", /* 16 */
1705 "THE_REQUEST", /* 17 */
1706 "CONTENT_TYPE", /* 18 */
1708 "REQUEST_LOG_ID", /* 20 */
1709 "SCRIPT_USER", /* 21 */
1710 "SCRIPT_GROUP", /* 22 */
1711 "DOCUMENT_URI", /* 23 */
1712 "LAST_MODIFIED", /* 24 */
1713 "CONTEXT_PREFIX", /* 25 */
1714 "CONTEXT_DOCUMENT_ROOT", /* 26 */
1715 "REQUEST_STATUS", /* 27 */
1716 "REMOTE_ADDR", /* 28 */
1717 "SERVER_PROTOCOL_VERSION", /* 29 */
1718 "SERVER_PROTOCOL_VERSION_MAJOR", /* 30 */
1719 "SERVER_PROTOCOL_VERSION_MINOR", /* 31 */
1720 "REMOTE_PORT", /* 32 */
1724 static const char *request_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
1726 int index = ((const char **)data - request_var_names);
1727 request_rec *r = ctx->r;
1735 return ap_http_scheme(r);
1741 return ap_get_useragent_host(r, REMOTE_NAME, NULL);
1743 return ap_get_remote_logname(r);
1747 return r->server->server_admin;
1749 return ap_get_server_name_for_url(r);
1751 return apr_psprintf(ctx->p, "%u", ap_get_server_port(r));
1757 return r->path_info;
1761 return (r->main != NULL ? "true" : "false");
1763 return ap_document_root(r);
1765 return r->ap_auth_type;
1767 return r->the_request;
1769 return r->content_type;
1777 if (r->finfo.valid & APR_FINFO_USER)
1778 apr_uid_name_get(&result, r->finfo.user, ctx->p);
1784 if (r->finfo.valid & APR_FINFO_USER)
1785 apr_gid_name_get(&result, r->finfo.group, ctx->p);
1790 const char *uri = apr_table_get(r->subprocess_env, "DOCUMENT_URI");
1791 return uri ? uri : r->uri;
1796 apr_time_exp_lt(&tm, r->mtime);
1797 return apr_psprintf(ctx->p, "%02d%02d%02d%02d%02d%02d%02d",
1798 (tm.tm_year / 100) + 19, (tm.tm_year % 100),
1799 tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min,
1803 return ap_context_prefix(r);
1805 return ap_context_document_root(r);
1807 return r->status ? apr_psprintf(ctx->p, "%d", r->status) : "";
1809 return r->useragent_ip;
1811 switch (r->proto_num) {
1812 case 1001: return "1001"; /* 1.1 */
1813 case 1000: return "1000"; /* 1.0 */
1814 case 9: return "9"; /* 0.9 */
1816 return apr_psprintf(ctx->p, "%d", r->proto_num);
1818 switch (HTTP_VERSION_MAJOR(r->proto_num)) {
1822 return apr_psprintf(ctx->p, "%d", HTTP_VERSION_MAJOR(r->proto_num));
1824 switch (HTTP_VERSION_MINOR(r->proto_num)) {
1829 return apr_psprintf(ctx->p, "%d", HTTP_VERSION_MINOR(r->proto_num));
1831 return apr_psprintf(ctx->p, "%u", ctx->c->client_addr->port);
1838 static const char *req_header_var_names[] = {
1839 "HTTP_USER_AGENT", /* 0 */
1840 "HTTP_PROXY_CONNECTION", /* 1 */
1841 "HTTP_REFERER", /* 2 */
1842 "HTTP_COOKIE", /* 3 */
1843 "HTTP_FORWARDED", /* 4 */
1844 "HTTP_HOST", /* 5 */
1845 "HTTP_ACCEPT", /* 6 */
1849 static const char *req_header_header_names[] = {
1859 static const char *req_header_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
1861 const char **varname = (const char **)data;
1862 int index = (varname - req_header_var_names);
1865 AP_DEBUG_ASSERT(index < 7);
1869 name = req_header_header_names[index];
1870 /* Skip the 'Vary: Host' header combination
1871 * as indicated in rfc7231 section-7.1.4
1873 if (strcasecmp(name, "Host")){
1874 add_vary(ctx, name);
1876 return apr_table_get(ctx->r->headers_in, name);
1879 static const char *misc_var_names[] = {
1880 "TIME_YEAR", /* 0 */
1883 "TIME_HOUR", /* 3 */
1886 "TIME_WDAY", /* 6 */
1888 "SERVER_SOFTWARE", /* 8 */
1889 "API_VERSION", /* 9 */
1893 static const char *misc_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
1896 int index = ((const char **)data - misc_var_names);
1897 apr_time_exp_lt(&tm, apr_time_now());
1901 return apr_psprintf(ctx->p, "%02d%02d", (tm.tm_year / 100) + 19,
1904 return apr_psprintf(ctx->p, "%02d", tm.tm_mon+1);
1906 return apr_psprintf(ctx->p, "%02d", tm.tm_mday);
1908 return apr_psprintf(ctx->p, "%02d", tm.tm_hour);
1910 return apr_psprintf(ctx->p, "%02d", tm.tm_min);
1912 return apr_psprintf(ctx->p, "%02d", tm.tm_sec);
1914 return apr_psprintf(ctx->p, "%d", tm.tm_wday);
1916 return apr_psprintf(ctx->p, "%02d%02d%02d%02d%02d%02d%02d",
1917 (tm.tm_year / 100) + 19, (tm.tm_year % 100),
1918 tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min,
1921 return ap_get_server_banner();
1923 return apr_itoa(ctx->p, MODULE_MAGIC_NUMBER_MAJOR);
1931 static int subnet_parse_arg(ap_expr_lookup_parms *parms)
1933 apr_ipsubnet_t *subnet;
1934 const char *addr = parms->arg;
1939 *parms->err = apr_psprintf(parms->ptemp,
1940 "-%s requires subnet/netmask as constant argument",
1945 mask = ap_strchr_c(addr, '/');
1947 addr = apr_pstrmemdup(parms->ptemp, addr, mask - addr);
1951 ret = apr_ipsubnet_create(&subnet, addr, mask, parms->pool);
1952 if (ret != APR_SUCCESS) {
1953 *parms->err = "parsing of subnet/netmask failed";
1957 *parms->data = subnet;
1961 static int op_ipmatch(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg1,
1964 apr_ipsubnet_t *subnet = (apr_ipsubnet_t *)data;
1965 apr_sockaddr_t *saddr;
1967 AP_DEBUG_ASSERT(subnet != NULL);
1969 /* maybe log an error if this goes wrong? */
1970 if (apr_sockaddr_info_get(&saddr, arg1, APR_UNSPEC, 0, 0, ctx->p) != APR_SUCCESS)
1973 return apr_ipsubnet_test(subnet, saddr);
1976 static int op_R(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg1)
1978 apr_ipsubnet_t *subnet = (apr_ipsubnet_t *)data;
1980 AP_DEBUG_ASSERT(subnet != NULL);
1985 return apr_ipsubnet_test(subnet, ctx->r->useragent_addr);
1988 static int op_T(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1995 return strcasecmp(arg, "off") == 0 ? FALSE : TRUE;
1998 return strcasecmp(arg, "no") == 0 ? FALSE : TRUE;
2001 return strcasecmp(arg, "false") == 0 ? FALSE : TRUE;
2003 return arg[1] == '\0' ? FALSE : TRUE;
2009 static int op_fnmatch(ap_expr_eval_ctx_t *ctx, const void *data,
2010 const char *arg1, const char *arg2)
2012 return (APR_SUCCESS == apr_fnmatch(arg2, arg1, APR_FNM_PATHNAME));
2015 static int op_strmatch(ap_expr_eval_ctx_t *ctx, const void *data,
2016 const char *arg1, const char *arg2)
2018 return (APR_SUCCESS == apr_fnmatch(arg2, arg1, 0));
2021 static int op_strcmatch(ap_expr_eval_ctx_t *ctx, const void *data,
2022 const char *arg1, const char *arg2)
2024 return (APR_SUCCESS == apr_fnmatch(arg2, arg1, APR_FNM_CASE_BLIND));
2027 struct expr_provider_single {
2030 ap_expr_lookup_fn_t *arg_parsing_func;
2034 struct expr_provider_multi {
2039 static const struct expr_provider_multi var_providers[] = {
2040 { misc_var_fn, misc_var_names },
2041 { req_header_var_fn, req_header_var_names },
2042 { request_var_fn, request_var_names },
2043 { conn_var_fn, conn_var_names },
2047 static const struct expr_provider_single string_func_providers[] = {
2048 { osenv_func, "osenv", NULL, 0 },
2049 { env_func, "env", NULL, 0 },
2050 { req_table_func, "resp", NULL, 0 },
2051 { req_table_func, "req", NULL, 0 },
2052 /* 'http' as alias for 'req' for compatibility with ssl_expr */
2053 { req_table_func, "http", NULL, 0 },
2054 { req_table_func, "note", NULL, 0 },
2055 { req_table_func, "reqenv", NULL, 0 },
2056 { req_table_func, "req_novary", NULL, 0 },
2057 { tolower_func, "tolower", NULL, 0 },
2058 { toupper_func, "toupper", NULL, 0 },
2059 { escape_func, "escape", NULL, 0 },
2060 { unescape_func, "unescape", NULL, 0 },
2061 { file_func, "file", NULL, 1 },
2062 { filesize_func, "filesize", NULL, 1 },
2063 { filemod_func, "filemod", NULL, 1 },
2064 { base64_func, "base64", NULL, 0 },
2065 { unbase64_func, "unbase64", NULL, 0 },
2066 { sha1_func, "sha1", NULL, 0 },
2067 { md5_func, "md5", NULL, 0 },
2068 #if APR_VERSION_AT_LEAST(1,6,0)
2069 { ldap_func, "ldap", NULL, 0 },
2071 { replace_func, "replace", replace_func_parse_arg, 0 },
2075 static const struct expr_provider_single unary_op_providers[] = {
2076 { op_nz, "n", NULL, 0 },
2077 { op_nz, "z", NULL, 0 },
2078 { op_R, "R", subnet_parse_arg, 0 },
2079 { op_T, "T", NULL, 0 },
2080 { op_file_min, "d", NULL, 1 },
2081 { op_file_min, "e", NULL, 1 },
2082 { op_file_min, "f", NULL, 1 },
2083 { op_file_min, "s", NULL, 1 },
2084 { op_file_link, "L", NULL, 1 },
2085 { op_file_link, "h", NULL, 1 },
2086 { op_file_xbit, "x", NULL, 1 },
2087 { op_file_subr, "F", NULL, 0 },
2088 { op_url_subr, "U", NULL, 0 },
2089 { op_url_subr, "A", NULL, 0 },
2090 { NULL, NULL, NULL }
2093 static const struct expr_provider_single binary_op_providers[] = {
2094 { op_ipmatch, "ipmatch", subnet_parse_arg, 0 },
2095 { op_fnmatch, "fnmatch", NULL, 0 },
2096 { op_strmatch, "strmatch", NULL, 0 },
2097 { op_strcmatch, "strcmatch", NULL, 0 },
2098 { NULL, NULL, NULL }
2101 static int core_expr_lookup(ap_expr_lookup_parms *parms)
2103 switch (parms->type) {
2104 case AP_EXPR_FUNC_VAR: {
2105 const struct expr_provider_multi *prov = var_providers;
2106 while (prov->func) {
2107 const char **name = prov->names;
2109 if (ap_cstr_casecmp(*name, parms->name) == 0) {
2110 *parms->func = prov->func;
2111 *parms->data = name;
2120 case AP_EXPR_FUNC_STRING:
2121 case AP_EXPR_FUNC_OP_UNARY:
2122 case AP_EXPR_FUNC_OP_BINARY: {
2123 const struct expr_provider_single *prov = NULL;
2124 switch (parms->type) {
2125 case AP_EXPR_FUNC_STRING:
2126 prov = string_func_providers;
2128 case AP_EXPR_FUNC_OP_UNARY:
2129 prov = unary_op_providers;
2131 case AP_EXPR_FUNC_OP_BINARY:
2132 prov = binary_op_providers;
2137 while (prov && prov->func) {
2139 if (parms->type == AP_EXPR_FUNC_OP_UNARY)
2140 match = !strcmp(prov->name, parms->name);
2142 match = !ap_cstr_casecmp(prov->name, parms->name);
2144 if ((parms->flags & AP_EXPR_FLAG_RESTRICTED)
2145 && prov->restricted) {
2147 apr_psprintf(parms->ptemp,
2148 "%s%s not available in restricted context",
2149 (parms->type == AP_EXPR_FUNC_STRING) ? "" : "-",
2153 *parms->func = prov->func;
2154 if (prov->arg_parsing_func) {
2155 return prov->arg_parsing_func(parms);
2158 *parms->data = prov->name;
2172 static int expr_lookup_not_found(ap_expr_lookup_parms *parms)
2175 const char *prefix = "";
2177 switch (parms->type) {
2178 case AP_EXPR_FUNC_VAR:
2181 case AP_EXPR_FUNC_STRING:
2184 case AP_EXPR_FUNC_LIST:
2185 type = "List-returning function";
2187 case AP_EXPR_FUNC_OP_UNARY:
2188 type = "Unary operator";
2190 case AP_EXPR_FUNC_OP_BINARY:
2191 type = "Binary operator";
2194 *parms->err = "Invalid expression type in expr_lookup";
2197 if ( parms->type == AP_EXPR_FUNC_OP_UNARY
2198 || parms->type == AP_EXPR_FUNC_OP_BINARY) {
2201 *parms->err = apr_psprintf(parms->ptemp, "%s '%s%s' does not exist", type,
2202 prefix, parms->name);
2206 static int ap_expr_post_config(apr_pool_t *pconf, apr_pool_t *plog,
2207 apr_pool_t *ptemp, server_rec *s)
2209 is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https);
2210 is_http2 = APR_RETRIEVE_OPTIONAL_FN(http2_is_h2);
2211 apr_pool_cleanup_register(pconf, &is_https, ap_pool_cleanup_set_null,
2212 apr_pool_cleanup_null);
2216 void ap_expr_init(apr_pool_t *p)
2218 ap_hook_expr_lookup(core_expr_lookup, NULL, NULL, APR_HOOK_MIDDLE);
2219 ap_hook_expr_lookup(expr_lookup_not_found, NULL, NULL, APR_HOOK_REALLY_LAST);
2220 ap_hook_post_config(ap_expr_post_config, NULL, NULL, APR_HOOK_MIDDLE);