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