]> granicus.if.org Git - apache/blob - server/util_expr_eval.c
Explicitly cast function pointer, to remove 'const'.
[apache] / server / util_expr_eval.c
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
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 /*                      _             _
18  *  ap_expr_eval.c, based on ssl_expr_eval.c from mod_ssl
19  */
20
21 #include "httpd.h"
22 #include "http_log.h"
23 #include "http_core.h"
24 #include "http_protocol.h"
25 #include "http_request.h"
26 #include "ap_provider.h"
27 #include "util_expr_private.h"
28
29 #include "apr_lib.h"
30 #include "apr_fnmatch.h"
31
32 #include <limits.h>     /* for INT_MAX */
33
34 /* we know core's module_index is 0 */
35 #undef APLOG_MODULE_INDEX
36 #define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
37
38 APR_HOOK_STRUCT(
39     APR_HOOK_LINK(expr_lookup)
40 )
41
42 AP_IMPLEMENT_HOOK_RUN_FIRST(int, expr_lookup, (ap_expr_lookup_parms *parms),
43                             (parms), DECLINED)
44
45 #define  LOG_MARK(info)  __FILE__, __LINE__, (info)->module_index
46
47 static const char *ap_expr_eval_string_func(ap_expr_eval_ctx_t *ctx,
48                                             const ap_expr_t *info,
49                                             const ap_expr_t *args);
50 static const char *ap_expr_eval_re_backref(ap_expr_eval_ctx_t *ctx,
51                                            unsigned int n);
52 static const char *ap_expr_eval_var(ap_expr_eval_ctx_t *ctx,
53                                     ap_expr_var_func_t *func,
54                                     const void *data);
55
56 /* define AP_EXPR_DEBUG to log the parse tree when parsing an expression */
57 #ifdef AP_EXPR_DEBUG
58 static void expr_dump_tree(const ap_expr_t *e, const server_rec *s,
59                            int loglevel, int indent);
60 #endif
61
62 /*
63  * To reduce counting overhead, we only count calls to
64  * ap_expr_eval_word() and ap_expr_eval(). The max number of
65  * stack frames is larger by some factor.
66  */
67 #define AP_EXPR_MAX_RECURSION   20
68 static int inc_rec(ap_expr_eval_ctx_t *ctx)
69 {
70     if (ctx->reclvl < AP_EXPR_MAX_RECURSION) {
71         ctx->reclvl++;
72         return 0;
73     }
74     *ctx->err = "Recursion limit reached";
75     /* short circuit further evaluation */
76     ctx->reclvl = INT_MAX;
77     return 1;
78 }
79
80 static const char *ap_expr_eval_word(ap_expr_eval_ctx_t *ctx,
81                                      const ap_expr_t *node)
82 {
83     const char *result = "";
84     if (inc_rec(ctx))
85         return result;
86     switch (node->node_op) {
87     case op_Digit:
88     case op_String:
89         result = node->node_arg1;
90         break;
91     case op_Var:
92         result = ap_expr_eval_var(ctx, (ap_expr_var_func_t *)node->node_arg1,
93                                   node->node_arg2);
94         break;
95     case op_Concat:
96         if (((ap_expr_t *)node->node_arg2)->node_op != op_Concat) {
97             const char *s1 = ap_expr_eval_word(ctx, node->node_arg1);
98             const char *s2 = ap_expr_eval_word(ctx, node->node_arg2);
99             if (!*s1)
100                 result = s2;
101             else if (!*s2)
102                 result = s1;
103             else
104                 result = apr_pstrcat(ctx->p, s1, s2, NULL);
105         }
106         else {
107             const ap_expr_t *nodep = node;
108             int i = 1;
109             struct iovec *vec;
110             do {
111                 nodep = nodep->node_arg2;
112                 i++;
113             } while (nodep->node_op == op_Concat);
114             vec = apr_palloc(ctx->p, i * sizeof(struct iovec));
115             nodep = node;
116             i = 0;
117             do {
118                 vec[i].iov_base = (void *)ap_expr_eval_word(ctx,
119                                                             nodep->node_arg1);
120                 vec[i].iov_len = strlen(vec[i].iov_base);
121                 i++;
122                 nodep = nodep->node_arg2;
123             } while (nodep->node_op == op_Concat);
124             vec[i].iov_base = (void *)ap_expr_eval_word(ctx, nodep);
125             vec[i].iov_len = strlen(vec[i].iov_base);
126             i++;
127             result = apr_pstrcatv(ctx->p, vec, i, NULL);
128         }
129         break;
130     case op_StringFuncCall: {
131         const ap_expr_t *info = node->node_arg1;
132         const ap_expr_t *args = node->node_arg2;
133         result = ap_expr_eval_string_func(ctx, info, args);
134         break;
135     }
136     case op_RegexBackref: {
137         const unsigned int *np = node->node_arg1;
138         result = ap_expr_eval_re_backref(ctx, *np);
139         break;
140     }
141     default:
142         *ctx->err = "Internal evaluation error: Unknown word expression node";
143         break;
144     }
145     if (!result)
146         result = "";
147     ctx->reclvl--;
148     return result;
149 }
150
151 static const char *ap_expr_eval_var(ap_expr_eval_ctx_t *ctx,
152                                     ap_expr_var_func_t *func,
153                                     const void *data)
154 {
155     AP_DEBUG_ASSERT(func != NULL);
156     AP_DEBUG_ASSERT(data != NULL);
157     return (*func)(ctx, data);
158 }
159
160 static const char *ap_expr_eval_re_backref(ap_expr_eval_ctx_t *ctx, unsigned int n)
161 {
162     int len;
163
164     if (!ctx->re_pmatch || !ctx->re_source || *ctx->re_source == '\0' ||
165         ctx->re_nmatch < n + 1)
166         return "";
167
168     len = ctx->re_pmatch[n].rm_eo - ctx->re_pmatch[n].rm_so;
169     if (len == 0)
170         return "";
171
172     return apr_pstrndup(ctx->p, *ctx->re_source + ctx->re_pmatch[n].rm_so, len);
173 }
174
175 static const char *ap_expr_eval_string_func(ap_expr_eval_ctx_t *ctx,
176                                             const ap_expr_t *info,
177                                             const ap_expr_t *arg)
178 {
179     ap_expr_string_func_t *func = (ap_expr_string_func_t *)info->node_arg1;
180     const void *data = info->node_arg2;
181
182     AP_DEBUG_ASSERT(info->node_op == op_StringFuncInfo);
183     AP_DEBUG_ASSERT(func != NULL);
184     AP_DEBUG_ASSERT(data != NULL);
185     return (*func)(ctx, data, ap_expr_eval_word(ctx, arg));
186 }
187
188 static int intstrcmp(const char *s1, const char *s2)
189 {
190     apr_int64_t i1 = apr_atoi64(s1);
191     apr_int64_t i2 = apr_atoi64(s2);
192
193     if (i1 < i2)
194         return -1;
195     else if (i1 == i2)
196         return 0;
197     else
198         return 1;
199 }
200
201 static int ap_expr_eval_comp(ap_expr_eval_ctx_t *ctx, const ap_expr_t *node)
202 {
203     const ap_expr_t *e1 = node->node_arg1;
204     const ap_expr_t *e2 = node->node_arg2;
205     switch (node->node_op) {
206     case op_EQ:
207         return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) == 0);
208     case op_NE:
209         return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) != 0);
210     case op_LT:
211         return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <  0);
212     case op_LE:
213         return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <= 0);
214     case op_GT:
215         return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >  0);
216     case op_GE:
217         return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >= 0);
218     case op_STR_EQ:
219         return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) == 0);
220     case op_STR_NE:
221         return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) != 0);
222     case op_STR_LT:
223         return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <  0);
224     case op_STR_LE:
225         return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <= 0);
226     case op_STR_GT:
227         return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >  0);
228     case op_STR_GE:
229         return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >= 0);
230     case op_IN: {
231             const char *needle = ap_expr_eval_word(ctx, e1);
232             if (e2->node_op == op_ListElement) {
233                 do {
234                     const ap_expr_t *val = e2->node_arg1;
235                     AP_DEBUG_ASSERT(e2->node_op == op_ListElement);
236                     if (strcmp(needle, ap_expr_eval_word(ctx, val)) == 0) {
237                         return 1;
238                         break;
239                     }
240                     e2 = e2->node_arg2;
241                 } while (e2 != NULL);
242             }
243             else if (e2->node_op == op_ListFuncCall) {
244                 const ap_expr_t *info = e2->node_arg1;
245                 const ap_expr_t *arg = e2->node_arg2;
246                 ap_expr_list_func_t *func = (ap_expr_list_func_t *)info->node_arg1;
247                 apr_array_header_t *haystack;
248                 int i = 0;
249                 AP_DEBUG_ASSERT(func != NULL);
250                 AP_DEBUG_ASSERT(info->node_op == op_ListFuncInfo);
251                 haystack = (*func)(ctx, info->node_arg2, ap_expr_eval_word(ctx, arg));
252                 if (haystack == NULL)
253                     return 0;
254                 for (; i < haystack->nelts; i++) {
255                     if (strcmp(needle, APR_ARRAY_IDX(haystack,i,char *)) == 0)
256                         return 1;
257                 }
258             }
259             return 0;
260         }
261     case op_REG:
262     case op_NRE: {
263             const char *word = ap_expr_eval_word(ctx, e1);
264             const ap_regex_t *regex = e2->node_arg1;
265             int result;
266
267             /*
268              * $0 ... $9 may contain stuff the user wants to keep. Therefore
269              * we only set them if there are capturing parens in the regex.
270              */
271             if (regex->re_nsub > 0) {
272                 result = (0 == ap_regexec(regex, word, ctx->re_nmatch,
273                                           ctx->re_pmatch, 0));
274                 *ctx->re_source = result ? word : NULL;
275             }
276             else {
277                 result = (0 == ap_regexec(regex, word, 0, NULL, 0));
278             }
279
280             if (node->node_op == op_REG)
281                 return result;
282             else
283                 return !result;
284         }
285     default:
286         *ctx->err = "Internal evaluation error: Unknown comp expression node";
287         return -1;
288     }
289 }
290
291 /* combined string/int comparison for compatibility with ssl_expr */
292 static int strcmplex(const char *str1, const char *str2)
293 {
294     int i, n1, n2;
295
296     if (str1 == NULL)
297         return -1;
298     if (str2 == NULL)
299         return +1;
300     n1 = strlen(str1);
301     n2 = strlen(str2);
302     if (n1 > n2)
303         return 1;
304     if (n1 < n2)
305         return -1;
306     for (i = 0; i < n1; i++) {
307         if (str1[i] > str2[i])
308             return 1;
309         if (str1[i] < str2[i])
310             return -1;
311     }
312     return 0;
313 }
314
315 static int ssl_expr_eval_comp(ap_expr_eval_ctx_t *ctx, const ap_expr_t *node)
316 {
317     const ap_expr_t *e1 = node->node_arg1;
318     const ap_expr_t *e2 = node->node_arg2;
319     switch (node->node_op) {
320     case op_EQ:
321     case op_STR_EQ:
322         return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) == 0);
323     case op_NE:
324     case op_STR_NE:
325         return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) != 0);
326     case op_LT:
327     case op_STR_LT:
328         return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <  0);
329     case op_LE:
330     case op_STR_LE:
331         return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <= 0);
332     case op_GT:
333     case op_STR_GT:
334         return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >  0);
335     case op_GE:
336     case op_STR_GE:
337         return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >= 0);
338     default:
339         return ap_expr_eval_comp(ctx, node);
340     }
341 }
342
343 AP_DECLARE_NONSTD(int) ap_expr_lookup_default(ap_expr_lookup_parms *parms)
344 {
345     return ap_run_expr_lookup(parms);
346 }
347
348 AP_DECLARE(const char *) ap_expr_parse(apr_pool_t *pool, apr_pool_t *ptemp,
349                                        ap_expr_info_t *info, const char *expr,
350                                        ap_expr_lookup_fn_t *lookup_fn)
351 {
352     ap_expr_parse_ctx_t ctx;
353     int rc;
354
355     ctx.pool     = pool;
356     ctx.ptemp    = ptemp;
357     ctx.inputbuf = expr;
358     ctx.inputlen = strlen(expr);
359     ctx.inputptr = ctx.inputbuf;
360     ctx.expr     = NULL;
361     ctx.error    = NULL;        /* generic bison error message (XXX: usually not very useful, should be axed) */
362     ctx.error2   = NULL;        /* additional error message */
363     ctx.flags    = info->flags;
364     ctx.scan_del    = '\0';
365     ctx.scan_buf[0] = '\0';
366     ctx.scan_ptr    = ctx.scan_buf;
367     ctx.lookup_fn   = lookup_fn ? lookup_fn : ap_expr_lookup_default;
368     ctx.at_start    = 1;
369
370     ap_expr_yylex_init(&ctx.scanner);
371     ap_expr_yyset_extra(&ctx, ctx.scanner);
372     rc = ap_expr_yyparse(&ctx);
373     ap_expr_yylex_destroy(ctx.scanner);
374     if (ctx.error) {
375         if (ctx.error2)
376             return apr_psprintf(pool, "%s: %s", ctx.error, ctx.error2);
377         else
378             return ctx.error;
379     }
380     else if (ctx.error2) {
381         return ctx.error2;
382     }
383
384     if (rc) /* XXX can this happen? */
385         return "syntax error";
386
387 #ifdef AP_EXPR_DEBUG
388     if (ctx.expr)
389         expr_dump_tree(ctx.expr, NULL, APLOG_NOTICE, 2);
390 #endif
391
392     info->root_node = ctx.expr;
393
394     return NULL;
395 }
396
397 AP_DECLARE(ap_expr_info_t*) ap_expr_parse_cmd_mi(const cmd_parms *cmd,
398                                                  const char *expr,
399                                                  unsigned int flags,
400                                                  const char **err,
401                                                  ap_expr_lookup_fn_t *lookup_fn,
402                                                  int module_index)
403 {
404     ap_expr_info_t *info = apr_pcalloc(cmd->pool, sizeof(ap_expr_info_t));
405     info->filename = cmd->directive->filename;
406     info->line_number = cmd->directive->line_num;
407     info->flags = flags;
408     info->module_index = module_index;
409     *err = ap_expr_parse(cmd->pool, cmd->temp_pool, info, expr, lookup_fn);
410
411     if (*err)
412         return NULL;
413
414     return info;
415 }
416
417 ap_expr_t *ap_expr_make(ap_expr_node_op_e op, const void *a1, const void *a2,
418                       ap_expr_parse_ctx_t *ctx)
419 {
420     ap_expr_t *node = apr_palloc(ctx->pool, sizeof(ap_expr_t));
421     node->node_op   = op;
422     node->node_arg1 = a1;
423     node->node_arg2 = a2;
424     return node;
425 }
426
427 static ap_expr_t *ap_expr_info_make(int type, const char *name,
428                                   ap_expr_parse_ctx_t *ctx,
429                                   const ap_expr_t *arg)
430 {
431     ap_expr_t *info = apr_palloc(ctx->pool, sizeof(ap_expr_t));
432     ap_expr_lookup_parms parms;
433     parms.type  = type;
434     parms.flags = ctx->flags;
435     parms.pool  = ctx->pool;
436     parms.ptemp = ctx->ptemp;
437     parms.name  = name;
438     parms.func  = &info->node_arg1;
439     parms.data  = &info->node_arg2;
440     parms.err   = &ctx->error2;
441     parms.arg   = (arg && arg->node_op == op_String) ? arg->node_arg1 : NULL;
442     if (ctx->lookup_fn(&parms) != OK)
443         return NULL;
444     return info;
445 }
446
447 ap_expr_t *ap_expr_str_func_make(const char *name, const ap_expr_t *arg,
448                                ap_expr_parse_ctx_t *ctx)
449 {
450     ap_expr_t *info = ap_expr_info_make(AP_EXPR_FUNC_STRING, name, ctx, arg);
451     if (!info)
452         return NULL;
453
454     info->node_op = op_StringFuncInfo;
455     return ap_expr_make(op_StringFuncCall, info, arg, ctx);
456 }
457
458 ap_expr_t *ap_expr_list_func_make(const char *name, const ap_expr_t *arg,
459                                 ap_expr_parse_ctx_t *ctx)
460 {
461     ap_expr_t *info = ap_expr_info_make(AP_EXPR_FUNC_LIST, name, ctx, arg);
462     if (!info)
463         return NULL;
464
465     info->node_op = op_ListFuncInfo;
466     return ap_expr_make(op_ListFuncCall, info, arg, ctx);
467 }
468
469 ap_expr_t *ap_expr_unary_op_make(const char *name, const ap_expr_t *arg,
470                                ap_expr_parse_ctx_t *ctx)
471 {
472     ap_expr_t *info = ap_expr_info_make(AP_EXPR_FUNC_OP_UNARY, name, ctx, arg);
473     if (!info)
474         return NULL;
475
476     info->node_op = op_UnaryOpInfo;
477     return ap_expr_make(op_UnaryOpCall, info, arg, ctx);
478 }
479
480 ap_expr_t *ap_expr_binary_op_make(const char *name, const ap_expr_t *arg1,
481                                 const ap_expr_t *arg2, ap_expr_parse_ctx_t *ctx)
482 {
483     ap_expr_t *args;
484     ap_expr_t *info = ap_expr_info_make(AP_EXPR_FUNC_OP_BINARY, name, ctx,
485                                         arg2);
486     if (!info)
487         return NULL;
488
489     info->node_op = op_BinaryOpInfo;
490     args = ap_expr_make(op_BinaryOpArgs, arg1, arg2, ctx);
491     return ap_expr_make(op_BinaryOpCall, info, args, ctx);
492 }
493
494
495 ap_expr_t *ap_expr_var_make(const char *name, ap_expr_parse_ctx_t *ctx)
496 {
497     ap_expr_t *node = ap_expr_info_make(AP_EXPR_FUNC_VAR, name, ctx, NULL);
498     if (!node)
499         return NULL;
500
501     node->node_op = op_Var;
502     return node;
503 }
504
505 #ifdef AP_EXPR_DEBUG
506
507 #define MARK                        APLOG_MARK,loglevel,0,s
508 #define DUMP_E_E(op, e1, e2)                                                \
509     do { ap_log_error(MARK,"%*s%s: %pp %pp", indent, " ", op, e1, e2);      \
510          if (e1) expr_dump_tree(e1, s, loglevel, indent + 2);               \
511          if (e2) expr_dump_tree(e2, s, loglevel, indent + 2);               \
512     } while (0)
513 #define DUMP_S_E(op, s1, e1)                                                    \
514     do { ap_log_error(MARK,"%*s%s: '%s' %pp", indent, " ", op, (char *)s1, e1); \
515          if (e1) expr_dump_tree(e1, s, loglevel, indent + 2);                   \
516     } while (0)
517 #define DUMP_S_P(op, s1, p1)                                                \
518     ap_log_error(MARK,"%*s%s: '%s' %pp", indent, " ", op, (char *)s1, p1);
519 #define DUMP_P_P(op, p1, p2)                                                \
520     ap_log_error(MARK,"%*s%s: %pp %pp", indent, " ", op, p1, p2);
521 #define DUMP_S_S(op, s1, s2)                                                       \
522     ap_log_error(MARK,"%*s%s: '%s' '%s'", indent, " ", op, (char *)s1, (char *)s2)
523 #define DUMP_P(op, p1)                                                      \
524     ap_log_error(MARK,"%*s%s: %pp", indent, " ", op, p1);
525 #define DUMP_IP(op, p1)                                                     \
526     ap_log_error(MARK,"%*s%s: %d", indent, " ", op, *(int *)p1);
527 #define DUMP_S(op, s1)                                                      \
528     ap_log_error(MARK,"%*s%s: '%s'", indent, " ", op, (char *)s1)
529
530 #define CASE_OP(op)                  case op: name = #op ; break;
531
532 static void expr_dump_tree(const ap_expr_t *e, const server_rec *s,
533                            int loglevel, int indent)
534 {
535     switch (e->node_op) {
536     /* no arg */
537     case op_NOP:
538     case op_True:
539     case op_False:
540         {
541             char *name;
542             switch (e->node_op) {
543             CASE_OP(op_NOP);
544             CASE_OP(op_True);
545             CASE_OP(op_False);
546             default:
547                 ap_assert(0);
548             }
549             ap_log_error(MARK, "%*s%s", indent, " ", name);
550         }
551         break;
552
553     /* arg1: string, arg2: expr */
554     case op_UnaryOpCall:
555     case op_BinaryOpCall:
556     case op_BinaryOpArgs:
557         {
558             char *name;
559             switch (e->node_op) {
560             CASE_OP(op_BinaryOpCall);
561             CASE_OP(op_UnaryOpCall);
562             CASE_OP(op_BinaryOpArgs);
563             default:
564                 ap_assert(0);
565             }
566             DUMP_S_E(name, e->node_arg1, e->node_arg2);
567         }
568         break;
569
570     /* arg1: expr, arg2: expr */
571     case op_Comp:
572     case op_Not:
573     case op_Or:
574     case op_And:
575     case op_EQ:
576     case op_NE:
577     case op_LT:
578     case op_LE:
579     case op_GT:
580     case op_GE:
581     case op_STR_EQ:
582     case op_STR_NE:
583     case op_STR_LT:
584     case op_STR_LE:
585     case op_STR_GT:
586     case op_STR_GE:
587     case op_IN:
588     case op_REG:
589     case op_NRE:
590     case op_Concat:
591     case op_StringFuncCall:
592     case op_ListFuncCall:
593     case op_ListElement:
594         {
595             char *name;
596             switch (e->node_op) {
597             CASE_OP(op_Comp);
598             CASE_OP(op_Not);
599             CASE_OP(op_Or);
600             CASE_OP(op_And);
601             CASE_OP(op_EQ);
602             CASE_OP(op_NE);
603             CASE_OP(op_LT);
604             CASE_OP(op_LE);
605             CASE_OP(op_GT);
606             CASE_OP(op_GE);
607             CASE_OP(op_STR_EQ);
608             CASE_OP(op_STR_NE);
609             CASE_OP(op_STR_LT);
610             CASE_OP(op_STR_LE);
611             CASE_OP(op_STR_GT);
612             CASE_OP(op_STR_GE);
613             CASE_OP(op_IN);
614             CASE_OP(op_REG);
615             CASE_OP(op_NRE);
616             CASE_OP(op_Concat);
617             CASE_OP(op_StringFuncCall);
618             CASE_OP(op_ListFuncCall);
619             CASE_OP(op_ListElement);
620             default:
621                 ap_assert(0);
622             }
623             DUMP_E_E(name, e->node_arg1, e->node_arg2);
624         }
625         break;
626     /* arg1: string */
627     case op_Digit:
628     case op_String:
629         {
630             char *name;
631             switch (e->node_op) {
632             CASE_OP(op_Digit);
633             CASE_OP(op_String);
634             default:
635                 ap_assert(0);
636             }
637             DUMP_S(name, e->node_arg1);
638         }
639         break;
640     /* arg1: pointer, arg2: pointer */
641     case op_Var:
642     case op_StringFuncInfo:
643     case op_UnaryOpInfo:
644     case op_BinaryOpInfo:
645     case op_ListFuncInfo:
646         {
647             char *name;
648             switch (e->node_op) {
649             CASE_OP(op_Var);
650             CASE_OP(op_StringFuncInfo);
651             CASE_OP(op_UnaryOpInfo);
652             CASE_OP(op_BinaryOpInfo);
653             CASE_OP(op_ListFuncInfo);
654             default:
655                 ap_assert(0);
656             }
657             DUMP_P_P(name, e->node_arg1, e->node_arg2);
658         }
659         break;
660     /* arg1: pointer */
661     case op_Regex:
662         DUMP_P("op_Regex", e->node_arg1);
663         break;
664     /* arg1: pointer to int */
665     case op_RegexBackref:
666         DUMP_IP("op_RegexBackref", e->node_arg1);
667         break;
668     default:
669         ap_log_error(MARK, "%*sERROR: INVALID OP %d", indent, " ", e->node_op);
670         break;
671     }
672 }
673 #endif /* AP_EXPR_DEBUG */
674
675 static int ap_expr_eval_unary_op(ap_expr_eval_ctx_t *ctx, const ap_expr_t *info,
676                                  const ap_expr_t *arg)
677 {
678     ap_expr_op_unary_t *op_func = (ap_expr_op_unary_t *)info->node_arg1;
679     const void *data = info->node_arg2;
680
681     AP_DEBUG_ASSERT(info->node_op == op_UnaryOpInfo);
682     AP_DEBUG_ASSERT(op_func != NULL);
683     AP_DEBUG_ASSERT(data != NULL);
684     return (*op_func)(ctx, data, ap_expr_eval_word(ctx, arg));
685 }
686
687 static int ap_expr_eval_binary_op(ap_expr_eval_ctx_t *ctx,
688                                   const ap_expr_t *info,
689                                   const ap_expr_t *args)
690 {
691     ap_expr_op_binary_t *op_func = (ap_expr_op_binary_t *)info->node_arg1;
692     const void *data = info->node_arg2;
693     const ap_expr_t *a1 = args->node_arg1;
694     const ap_expr_t *a2 = args->node_arg2;
695
696     AP_DEBUG_ASSERT(info->node_op == op_BinaryOpInfo);
697     AP_DEBUG_ASSERT(args->node_op == op_BinaryOpArgs);
698     AP_DEBUG_ASSERT(op_func != NULL);
699     AP_DEBUG_ASSERT(data != NULL);
700     return (*op_func)(ctx, data, ap_expr_eval_word(ctx, a1),
701                       ap_expr_eval_word(ctx, a2));
702 }
703
704
705 static int ap_expr_eval(ap_expr_eval_ctx_t *ctx, const ap_expr_t *node)
706 {
707     const ap_expr_t *e1 = node->node_arg1;
708     const ap_expr_t *e2 = node->node_arg2;
709     int result = FALSE;
710     if (inc_rec(ctx))
711         return result;
712     while (1) {
713         switch (node->node_op) {
714         case op_True:
715             result ^= TRUE;
716             goto out;
717         case op_False:
718             result ^= FALSE;
719             goto out;
720         case op_Not:
721             result = !result;
722             node = e1;
723             break;
724         case op_Or:
725             do {
726                 if (e1->node_op == op_Not) {
727                     if (!ap_expr_eval(ctx, e1->node_arg1)) {
728                         result ^= TRUE;
729                         goto out;
730                     }
731                 }
732                 else {
733                     if (ap_expr_eval(ctx, e1)) {
734                         result ^= TRUE;
735                         goto out;
736                     }
737                 }
738                 node = node->node_arg2;
739                 e1 = node->node_arg1;
740             } while (node->node_op == op_Or);
741             break;
742         case op_And:
743             do {
744                 if (e1->node_op == op_Not) {
745                     if (ap_expr_eval(ctx, e1->node_arg1)) {
746                         result ^= FALSE;
747                         goto out;
748                     }
749                 }
750                 else {
751                     if (!ap_expr_eval(ctx, e1)) {
752                         result ^= FALSE;
753                         goto out;
754                     }
755                 }
756                 node = node->node_arg2;
757                 e1 = node->node_arg1;
758             } while (node->node_op == op_And);
759             break;
760         case op_UnaryOpCall:
761             result ^= ap_expr_eval_unary_op(ctx, e1, e2);
762             goto out;
763         case op_BinaryOpCall:
764             result ^= ap_expr_eval_binary_op(ctx, e1, e2);
765             goto out;
766         case op_Comp:
767             if (ctx->info->flags & AP_EXPR_FLAG_SSL_EXPR_COMPAT)
768                 result ^= ssl_expr_eval_comp(ctx, e1);
769             else
770                 result ^= ap_expr_eval_comp(ctx, e1);
771             goto out;
772         default:
773             *ctx->err = "Internal evaluation error: Unknown expression node";
774             goto out;
775         }
776         e1 = node->node_arg1;
777         e2 = node->node_arg2;
778     }
779 out:
780     ctx->reclvl--;
781     return result;
782 }
783
784 AP_DECLARE(int) ap_expr_exec(request_rec *r, const ap_expr_info_t *info,
785                              const char **err)
786 {
787     return ap_expr_exec_re(r, info, 0, NULL, NULL, err);
788 }
789
790 AP_DECLARE(int) ap_expr_exec_ctx(ap_expr_eval_ctx_t *ctx)
791 {
792     int rc;
793
794     AP_DEBUG_ASSERT(ctx->p != NULL);
795     /* XXX: allow r, c == NULL */
796     AP_DEBUG_ASSERT(ctx->r != NULL);
797     AP_DEBUG_ASSERT(ctx->c != NULL);
798     AP_DEBUG_ASSERT(ctx->s != NULL);
799     AP_DEBUG_ASSERT(ctx->err != NULL);
800     AP_DEBUG_ASSERT(ctx->info != NULL);
801     if (ctx->re_pmatch) {
802         AP_DEBUG_ASSERT(ctx->re_source != NULL);
803         AP_DEBUG_ASSERT(ctx->re_nmatch > 0);
804     }
805     ctx->reclvl = 0;
806
807     *ctx->err = NULL;
808     if (ctx->info->flags & AP_EXPR_FLAG_STRING_RESULT) {
809         *ctx->result_string = ap_expr_eval_word(ctx, ctx->info->root_node);
810         if (*ctx->err != NULL) {
811             ap_log_rerror(LOG_MARK(ctx->info), APLOG_ERR, 0, ctx->r,
812                           "Evaluation of expression from %s:%d failed: %s",
813                           ctx->info->filename, ctx->info->line_number, *ctx->err);
814             return -1;
815         } else {
816             ap_log_rerror(LOG_MARK(ctx->info), APLOG_TRACE4, 0, ctx->r,
817                           "Evaluation of string expression from %s:%d gave: %s",
818                           ctx->info->filename, ctx->info->line_number,
819                           *ctx->result_string);
820             return 1;
821         }
822     }
823     else {
824         rc = ap_expr_eval(ctx, ctx->info->root_node);
825         if (*ctx->err != NULL) {
826             ap_log_rerror(LOG_MARK(ctx->info), APLOG_ERR, 0, ctx->r,
827                           "Evaluation of expression from %s:%d failed: %s",
828                           ctx->info->filename, ctx->info->line_number, *ctx->err);
829             return -1;
830         } else {
831             rc = rc ? 1 : 0;
832             ap_log_rerror(LOG_MARK(ctx->info), APLOG_TRACE4, 0, ctx->r,
833                           "Evaluation of expression from %s:%d gave: %d",
834                           ctx->info->filename, ctx->info->line_number, rc);
835
836             if (ctx->vary_this && *ctx->vary_this)
837                 apr_table_merge(ctx->r->headers_out, "Vary", *ctx->vary_this);
838
839             return rc;
840         }
841     }
842 }
843
844 AP_DECLARE(int) ap_expr_exec_re(request_rec *r, const ap_expr_info_t *info,
845                                 apr_size_t nmatch, ap_regmatch_t *pmatch,
846                                 const char **source, const char **err)
847 {
848     ap_expr_eval_ctx_t ctx;
849     int dont_vary = (info->flags & AP_EXPR_FLAG_DONT_VARY);
850     const char *tmp_source = NULL, *vary_this = NULL;
851     ap_regmatch_t tmp_pmatch[AP_MAX_REG_MATCH];
852
853     AP_DEBUG_ASSERT((info->flags & AP_EXPR_FLAG_STRING_RESULT) == 0);
854
855     ctx.r = r;
856     ctx.c = r->connection;
857     ctx.s = r->server;
858     ctx.p = r->pool;
859     ctx.err  = err;
860     ctx.info = info;
861     ctx.re_nmatch = nmatch;
862     ctx.re_pmatch = pmatch;
863     ctx.re_source = source;
864     ctx.vary_this = dont_vary ? NULL : &vary_this;
865     ctx.data = NULL;
866
867     if (!pmatch) {
868         ctx.re_nmatch = AP_MAX_REG_MATCH;
869         ctx.re_pmatch = tmp_pmatch;
870         ctx.re_source = &tmp_source;
871     }
872
873     return ap_expr_exec_ctx(&ctx);
874 }
875
876 AP_DECLARE(const char *) ap_expr_str_exec_re(request_rec *r,
877                                              const ap_expr_info_t *info,
878                                              apr_size_t nmatch,
879                                              ap_regmatch_t *pmatch,
880                                              const char **source,
881                                              const char **err)
882 {
883     ap_expr_eval_ctx_t ctx;
884     int dont_vary, rc;
885     const char *tmp_source = NULL, *vary_this = NULL;
886     ap_regmatch_t tmp_pmatch[AP_MAX_REG_MATCH];
887     const char *result;
888
889     AP_DEBUG_ASSERT(info->flags & AP_EXPR_FLAG_STRING_RESULT);
890
891     if (info->root_node->node_op == op_String) {
892         /* short-cut for constant strings */
893         *err = NULL;
894         return (const char *)info->root_node->node_arg1;
895     }
896
897     dont_vary = (info->flags & AP_EXPR_FLAG_DONT_VARY);
898
899     ctx.r = r;
900     ctx.c = r->connection;
901     ctx.s = r->server;
902     ctx.p = r->pool;
903     ctx.err  = err;
904     ctx.info = info;
905     ctx.re_nmatch = nmatch;
906     ctx.re_pmatch = pmatch;
907     ctx.re_source = source;
908     ctx.vary_this = dont_vary ? NULL : &vary_this;
909     ctx.data = NULL;
910     ctx.result_string = &result;
911
912     if (!pmatch) {
913         ctx.re_nmatch = AP_MAX_REG_MATCH;
914         ctx.re_pmatch = tmp_pmatch;
915         ctx.re_source = &tmp_source;
916     }
917
918     rc = ap_expr_exec_ctx(&ctx);
919     if (rc > 0)
920         return result;
921     else if (rc < 0)
922         return NULL;
923     else
924         ap_assert(0);
925 }
926
927 AP_DECLARE(const char *) ap_expr_str_exec(request_rec *r,
928                                           const ap_expr_info_t *info,
929                                           const char **err)
930 {
931     return ap_expr_str_exec_re(r, info, 0, NULL, NULL, err);
932 }
933
934
935 static void add_vary(ap_expr_eval_ctx_t *ctx, const char *name)
936 {
937     if (!ctx->vary_this)
938         return;
939
940     if (*ctx->vary_this) {
941         *ctx->vary_this = apr_pstrcat(ctx->p, *ctx->vary_this, ", ", name,
942                                       NULL);
943     }
944     else {
945         *ctx->vary_this = name;
946     }
947 }
948
949 static const char *req_table_func(ap_expr_eval_ctx_t *ctx, const void *data,
950                                   const char *arg)
951 {
952     const char *name = (const char *)data;
953     apr_table_t *t;
954     if (!ctx->r)
955         return "";
956
957     if (name[2] == 's') {           /* resp */
958         /* Try r->headers_out first, fall back on err_headers_out. */
959         const char *v = apr_table_get(ctx->r->headers_out, arg);
960         if (v) {
961             return v;
962         }
963         t = ctx->r->err_headers_out;
964     }
965     else if (name[0] == 'n')        /* notes */
966         t = ctx->r->notes;
967     else if (name[3] == 'e')        /* reqenv */
968         t = ctx->r->subprocess_env;
969     else {                          /* req, http */
970         t = ctx->r->headers_in;
971         add_vary(ctx, arg);
972     }
973     return apr_table_get(t, arg);
974 }
975
976 static const char *env_func(ap_expr_eval_ctx_t *ctx, const void *data,
977                             const char *arg)
978 {
979     const char *res;
980     /* this order is for ssl_expr compatibility */
981     if (ctx->r) {
982         if ((res = apr_table_get(ctx->r->notes, arg)) != NULL)
983             return res;
984         else if ((res = apr_table_get(ctx->r->subprocess_env, arg)) != NULL)
985             return res;
986     }
987     return getenv(arg);
988 }
989
990 static const char *osenv_func(ap_expr_eval_ctx_t *ctx, const void *data,
991                               const char *arg)
992 {
993     return getenv(arg);
994 }
995
996 static const char *tolower_func(ap_expr_eval_ctx_t *ctx, const void *data,
997                                 const char *arg)
998 {
999     char *result = apr_pstrdup(ctx->p, arg);
1000     ap_str_tolower(result);
1001     return result;
1002 }
1003
1004 static const char *toupper_func(ap_expr_eval_ctx_t *ctx, const void *data,
1005                                 const char *arg)
1006 {
1007     char *result = apr_pstrdup(ctx->p, arg);
1008     ap_str_toupper(result);
1009     return result;
1010 }
1011
1012 static const char *escape_func(ap_expr_eval_ctx_t *ctx, const void *data,
1013                                const char *arg)
1014 {
1015     return ap_escape_uri(ctx->p, arg);
1016 }
1017
1018 #define MAX_FILE_SIZE 10*1024*1024
1019 static const char *file_func(ap_expr_eval_ctx_t *ctx, const void *data,
1020                              char *arg)
1021 {
1022     apr_file_t *fp;
1023     char *buf;
1024     apr_off_t offset;
1025     apr_size_t len;
1026     apr_finfo_t finfo;
1027
1028     if (apr_file_open(&fp, arg, APR_READ|APR_BUFFERED,
1029                       APR_OS_DEFAULT, ctx->p) != APR_SUCCESS) {
1030         *ctx->err = apr_psprintf(ctx->p, "Cannot open file %s", arg);
1031         return "";
1032     }
1033     apr_file_info_get(&finfo, APR_FINFO_SIZE, fp);
1034     if (finfo.size > MAX_FILE_SIZE) {
1035         *ctx->err = apr_psprintf(ctx->p, "File %s too large", arg);
1036         apr_file_close(fp);
1037         return "";
1038     }
1039     len = (apr_size_t)finfo.size;
1040     if (len == 0) {
1041         apr_file_close(fp);
1042         return "";
1043     }
1044     else {
1045         if ((buf = (char *)apr_palloc(ctx->p, sizeof(char)*(len+1))) == NULL) {
1046             *ctx->err = "Cannot allocate memory";
1047             apr_file_close(fp);
1048             return "";
1049         }
1050         offset = 0;
1051         apr_file_seek(fp, APR_SET, &offset);
1052         if (apr_file_read(fp, buf, &len) != APR_SUCCESS) {
1053             *ctx->err = apr_psprintf(ctx->p, "Cannot read from file %s", arg);
1054             apr_file_close(fp);
1055             return "";
1056         }
1057         buf[len] = '\0';
1058     }
1059     apr_file_close(fp);
1060     return buf;
1061 }
1062
1063 static const char *filesize_func(ap_expr_eval_ctx_t *ctx, const void *data,
1064                                   char *arg)
1065 {
1066     apr_finfo_t sb;
1067     if (apr_stat(&sb, arg, APR_FINFO_MIN, ctx->p) == APR_SUCCESS
1068         && sb.filetype == APR_REG && sb.size > 0)
1069         return apr_psprintf(ctx->p, "%" APR_OFF_T_FMT, sb.size);
1070     else
1071         return "0";
1072 }
1073
1074 static const char *unescape_func(ap_expr_eval_ctx_t *ctx, const void *data,
1075                                  const char *arg)
1076 {
1077     char *result = apr_pstrdup(ctx->p, arg);
1078     int ret = ap_unescape_url_keep2f(result, 0);
1079     if (ret == OK)
1080         return result;
1081     ap_log_rerror(LOG_MARK(ctx->info), APLOG_DEBUG, 0, ctx->r, APLOGNO(00538)
1082                   "%s %% escape in unescape('%s') at %s:%d",
1083                   ret == HTTP_BAD_REQUEST ? "Bad" : "Forbidden", arg,
1084                   ctx->info->filename, ctx->info->line_number);
1085     return "";
1086 }
1087
1088 static int op_nz(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1089 {
1090     const char *name = (const char *)data;
1091     if (name[0] == 'z')
1092         return (arg[0] == '\0');
1093     else
1094         return (arg[0] != '\0');
1095 }
1096
1097 static int op_file_min(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1098 {
1099     apr_finfo_t sb;
1100     const char *name = (const char *)data;
1101     if (apr_stat(&sb, arg, APR_FINFO_MIN, ctx->p) != APR_SUCCESS)
1102         return FALSE;
1103     switch (name[0]) {
1104     case 'd':
1105         return (sb.filetype == APR_DIR);
1106     case 'e':
1107         return TRUE;
1108     case 'f':
1109         return (sb.filetype == APR_REG);
1110     case 's':
1111         return (sb.filetype == APR_REG && sb.size > 0);
1112     default:
1113         ap_assert(0);
1114     }
1115     return FALSE;
1116 }
1117
1118 static int op_file_link(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1119 {
1120     apr_finfo_t sb;
1121 #if !defined(OS2)
1122     if (apr_stat(&sb, arg, APR_FINFO_MIN | APR_FINFO_LINK, ctx->p) == APR_SUCCESS
1123         && sb.filetype == APR_LNK) {
1124         return TRUE;
1125     }
1126 #endif
1127     return FALSE;
1128 }
1129
1130 static int op_file_xbit(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1131 {
1132     apr_finfo_t sb;
1133     if (apr_stat(&sb, arg, APR_FINFO_PROT| APR_FINFO_LINK, ctx->p) == APR_SUCCESS
1134         && (sb.protection & (APR_UEXECUTE | APR_GEXECUTE | APR_WEXECUTE))) {
1135         return TRUE;
1136     }
1137     return FALSE;
1138 }
1139
1140 static int op_url_subr(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1141 {
1142     int rc = FALSE;
1143     request_rec  *rsub, *r = ctx->r;
1144     if (!r)
1145         return FALSE;
1146     /* avoid some infinite recursions */
1147     if (r->main && r->main->uri && r->uri && strcmp(r->main->uri, r->uri) == 0)
1148         return FALSE;
1149
1150     rsub = ap_sub_req_lookup_uri(arg, r, NULL);
1151     if (rsub->status < 400) {
1152             rc = TRUE;
1153     }
1154     ap_log_rerror(LOG_MARK(ctx->info), APLOG_TRACE5, 0, r,
1155                   "Subrequest for -U %s at %s:%d gave status: %d",
1156                   arg, ctx->info->filename, ctx->info->line_number,
1157                   rsub->status);
1158     ap_destroy_sub_req(rsub);
1159     return rc;
1160 }
1161
1162 static int op_file_subr(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1163 {
1164     int rc = FALSE;
1165     apr_finfo_t sb;
1166     request_rec *rsub, *r = ctx->r;
1167     if (!r)
1168         return FALSE;
1169     rsub = ap_sub_req_lookup_file(arg, r, NULL);
1170     if (rsub->status < 300 &&
1171         /* double-check that file exists since default result is 200 */
1172         apr_stat(&sb, rsub->filename, APR_FINFO_MIN, ctx->p) == APR_SUCCESS) {
1173         rc = TRUE;
1174     }
1175     ap_log_rerror(LOG_MARK(ctx->info), APLOG_TRACE5, 0, r,
1176                   "Subrequest for -F %s at %s:%d gave status: %d",
1177                   arg, ctx->info->filename, ctx->info->line_number,
1178                   rsub->status);
1179     ap_destroy_sub_req(rsub);
1180     return rc;
1181 }
1182
1183
1184 APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *));
1185 static APR_OPTIONAL_FN_TYPE(ssl_is_https) *is_https = NULL;
1186
1187 static const char *conn_var_names[] = {
1188     "HTTPS",                    /*  0 */
1189     "IPV6",                     /*  1 */
1190     "CONN_LOG_ID",              /*  2 */
1191     "CONN_REMOTE_ADDR",         /*  3 */
1192     NULL
1193 };
1194
1195 static const char *conn_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
1196 {
1197     int index = ((const char **)data - conn_var_names);
1198     conn_rec *c = ctx->c;
1199     if (!c)
1200         return "";
1201
1202     switch (index) {
1203     case 0:
1204         if (is_https && is_https(c))
1205             return "on";
1206         else
1207             return "off";
1208     case 1:
1209 #if APR_HAVE_IPV6
1210         {
1211             apr_sockaddr_t *addr = c->peer_addr;
1212             if (addr->family == AF_INET6
1213                 && !IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addr->ipaddr_ptr))
1214                 return "on";
1215             else
1216                 return "off";
1217         }
1218 #else
1219         return "off";
1220 #endif
1221     case 2:
1222         return c->log_id;
1223     case 3:
1224         return c->peer_ip;
1225     default:
1226         ap_assert(0);
1227         return NULL;
1228     }
1229 }
1230
1231 static const char *request_var_names[] = {
1232     "REQUEST_METHOD",           /*  0 */
1233     "REQUEST_SCHEME",           /*  1 */
1234     "REQUEST_URI",              /*  2 */
1235     "REQUEST_FILENAME",         /*  3 */
1236     "REMOTE_HOST",              /*  4 */
1237     "REMOTE_IDENT",             /*  5 */
1238     "REMOTE_USER",              /*  6 */
1239     "SERVER_ADMIN",             /*  7 */
1240     "SERVER_NAME",              /*  8 */
1241     "SERVER_PORT",              /*  9 */
1242     "SERVER_PROTOCOL",          /* 10 */
1243     "SCRIPT_FILENAME",          /* 11 */
1244     "PATH_INFO",                /* 12 */
1245     "QUERY_STRING",             /* 13 */
1246     "IS_SUBREQ",                /* 14 */
1247     "DOCUMENT_ROOT",            /* 15 */
1248     "AUTH_TYPE",                /* 16 */
1249     "THE_REQUEST",              /* 17 */
1250     "CONTENT_TYPE",             /* 18 */
1251     "HANDLER",                  /* 19 */
1252     "REQUEST_LOG_ID",           /* 20 */
1253     "SCRIPT_USER",              /* 21 */
1254     "SCRIPT_GROUP",             /* 22 */
1255     "DOCUMENT_URI",             /* 23 */
1256     "LAST_MODIFIED",            /* 24 */
1257     "CONTEXT_PREFIX",           /* 25 */
1258     "CONTEXT_DOCUMENT_ROOT",    /* 26 */
1259     "REQUEST_STATUS",           /* 27 */
1260     "REMOTE_ADDR",              /* 28 */
1261     NULL
1262 };
1263
1264 static const char *request_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
1265 {
1266     int index = ((const char **)data - request_var_names);
1267     request_rec *r = ctx->r;
1268     if (!r)
1269         return "";
1270
1271     switch (index) {
1272     case 0:
1273         return r->method;
1274     case 1:
1275         return ap_http_scheme(r);
1276     case 2:
1277         return r->uri;
1278     case 3:
1279         return r->filename;
1280     case 4:
1281         return ap_get_remote_host(r->connection, r->per_dir_config,
1282                                   REMOTE_NAME, NULL);
1283     case 5:
1284         return ap_get_remote_logname(r);
1285     case 6:
1286         return r->user;
1287     case 7:
1288         return r->server->server_admin;
1289     case 8:
1290         return ap_get_server_name_for_url(r);
1291     case 9:
1292         return apr_psprintf(ctx->p, "%u", ap_get_server_port(r));
1293     case 10:
1294         return r->protocol;
1295     case 11:
1296         return r->filename;
1297     case 12:
1298         return r->path_info;
1299     case 13:
1300         return r->args;
1301     case 14:
1302         return (r->main != NULL ? "true" : "false");
1303     case 15:
1304         return ap_document_root(r);
1305     case 16:
1306         return r->ap_auth_type;
1307     case 17:
1308         return r->the_request;
1309     case 18:
1310         return r->content_type;
1311     case 19:
1312         return r->handler;
1313     case 20:
1314         return r->log_id;
1315     case 21:
1316         {
1317             char *result = "";
1318             if (r->finfo.valid & APR_FINFO_USER)
1319                 apr_uid_name_get(&result, r->finfo.user, ctx->p);
1320             return result;
1321         }
1322     case 22:
1323         {
1324             char *result = "";
1325             if (r->finfo.valid & APR_FINFO_USER)
1326                 apr_gid_name_get(&result, r->finfo.group, ctx->p);
1327             return result;
1328         }
1329     case 23:
1330         return r->uri;
1331     case 24:
1332         {
1333             apr_time_exp_t tm;
1334             apr_time_exp_lt(&tm, r->mtime);
1335             return apr_psprintf(ctx->p, "%02d%02d%02d%02d%02d%02d%02d",
1336                                 (tm.tm_year / 100) + 19, (tm.tm_year % 100),
1337                                 tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min,
1338                                 tm.tm_sec);
1339         }
1340     case 25:
1341         return ap_context_prefix(r);
1342     case 26:
1343         return ap_context_document_root(r);
1344     case 27:
1345         return r->status ? apr_psprintf(ctx->p, "%d", r->status) : "";
1346     case 28:
1347         return r->client_ip;
1348     default:
1349         ap_assert(0);
1350         return NULL;
1351     }
1352 }
1353
1354 static const char *req_header_var_names[] = {
1355     "HTTP_USER_AGENT",
1356     "HTTP_PROXY_CONNECTION",
1357     "HTTP_REFERER",
1358     "HTTP_COOKIE",
1359     "HTTP_FORWARDED",
1360     "HTTP_HOST",
1361     "HTTP_ACCEPT",
1362     NULL
1363 };
1364
1365 static const char *req_header_header_names[] = {
1366     "User-Agent",
1367     "Proxy-Connection",
1368     "Referer",
1369     "Cookie",
1370     "Forwarded",
1371     "Host",
1372     "Accept"
1373 };
1374
1375 static const char *req_header_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
1376 {
1377     const char **varname = (const char **)data;
1378     int index = (varname - req_header_var_names);
1379     const char *name;
1380
1381     AP_DEBUG_ASSERT(index < 6);
1382     if (!ctx->r)
1383         return "";
1384
1385     name = req_header_header_names[index];
1386     add_vary(ctx, name);
1387     return apr_table_get(ctx->r->headers_in, name);
1388 }
1389
1390 static const char *misc_var_names[] = {
1391     "TIME_YEAR",        /* 0 */
1392     "TIME_MON",         /* 1 */
1393     "TIME_DAY",         /* 2 */
1394     "TIME_HOUR",        /* 3 */
1395     "TIME_MIN",         /* 4 */
1396     "TIME_SEC",         /* 5 */
1397     "TIME_WDAY",        /* 6 */
1398     "TIME",             /* 7 */
1399     "SERVER_SOFTWARE",  /* 8 */
1400     "API_VERSION",      /* 9 */
1401     NULL
1402 };
1403
1404 static const char *misc_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
1405 {
1406     apr_time_exp_t tm;
1407     int index = ((const char **)data - misc_var_names);
1408     apr_time_exp_lt(&tm, apr_time_now());
1409
1410     switch (index) {
1411     case 0:
1412         return apr_psprintf(ctx->p, "%02d%02d", (tm.tm_year / 100) + 19,
1413                             tm.tm_year % 100);
1414     case 1:
1415         return apr_psprintf(ctx->p, "%02d", tm.tm_mon+1);
1416     case 2:
1417         return apr_psprintf(ctx->p, "%02d", tm.tm_mday);
1418     case 3:
1419         return apr_psprintf(ctx->p, "%02d", tm.tm_hour);
1420     case 4:
1421         return apr_psprintf(ctx->p, "%02d", tm.tm_min);
1422     case 5:
1423         return apr_psprintf(ctx->p, "%02d", tm.tm_sec);
1424     case 6:
1425         return apr_psprintf(ctx->p, "%d", tm.tm_wday);
1426     case 7:
1427         return apr_psprintf(ctx->p, "%02d%02d%02d%02d%02d%02d%02d",
1428                             (tm.tm_year / 100) + 19, (tm.tm_year % 100),
1429                             tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min,
1430                             tm.tm_sec);
1431     case 8:
1432         return ap_get_server_banner();
1433     case 9:
1434         return apr_itoa(ctx->p, MODULE_MAGIC_NUMBER);
1435     default:
1436         ap_assert(0);
1437     }
1438
1439     return NULL;
1440 }
1441
1442 static int subnet_parse_arg(ap_expr_lookup_parms *parms)
1443 {
1444     apr_ipsubnet_t *subnet;
1445     const char *addr = parms->arg;
1446     const char *mask;
1447     apr_status_t ret;
1448
1449     if (!parms->arg) {
1450         *parms->err = apr_psprintf(parms->ptemp,
1451                                    "-%s requires subnet/netmask as constant argument",
1452                                    parms->name);
1453         return !OK;
1454     }
1455
1456     mask = ap_strchr_c(addr, '/');
1457     if (mask) {
1458         addr = apr_pstrmemdup(parms->ptemp, addr, mask - addr);
1459         mask++;
1460     }
1461
1462     ret = apr_ipsubnet_create(&subnet, addr, mask, parms->pool);
1463     if (ret != APR_SUCCESS) {
1464         *parms->err = "parsing of subnet/netmask failed";
1465         return !OK;
1466     }
1467
1468     *parms->data = subnet;
1469     return OK;
1470 }
1471
1472 static int op_ipmatch(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg1,
1473                 const char *arg2)
1474 {
1475     apr_ipsubnet_t *subnet = (apr_ipsubnet_t *)data;
1476     apr_sockaddr_t *saddr;
1477
1478     AP_DEBUG_ASSERT(subnet != NULL);
1479
1480     /* maybe log an error if this goes wrong? */
1481     if (apr_sockaddr_info_get(&saddr, arg1, APR_UNSPEC, 0, 0, ctx->p) != APR_SUCCESS)
1482         return FALSE;
1483
1484     return apr_ipsubnet_test(subnet, saddr);
1485 }
1486
1487 static int op_R(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg1)
1488 {
1489     apr_ipsubnet_t *subnet = (apr_ipsubnet_t *)data;
1490
1491     AP_DEBUG_ASSERT(subnet != NULL);
1492
1493     if (!ctx->r)
1494         return FALSE;
1495
1496     return apr_ipsubnet_test(subnet, ctx->r->client_addr);
1497 }
1498
1499 static int op_T(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1500 {
1501     switch (arg[0]) {
1502     case '\0':
1503         return FALSE;
1504     case 'o':
1505     case 'O':
1506         return strcasecmp(arg, "off") == 0 ? FALSE : TRUE;
1507     case 'n':
1508     case 'N':
1509         return strcasecmp(arg, "no") == 0 ? FALSE : TRUE;
1510     case 'f':
1511     case 'F':
1512         return strcasecmp(arg, "false") == 0 ? FALSE : TRUE;
1513     case '0':
1514         return arg[1] == '\0' ? FALSE : TRUE;
1515     default:
1516         return TRUE;
1517     }
1518 }
1519
1520 static int op_fnmatch(ap_expr_eval_ctx_t *ctx, const void *data,
1521                       const char *arg1, const char *arg2)
1522 {
1523     return (APR_SUCCESS == apr_fnmatch(arg2, arg1, APR_FNM_PATHNAME));
1524 }
1525
1526 static int op_strmatch(ap_expr_eval_ctx_t *ctx, const void *data,
1527                        const char *arg1, const char *arg2)
1528 {
1529     return (APR_SUCCESS == apr_fnmatch(arg2, arg1, 0));
1530 }
1531
1532 static int op_strcmatch(ap_expr_eval_ctx_t *ctx, const void *data,
1533                         const char *arg1, const char *arg2)
1534 {
1535     return (APR_SUCCESS == apr_fnmatch(arg2, arg1, APR_FNM_CASE_BLIND));
1536 }
1537
1538 struct expr_provider_single {
1539     const void *func;
1540     const char *name;
1541     ap_expr_lookup_fn_t *arg_parsing_func;
1542     int restricted;
1543 };
1544
1545 struct expr_provider_multi {
1546     const void *func;
1547     const char **names;
1548 };
1549
1550 static const struct expr_provider_multi var_providers[] = {
1551     { misc_var_fn, misc_var_names },
1552     { req_header_var_fn, req_header_var_names },
1553     { request_var_fn, request_var_names },
1554     { conn_var_fn, conn_var_names },
1555     { NULL, NULL }
1556 };
1557
1558 static const struct expr_provider_single string_func_providers[] = {
1559     { osenv_func,           "osenv",          NULL, 0 },
1560     { env_func,             "env",            NULL, 0 },
1561     { req_table_func,       "resp",           NULL, 0 },
1562     { req_table_func,       "req",            NULL, 0 },
1563     /* 'http' as alias for 'req' for compatibility with ssl_expr */
1564     { req_table_func,       "http",           NULL, 0 },
1565     { req_table_func,       "note",           NULL, 0 },
1566     { req_table_func,       "reqenv",         NULL, 0 },
1567     { tolower_func,         "tolower",        NULL, 0 },
1568     { toupper_func,         "toupper",        NULL, 0 },
1569     { escape_func,          "escape",         NULL, 0 },
1570     { unescape_func,        "unescape",       NULL, 0 },
1571     { file_func,            "file",           NULL, 1 },
1572     { filesize_func,        "filesize",       NULL, 1 },
1573     { NULL, NULL, NULL}
1574 };
1575 /* XXX: base64 encode/decode ? */
1576
1577 static const struct expr_provider_single unary_op_providers[] = {
1578     { op_nz,        "n", NULL,             0 },
1579     { op_nz,        "z", NULL,             0 },
1580     { op_R,         "R", subnet_parse_arg, 0 },
1581     { op_T,         "T", NULL,             0 },
1582     { op_file_min,  "d", NULL,             1 },
1583     { op_file_min,  "e", NULL,             1 },
1584     { op_file_min,  "f", NULL,             1 },
1585     { op_file_min,  "s", NULL,             1 },
1586     { op_file_link, "L", NULL,             1 },
1587     { op_file_link, "h", NULL,             1 },
1588     { op_file_xbit, "x", NULL,             1 },
1589     { op_file_subr, "F", NULL,             0 },
1590     { op_url_subr,  "U", NULL,             0 },
1591     { op_url_subr,  "A", NULL,             0 },
1592     { NULL, NULL, NULL }
1593 };
1594
1595 static const struct expr_provider_single binary_op_providers[] = {
1596     { op_ipmatch,   "ipmatch",      subnet_parse_arg, 0 },
1597     { op_fnmatch,   "fnmatch",      NULL,             0 },
1598     { op_strmatch,  "strmatch",     NULL,             0 },
1599     { op_strcmatch, "strcmatch",    NULL,             0 },
1600     { NULL, NULL, NULL }
1601 };
1602
1603 static int core_expr_lookup(ap_expr_lookup_parms *parms)
1604 {
1605     switch (parms->type) {
1606     case AP_EXPR_FUNC_VAR: {
1607             const struct expr_provider_multi *prov = var_providers;
1608             while (prov->func) {
1609                 const char **name = prov->names;
1610                 while (*name) {
1611                     if (strcasecmp(*name, parms->name) == 0) {
1612                         *parms->func = prov->func;
1613                         *parms->data = name;
1614                         return OK;
1615                     }
1616                     name++;
1617                 }
1618                 prov++;
1619             }
1620         }
1621         break;
1622     case AP_EXPR_FUNC_STRING:
1623     case AP_EXPR_FUNC_OP_UNARY:
1624     case AP_EXPR_FUNC_OP_BINARY: {
1625             const struct expr_provider_single *prov;
1626             switch (parms->type) {
1627             case AP_EXPR_FUNC_STRING:
1628                 prov = string_func_providers;
1629                 break;
1630             case AP_EXPR_FUNC_OP_UNARY:
1631                 prov = unary_op_providers;
1632                 break;
1633             case AP_EXPR_FUNC_OP_BINARY:
1634                 prov = binary_op_providers;
1635                 break;
1636             default:
1637                 ap_assert(0);
1638             }
1639             while (prov->func) {
1640                 int match;
1641                 if (parms->type == AP_EXPR_FUNC_OP_UNARY)
1642                     match = !strcmp(prov->name, parms->name);
1643                 else
1644                     match = !strcasecmp(prov->name, parms->name);
1645                 if (match) {
1646                     if ((parms->flags & AP_EXPR_FLAG_RESTRICTED)
1647                         && prov->restricted) {
1648                         *parms->err =
1649                             apr_psprintf(parms->ptemp,
1650                                          "%s%s not available in restricted context",
1651                                          (parms->type == AP_EXPR_FUNC_STRING) ? "" : "-",
1652                                          prov->name);
1653                         return !OK;
1654                     }
1655                     *parms->func = prov->func;
1656                     if (prov->arg_parsing_func) {
1657                         return prov->arg_parsing_func(parms);
1658                     }
1659                     else {
1660                         *parms->data = prov->name;
1661                         return OK;
1662                     }
1663                 }
1664                 prov++;
1665             }
1666         }
1667         break;
1668     default:
1669         break;
1670     }
1671     return DECLINED;
1672 }
1673
1674 static int expr_lookup_not_found(ap_expr_lookup_parms *parms)
1675 {
1676     const char *type;
1677     const char *prefix = "";
1678
1679     switch (parms->type) {
1680     case AP_EXPR_FUNC_VAR:
1681         type = "Variable";
1682         break;
1683     case AP_EXPR_FUNC_STRING:
1684         type = "Function";
1685         break;
1686     case AP_EXPR_FUNC_LIST:
1687         type = "List-returning function";
1688         break;
1689     case AP_EXPR_FUNC_OP_UNARY:
1690         type = "Unary operator";
1691         break;
1692     case AP_EXPR_FUNC_OP_BINARY:
1693         type = "Binary operator";
1694         break;
1695     default:
1696         *parms->err = "Inavalid expression type in expr_lookup";
1697         return !OK;
1698     }
1699     if (   parms->type == AP_EXPR_FUNC_OP_UNARY
1700         || parms->type == AP_EXPR_FUNC_OP_BINARY) {
1701         prefix = "-";
1702     }
1703     *parms->err = apr_psprintf(parms->ptemp, "%s '%s%s' does not exist", type,
1704                                prefix, parms->name);
1705     return !OK;
1706 }
1707
1708 static int ap_expr_post_config(apr_pool_t *pconf, apr_pool_t *plog,
1709                                apr_pool_t *ptemp, server_rec *s)
1710 {
1711     is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https);
1712     apr_pool_cleanup_register(pconf, &is_https, ap_pool_cleanup_set_null,
1713                               apr_pool_cleanup_null);
1714     return OK;
1715 }
1716
1717 void ap_expr_init(apr_pool_t *p)
1718 {
1719     ap_hook_expr_lookup(core_expr_lookup, NULL, NULL, APR_HOOK_MIDDLE);
1720     ap_hook_expr_lookup(expr_lookup_not_found, NULL, NULL, APR_HOOK_REALLY_LAST);
1721     ap_hook_post_config(ap_expr_post_config, NULL, NULL, APR_HOOK_MIDDLE);
1722 }
1723