1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * ap_expr_eval.c, based on ssl_expr_eval.c from mod_ssl
23 #include "http_core.h"
24 #include "http_protocol.h"
25 #include "ap_provider.h"
26 #include "util_expr_private.h"
30 APLOG_USE_MODULE(core);
33 APR_HOOK_LINK(expr_lookup)
36 AP_IMPLEMENT_HOOK_RUN_FIRST(int, expr_lookup, (ap_expr_lookup_parms *parms),
39 static const char *ap_expr_eval_string_func(ap_expr_eval_ctx *ctx, const ap_expr *info,
41 static const char *ap_expr_eval_var(ap_expr_eval_ctx *ctx,
42 const ap_expr_var_func_t *func,
44 static void expr_dump_tree(const ap_expr *e, const server_rec *s, int loglevel, int indent);
46 static const char *ap_expr_eval_word(ap_expr_eval_ctx *ctx, const ap_expr *node)
48 const char *result = "";
49 switch (node->node_op) {
51 result = node->node_arg1;
54 result = node->node_arg1;
57 result = ap_expr_eval_var(ctx, node->node_arg1, node->node_arg2);
59 case op_StringFuncCall: {
60 const ap_expr *info = node->node_arg1;
61 const ap_expr *args = node->node_arg2;
62 result = ap_expr_eval_string_func(ctx, info, args);
66 *ctx->err = "Internal evaluation error: Unknown expression node";
74 static const char *ap_expr_eval_var(ap_expr_eval_ctx *ctx,
75 const ap_expr_var_func_t *func,
78 AP_DEBUG_ASSERT(func != NULL);
79 AP_DEBUG_ASSERT(data != NULL);
80 return (*func)(ctx, data);
83 static const char *ap_expr_eval_string_func(ap_expr_eval_ctx *ctx, const ap_expr *info,
86 ap_expr_string_func_t *func = (ap_expr_string_func_t *)info->node_arg1;
87 const void *data = info->node_arg2;
89 AP_DEBUG_ASSERT(info->node_op == op_StringFuncInfo);
90 AP_DEBUG_ASSERT(func != NULL);
91 AP_DEBUG_ASSERT(data != NULL);
92 return (*func)(ctx, data, ap_expr_eval_word(ctx, arg));
95 static int intstrcmp(const char *s1, const char *s2)
97 apr_int64_t i1 = apr_atoi64(s1);
98 apr_int64_t i2 = apr_atoi64(s2);
108 static int ap_expr_eval_comp(ap_expr_eval_ctx *ctx, const ap_expr *node)
110 switch (node->node_op) {
112 const ap_expr *e1 = node->node_arg1;
113 const ap_expr *e2 = node->node_arg2;
114 return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) == 0);
117 const ap_expr *e1 = node->node_arg1;
118 const ap_expr *e2 = node->node_arg2;
119 return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) != 0);
122 const ap_expr *e1 = node->node_arg1;
123 const ap_expr *e2 = node->node_arg2;
124 return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) < 0);
127 const ap_expr *e1 = node->node_arg1;
128 const ap_expr *e2 = node->node_arg2;
129 return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <= 0);
132 const ap_expr *e1 = node->node_arg1;
133 const ap_expr *e2 = node->node_arg2;
134 return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) > 0);
137 const ap_expr *e1 = node->node_arg1;
138 const ap_expr *e2 = node->node_arg2;
139 return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >= 0);
142 const ap_expr *e1 = node->node_arg1;
143 const ap_expr *e2 = node->node_arg2;
144 return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) == 0);
147 const ap_expr *e1 = node->node_arg1;
148 const ap_expr *e2 = node->node_arg2;
149 return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) != 0);
152 const ap_expr *e1 = node->node_arg1;
153 const ap_expr *e2 = node->node_arg2;
154 return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) < 0);
157 const ap_expr *e1 = node->node_arg1;
158 const ap_expr *e2 = node->node_arg2;
159 return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <= 0);
162 const ap_expr *e1 = node->node_arg1;
163 const ap_expr *e2 = node->node_arg2;
164 return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) > 0);
167 const ap_expr *e1 = node->node_arg1;
168 const ap_expr *e2 = node->node_arg2;
169 return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >= 0);
172 const ap_expr *e1 = node->node_arg1;
173 const ap_expr *e2 = node->node_arg2;
174 const char *needle = ap_expr_eval_word(ctx, e1);
175 if (e2->node_op == op_ListElement) {
177 const ap_expr *val = e2->node_arg1;
178 AP_DEBUG_ASSERT(e2->node_op == op_ListElement);
179 if (strcmp(needle, ap_expr_eval_word(ctx, val)) == 0) {
184 } while (e2 != NULL);
186 else if (e2->node_op == op_ListFuncCall) {
187 const ap_expr *info = e2->node_arg1;
188 const ap_expr *arg = e2->node_arg2;
189 ap_expr_list_func_t *func = (ap_expr_list_func_t *)info->node_arg1;
190 apr_array_header_t *haystack;
192 AP_DEBUG_ASSERT(func != NULL);
193 AP_DEBUG_ASSERT(info->node_op == op_ListFuncInfo);
194 haystack = (*func)(ctx, info->node_arg2, ap_expr_eval_word(ctx, arg));
195 if (haystack == NULL)
197 for (; i < haystack->nelts; i++) {
198 if (strcmp(needle, APR_ARRAY_IDX(haystack,i,char *)) == 0)
208 const ap_regex_t *regex;
210 e1 = node->node_arg1;
211 e2 = node->node_arg2;
212 word = ap_expr_eval_word(ctx, e1);
213 regex = e2->node_arg1;
214 return (ap_regexec(regex, word, 0, NULL, 0) == 0);
220 const ap_regex_t *regex;
222 e1 = node->node_arg1;
223 e2 = node->node_arg2;
224 word = ap_expr_eval_word(ctx, e1);
225 regex = e2->node_arg1;
226 return !(ap_regexec(regex, word, 0, NULL, 0) == 0);
229 *ctx->err = "Internal evaluation error: Unknown expression node";
235 /* combined string/int comparison for compatibility with ssl_expr */
236 static int strcmplex(const char *str1, const char *str2)
250 for (i = 0; i < n1; i++) {
251 if (str1[i] > str2[i])
253 if (str1[i] < str2[i])
259 static int ssl_expr_eval_comp(ap_expr_eval_ctx *ctx, const ap_expr *node)
261 const ap_expr *e1 = node->node_arg1;
262 const ap_expr *e2 = node->node_arg2;
263 switch (node->node_op) {
266 return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) == 0);
269 return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) != 0);
272 return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) < 0);
275 return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <= 0);
278 return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) > 0);
281 return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >= 0);
283 return ap_expr_eval_comp(ctx, node);
288 AP_DECLARE(const char *) ap_expr_parse(apr_pool_t *pool, apr_pool_t *ptemp,
289 ap_expr_info_t *info, const char *expr,
290 ap_expr_lookup_fn *lookup_fn)
292 ap_expr_parse_ctx ctx;
298 ctx.inputlen = strlen(expr);
299 ctx.inputptr = ctx.inputbuf;
301 ctx.error = NULL; /* generic bison error message (usually not very useful) */
302 ctx.error2 = NULL; /* additional error message */
303 ctx.flags = info->flags;
305 ctx.scan_buf[0] = '\0';
306 ctx.scan_ptr = ctx.scan_buf;
307 ctx.lookup_fn = lookup_fn ? lookup_fn : ap_run_expr_lookup;
309 ap_expr_yylex_init(&ctx.scanner);
310 ap_expr_yyset_extra(&ctx, ctx.scanner);
311 rc = ap_expr_yyparse(&ctx);
312 ap_expr_yylex_destroy(ctx.scanner);
315 return apr_psprintf(pool, "%s: %s", ctx.error, ctx.error2);
319 else if (ctx.error2) {
323 if (rc) /* XXX can this happen? */
324 return "syntax error";
326 /* XXX Make this properly depend on the loglevel, which requires
327 * XXX having a server_rec
331 expr_dump_tree(ctx.expr, NULL, APLOG_NOTICE, 2);
334 info->root_node = ctx.expr;
339 AP_DECLARE(ap_expr_info_t*) ap_expr_parse_cmd(const cmd_parms *cmd,
342 ap_expr_lookup_fn *lookup_fn)
344 ap_expr_info_t *info = apr_pcalloc(cmd->pool, sizeof(ap_expr_info_t));
345 info->filename = cmd->directive->filename;
346 info->line_number = cmd->directive->line_num;
347 *err = ap_expr_parse(cmd->pool, cmd->temp_pool, info, expr, lookup_fn);
355 ap_expr *ap_expr_make(ap_expr_node_op op, const void *a1, const void *a2,
356 ap_expr_parse_ctx *ctx)
358 ap_expr *node = apr_palloc(ctx->pool, sizeof(ap_expr));
360 node->node_arg1 = a1;
361 node->node_arg2 = a2;
366 static ap_expr *ap_expr_info_make(int type, const char *name, ap_expr_parse_ctx *ctx)
368 ap_expr *info = apr_palloc(ctx->pool, sizeof(ap_expr));
369 ap_expr_lookup_parms parms;
372 parms.pool = ctx->pool;
373 parms.ptemp = ctx->ptemp;
375 parms.func = &info->node_arg1;
376 parms.data = &info->node_arg2;
377 parms.err = &ctx->error2;
378 if (ctx->lookup_fn(&parms) != OK)
383 ap_expr *ap_expr_str_func_make(const char *name, const ap_expr *arg,
384 ap_expr_parse_ctx *ctx)
386 ap_expr *info = ap_expr_info_make(AP_EXPR_FUNC_STRING, name, ctx);
390 info->node_op = op_StringFuncInfo;
391 return ap_expr_make(op_StringFuncCall, info, arg, ctx);
394 ap_expr *ap_expr_list_func_make(const char *name, const ap_expr *arg,
395 ap_expr_parse_ctx *ctx)
397 ap_expr *info = ap_expr_info_make(AP_EXPR_FUNC_LIST, name, ctx);
401 info->node_op = op_ListFuncInfo;
402 return ap_expr_make(op_ListFuncCall, info, arg, ctx);
405 ap_expr *ap_expr_unary_op_make(const char *name, const ap_expr *arg,
406 ap_expr_parse_ctx *ctx)
408 ap_expr *info = ap_expr_info_make(AP_EXPR_FUNC_OP_UNARY, name, ctx);
412 info->node_op = op_UnaryOpInfo;
413 return ap_expr_make(op_UnaryOpCall, info, arg, ctx);
416 ap_expr *ap_expr_binary_op_make(const char *name, const ap_expr *arg1,
417 const ap_expr *arg2, ap_expr_parse_ctx *ctx)
420 ap_expr *info = ap_expr_info_make(AP_EXPR_FUNC_OP_UNARY, name, ctx);
424 info->node_op = op_BinaryOpInfo;
425 args = ap_expr_make(op_BinaryOpArgs, arg1, arg2, ctx);
426 return ap_expr_make(op_BinaryOpCall, info, args, ctx);
430 ap_expr *ap_expr_var_make(const char *name, ap_expr_parse_ctx *ctx)
432 ap_expr *node = ap_expr_info_make(AP_EXPR_FUNC_VAR, name, ctx);
436 node->node_op = op_Var;
441 #define MARK APLOG_MARK,loglevel,0,s
442 #define DUMP_E_E(op, e1, e2) \
443 do { ap_log_error(MARK,"%*s%s: %pp %pp", indent, " ", op, e1, e2); \
444 if (e1) expr_dump_tree(e1, s, loglevel, indent + 2); \
445 if (e2) expr_dump_tree(e2, s, loglevel, indent + 2); \
447 #define DUMP_S_E(op, s1, e1) \
448 do { ap_log_error(MARK,"%*s%s: '%s' %pp", indent, " ", op, (char *)s1, e1); \
449 if (e1) expr_dump_tree(e1, s, loglevel, indent + 2); \
451 #define DUMP_S_P(op, s1, p1) \
452 ap_log_error(MARK,"%*s%s: '%s' %pp", indent, " ", op, (char *)s1, p1);
453 #define DUMP_P_P(op, p1, p2) \
454 ap_log_error(MARK,"%*s%s: %pp %pp", indent, " ", op, p1, p2);
455 #define DUMP_S_S(op, s1, s2) \
456 ap_log_error(MARK,"%*s%s: '%s' '%s'", indent, " ", op, (char *)s1, (char *)s2)
457 #define DUMP_P(op, p1) \
458 ap_log_error(MARK,"%*s%s: %pp", indent, " ", op, p1);
459 #define DUMP_S(op, s1) \
460 ap_log_error(MARK,"%*s%s: '%s'", indent, " ", op, (char *)s1)
462 #define CASE_OP(op) case op: name = #op ; break;
464 static void expr_dump_tree(const ap_expr *e, const server_rec *s, int loglevel, int indent)
466 switch (e->node_op) {
473 switch (e->node_op) {
480 ap_log_error(MARK, "%*s%s", indent, " ", name);
484 /* arg1: string, arg2: expr */
486 case op_BinaryOpCall:
487 case op_BinaryOpArgs:
490 switch (e->node_op) {
491 CASE_OP(op_BinaryOpCall);
492 CASE_OP(op_UnaryOpCall);
493 CASE_OP(op_BinaryOpArgs);
497 DUMP_S_E(name, e->node_arg1, e->node_arg2);
501 /* arg1: expr, arg2: expr */
522 case op_StringFuncCall:
523 case op_ListFuncCall:
527 switch (e->node_op) {
548 CASE_OP(op_StringFuncCall);
549 CASE_OP(op_ListFuncCall);
550 CASE_OP(op_ListElement);
554 DUMP_E_E(name, e->node_arg1, e->node_arg2);
562 switch (e->node_op) {
568 DUMP_S(name, e->node_arg1);
571 /* arg1: pointer, arg2: pointer */
573 case op_StringFuncInfo:
575 case op_BinaryOpInfo:
576 case op_ListFuncInfo:
579 switch (e->node_op) {
581 CASE_OP(op_StringFuncInfo);
582 CASE_OP(op_UnaryOpInfo);
583 CASE_OP(op_BinaryOpInfo);
584 CASE_OP(op_ListFuncInfo);
588 DUMP_P_P(name, e->node_arg1, e->node_arg2);
593 DUMP_P("op_Regex", e->node_arg1);
596 ap_log_error(MARK, "%*sERROR: INVALID OP %d", indent, " ", e->node_op);
600 static int ap_expr_eval_unary_op(ap_expr_eval_ctx *ctx, const ap_expr *info,
603 const ap_expr_op_unary_t *op_func = info->node_arg1;
604 const void *data = info->node_arg2;
606 AP_DEBUG_ASSERT(info->node_op == op_UnaryOpInfo);
607 AP_DEBUG_ASSERT(op_func != NULL);
608 AP_DEBUG_ASSERT(data != NULL);
609 return (*op_func)(ctx, data, ap_expr_eval_word(ctx, arg));
612 static int ap_expr_eval_binary_op(ap_expr_eval_ctx *ctx, const ap_expr *info,
615 const ap_expr_op_binary_t *op_func = info->node_arg1;
616 const void *data = info->node_arg2;
617 const ap_expr *a1 = args->node_arg1;
618 const ap_expr *a2 = args->node_arg2;
620 AP_DEBUG_ASSERT(info->node_op == op_BinaryOpInfo);
621 AP_DEBUG_ASSERT(args->node_op == op_BinaryOpArgs);
622 AP_DEBUG_ASSERT(op_func != NULL);
623 AP_DEBUG_ASSERT(data != NULL);
624 return (*op_func)(ctx, data, ap_expr_eval_word(ctx, a1),
625 ap_expr_eval_word(ctx, a2));
629 static int ap_expr_eval(ap_expr_eval_ctx *ctx, const ap_expr *node)
631 switch (node->node_op) {
639 const ap_expr *e = node->node_arg1;
640 return (!ap_expr_eval(ctx, e));
643 const ap_expr *e1 = node->node_arg1;
644 const ap_expr *e2 = node->node_arg2;
645 return (ap_expr_eval(ctx, e1) || ap_expr_eval(ctx, e2));
648 const ap_expr *e1 = node->node_arg1;
649 const ap_expr *e2 = node->node_arg2;
650 return (ap_expr_eval(ctx, e1) && ap_expr_eval(ctx, e2));
652 case op_UnaryOpCall: {
653 const ap_expr *info = node->node_arg1;
654 const ap_expr *args = node->node_arg2;
655 return ap_expr_eval_unary_op(ctx, info, args);
657 case op_BinaryOpCall: {
658 const ap_expr *info = node->node_arg1;
659 const ap_expr *args = node->node_arg2;
660 return ap_expr_eval_binary_op(ctx, info, args);
663 const ap_expr *e = node->node_arg1;
664 if (ctx->info->flags & AP_EXPR_FLAGS_SSL_EXPR_COMPAT)
665 return ssl_expr_eval_comp(ctx, e);
667 return ap_expr_eval_comp(ctx, e);
670 *ctx->err = "Internal evaluation error: Unknown expression node";
677 AP_DECLARE(int) ap_expr_exec(request_rec *r, const ap_expr_info_t *info, const char **err)
679 ap_expr_eval_ctx ctx;
682 ctx.c = r->connection;
689 rc = ap_expr_eval(&ctx, info->root_node);
696 static const char *req_table_func(ap_expr_eval_ctx *ctx, const void *data,
699 const char *name = (const char *)data;
704 if (name[3] == 's') /* resp */
705 t = ctx->r->headers_out;
706 else if (name[4] == 'e') /* reqenv */
707 t = ctx->r->subprocess_env;
708 else if (name[0] == 'n') /* notes */
711 t = ctx->r->headers_in;
712 return apr_table_get(t, arg);
715 static const char *env_func(ap_expr_eval_ctx *ctx, const void *data,
719 /* this order is for ssl_expr compatibility */
721 if ((res = apr_table_get(ctx->r->notes, arg)) != NULL)
723 else if ((res = apr_table_get(ctx->r->subprocess_env, arg)) != NULL)
729 static const char *osenv_func(ap_expr_eval_ctx *ctx, const void *data,
735 static const char *tolower_func(ap_expr_eval_ctx *ctx, const void *data,
738 char *result = apr_pstrdup(ctx->p, arg);
739 ap_str_tolower(result);
743 static const char *toupper_func(ap_expr_eval_ctx *ctx, const void *data,
747 char *result = apr_pstrdup(ctx->p, arg);
749 for (p = result; *p; ++p) {
750 *p = apr_toupper(*p);
756 static const char *escape_func(ap_expr_eval_ctx *ctx, const void *data,
759 return ap_escape_uri(ctx->p, arg);
762 #define MAX_FILE_SIZE 10*1024*1024
763 static const char *file_func(ap_expr_eval_ctx *ctx, const void *data, char *arg)
771 if (apr_file_open(&fp, arg, APR_READ|APR_BUFFERED,
772 APR_OS_DEFAULT, ctx->p) != APR_SUCCESS) {
773 *ctx->err = apr_psprintf(ctx->p, "Cannot open file %s", arg);
776 apr_file_info_get(&finfo, APR_FINFO_SIZE, fp);
777 if (finfo.size > MAX_FILE_SIZE) {
778 *ctx->err = apr_psprintf(ctx->p, "File %s too large", arg);
782 len = (apr_size_t)finfo.size;
788 if ((buf = (char *)apr_palloc(ctx->p, sizeof(char)*(len+1))) == NULL) {
789 *ctx->err = "Cannot allocate memory";
794 apr_file_seek(fp, APR_SET, &offset);
795 if (apr_file_read(fp, buf, &len) != APR_SUCCESS) {
796 *ctx->err = apr_psprintf(ctx->p, "Cannot read from file %s", arg);
807 static const char *unescape_func(ap_expr_eval_ctx *ctx, const void *data,
810 char *result = apr_pstrdup(ctx->p, arg);
811 if (ap_unescape_url(result))
818 static int op_nz(ap_expr_eval_ctx *ctx, const void *data, const char *arg)
820 const char *name = (const char *)data;
822 return (arg[0] == '\0');
824 return (arg[0] != '\0');
827 APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *));
828 static APR_OPTIONAL_FN_TYPE(ssl_is_https) *is_https = NULL;
830 static const char *conn_var_names[] = {
831 "REMOTE_ADDR", /* 0 */
837 static const char *conn_var_fn(ap_expr_eval_ctx *ctx, const void *data)
839 int index = ((const char **)data - conn_var_names);
840 conn_rec *c = ctx->c;
848 if (is_https && is_https(c))
855 apr_sockaddr_t *addr = c->remote_addr;
856 if (addr->family == AF_INET6
857 && !IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addr->ipaddr_ptr))
871 static const char *request_var_names[] = {
872 "REQUEST_METHOD", /* 0 */
873 "REQUEST_SCHEME", /* 1 */
874 "REQUEST_URI", /* 2 */
875 "REQUEST_FILENAME", /* 3 */
876 "REMOTE_HOST", /* 4 */
877 "REMOTE_IDENT", /* 5 */
878 "REMOTE_USER", /* 6 */
879 "SERVER_ADMIN", /* 7 */
880 "SERVER_NAME", /* 8 */
881 "SERVER_PORT", /* 9 */
882 "SERVER_PROTOCOL", /* 10 */
883 "SCRIPT_FILENAME", /* 11 */
884 "PATH_INFO", /* 12 */
885 "QUERY_STRING", /* 13 */
886 "IS_SUBREQ", /* 14 */
887 "DOCUMENT_ROOT", /* 15 */
888 "AUTH_TYPE", /* 16 */
889 "THE_REQUEST", /* 17 */
890 "CONTENT_TYPE", /* 18 */
894 static const char *request_var_fn(ap_expr_eval_ctx *ctx, const void *data)
896 int index = ((const char **)data - request_var_names);
897 request_rec *r = ctx->r;
905 return ap_http_scheme(r);
911 return ap_get_remote_host(r->connection, r->per_dir_config,
914 return ap_get_remote_logname(r);
918 return r->server->server_admin;
920 return ap_get_server_name(r);
922 return apr_psprintf(ctx->p, "%u", ap_get_server_port(r));
932 return (r->main != NULL ? "true" : "false");
934 return ap_document_root(r);
936 return r->ap_auth_type;
938 return r->the_request;
940 return r->content_type;
947 static const char *req_header_var_names[] = {
948 "HTTP_USER_AGENT", /* 0 */
949 "HTTP_PROXY_CONNECTION", /* 1 */
958 static const char *req_header_var_fn(ap_expr_eval_ctx *ctx, const void *data)
960 const char **name = (const char **)data;
961 int index = (name - req_header_var_names);
967 return apr_table_get(ctx->r->headers_in, "User-Agent");
969 return apr_table_get(ctx->r->headers_in, "Proxy-Connection");
971 /* apr_table_get is case insensitive, just skip leading "HTTP_" */
972 return apr_table_get(ctx->r->headers_in, *name + 5);
976 static const char *misc_var_names[] = {
985 "SERVER_SOFTWARE", /* 8 */
986 "API_VERSION", /* 9 */
990 static const char *misc_var_fn(ap_expr_eval_ctx *ctx, const void *data)
993 int index = ((const char **)data - misc_var_names);
994 apr_time_exp_lt(&tm, apr_time_now());
998 return apr_psprintf(ctx->p, "%02d%02d", (tm.tm_year / 100) + 19,
1001 return apr_psprintf(ctx->p, "%02d", tm.tm_mon+1);
1003 return apr_psprintf(ctx->p, "%02d", tm.tm_mday);
1005 return apr_psprintf(ctx->p, "%02d", tm.tm_hour);
1007 return apr_psprintf(ctx->p, "%02d", tm.tm_min);
1009 return apr_psprintf(ctx->p, "%02d", tm.tm_sec);
1011 return apr_psprintf(ctx->p, "%d", tm.tm_wday);
1013 return apr_psprintf(ctx->p, "%02d%02d%02d%02d%02d%02d%02d",
1014 (tm.tm_year / 100) + 19, (tm.tm_year % 100),
1015 tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min,
1018 return ap_get_server_banner();
1020 return apr_itoa(ctx->p, MODULE_MAGIC_NUMBER);
1028 struct expr_provider_single {
1032 struct expr_provider_multi {
1037 static const struct expr_provider_multi var_providers[] = {
1038 { misc_var_fn, misc_var_names },
1039 { req_header_var_fn, req_header_var_names },
1040 { request_var_fn, request_var_names },
1041 { conn_var_fn, conn_var_names },
1045 static const struct expr_provider_single string_func_providers[] = {
1046 { osenv_func, "osenv" },
1047 { env_func, "env" },
1048 { req_table_func, "resp" },
1049 { req_table_func, "req" },
1050 /* 'http' as alias for 'req' for compatibility with ssl_expr */
1051 { req_table_func, "http" },
1052 { req_table_func, "note" },
1053 { tolower_func, "tolower" },
1054 { toupper_func, "toupper" },
1055 { escape_func, "escape" },
1056 { unescape_func, "unescape" },
1057 { file_func, "file" },
1060 /* XXX: base64 encode/decode ? */
1062 static const struct expr_provider_single unary_op_providers[] = {
1067 static int core_expr_lookup(ap_expr_lookup_parms *parms)
1069 switch (parms->type) {
1070 case AP_EXPR_FUNC_VAR: {
1071 const struct expr_provider_multi *prov = var_providers;
1072 while (prov->func) {
1073 const char **name = prov->names;
1075 if (strcasecmp(*name, parms->name) == 0) {
1076 *parms->func = prov->func;
1077 *parms->data = name;
1086 case AP_EXPR_FUNC_STRING: {
1087 const struct expr_provider_single *prov = string_func_providers;
1088 while (prov->func) {
1089 if (strcasecmp(prov->name, parms->name) == 0) {
1090 *parms->func = prov->func;
1091 *parms->data = prov->name;
1098 case AP_EXPR_FUNC_OP_UNARY: {
1099 const struct expr_provider_single *prov = unary_op_providers;
1100 while (prov->func) {
1101 if (strcasecmp(prov->name, parms->name) == 0) {
1102 *parms->func = prov->func;
1103 *parms->data = prov->name;
1116 static int expr_lookup_not_found(ap_expr_lookup_parms *parms)
1120 switch (parms->type) {
1121 case AP_EXPR_FUNC_VAR:
1124 case AP_EXPR_FUNC_STRING:
1127 case AP_EXPR_FUNC_LIST:
1128 type = "List-returning function";
1130 case AP_EXPR_FUNC_OP_UNARY:
1131 type = "Unary operator";
1133 case AP_EXPR_FUNC_OP_BINARY:
1134 type = "Binary operator";
1137 *parms->err = "Inavalid expression type in expr_lookup";
1140 *parms->err = apr_psprintf(parms->ptemp, "%s '%s' does not exist", type,
1145 static int ap_expr_post_config(apr_pool_t *pconf, apr_pool_t *plog,
1146 apr_pool_t *ptemp, server_rec *s)
1148 is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https);
1149 apr_pool_cleanup_register(pconf, &is_https, ap_pool_cleanup_set_null,
1150 apr_pool_cleanup_null);
1154 void ap_expr_init(apr_pool_t *p)
1156 ap_hook_expr_lookup(core_expr_lookup, NULL, NULL, APR_HOOK_MIDDLE);
1157 ap_hook_expr_lookup(expr_lookup_not_found, NULL, NULL, APR_HOOK_REALLY_LAST);
1158 ap_hook_post_config(ap_expr_post_config, NULL, NULL, APR_HOOK_MIDDLE);