From b6649687a3a83479cdcbb6c06f2ce008501a5992 Mon Sep 17 00:00:00 2001 From: Stefan Fritsch Date: Sun, 21 Nov 2010 19:51:41 +0000 Subject: [PATCH] More ap_expr updates: - minor bump for ap_expr_exec_re() introduced in r1037504 - actually commit the changes to allow using backreferences in SetEnvIfExpr - automatically add the correct entries to the Vary-header if the result of an expression evaluation depends on a request header (can be turned off by setting the AP_EXPR_FLAGS_DONT_VARY flag) - set AP_EXPR_FLAGS_DONT_VARY in mod_log_config's conditional logging - fix various off-by-one errors in req_table_func git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1037540 13f79535-47bb-0310-9956-ffa450edef68 --- include/ap_expr.h | 27 ++++++++++--- include/ap_mmn.h | 3 +- modules/loggers/mod_log_config.c | 1 + modules/metadata/mod_setenvif.c | 5 ++- server/util_expr_eval.c | 65 +++++++++++++++++++++++--------- 5 files changed, 76 insertions(+), 25 deletions(-) diff --git a/include/ap_expr.h b/include/ap_expr.h index 2a27559232..f71f8817bb 100644 --- a/include/ap_expr.h +++ b/include/ap_expr.h @@ -43,27 +43,37 @@ typedef struct { const char *filename; /** The line number where the expression has been defined (for logging). */ unsigned int line_number; -#define AP_EXPR_FLAGS_SSL_EXPR_COMPAT 1 - /** Flags relevant for the expression */ + /** Flags relevant for the expression, see AP_EXPR_FLAGS_* */ unsigned int flags; /** The module that is used for loglevel configuration (XXX put into eval_ctx?) */ int module_index; } ap_expr_info_t; +/** Use ssl_expr compatibility mode (changes the meaning of the comparison + * operators) + */ +#define AP_EXPR_FLAGS_SSL_EXPR_COMPAT 1 +/** If using the simple ap_expr_exec(), don't add siginificant request headers + * to the Vary response header + */ +#define AP_EXPR_FLAGS_DONT_VARY 2 + /** - * Evaluate a parse tree + * Evaluate a parse tree, simple interface * @param r The current request * @param expr The expression to be evaluated * @param err Where an error message should be stored * @return > 0 if expression evaluates to true, == 0 if false, < 0 on error * @note err will be set to NULL on success, or to an error message on error + * @note request headers used during evaluation will be added to the Vary: + * response header, unless AP_EXPR_FLAGS_DONT_VARY is set. */ AP_DECLARE(int) ap_expr_exec(request_rec *r, const ap_expr_info_t *expr, const char **err); /** - * Evaluate a parse tree, with regexp backreferences + * Evaluate a parse tree, with access to regexp backreference * @param r The current request * @param expr The expression to be evaluated * @param nmatch size of the regex match vector pmatch @@ -75,6 +85,8 @@ AP_DECLARE(int) ap_expr_exec(request_rec *r, const ap_expr_info_t *expr, * @note nmatch/pmatch/source can be used both to make previous matches * available to ap_expr_exec_re and to use ap_expr_exec_re's matches * later on. + * @note request headers used during evaluation will be added to the Vary: + * response header, unless AP_EXPR_FLAGS_DONT_VARY is set. */ AP_DECLARE(int) ap_expr_exec_re(request_rec *r, const ap_expr_info_t *expr, apr_size_t nmatch, ap_regmatch_t *pmatch, @@ -98,8 +110,13 @@ typedef struct { ap_regmatch_t *re_pmatch; /** size of the vector pointed to by re_pmatch */ apr_size_t re_nmatch; - /** the string corresponding to the re_pmatch*/ + /** the string corresponding to the re_pmatch */ const char **re_source; + /** A string where the comma separated names of headers are stored + * to be later added to the Vary: header. If NULL, the caller is not + * interested in this information. + */ + const char **vary_this; } ap_expr_eval_ctx; diff --git a/include/ap_mmn.h b/include/ap_mmn.h index 3f7d3d566c..38d57b2bf0 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -285,6 +285,7 @@ * 20101106.2 (2.3.9-dev) Add suexec_disabled_reason field to ap_unixd_config * 20101113.0 (2.3.9-dev) Add source address to mod_proxy.h * 20101113.1 (2.3.9-dev) Add ap_set_flag_slot_char() + * 20101113.2 (2.3.9-dev) Add ap_expr_exec_re() */ #define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */ @@ -292,7 +293,7 @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 20101113 #endif -#define MODULE_MAGIC_NUMBER_MINOR 1 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 2 /* 0...n */ /** * Determine if the server's current MODULE_MAGIC_NUMBER is at least a diff --git a/modules/loggers/mod_log_config.c b/modules/loggers/mod_log_config.c index 12fce8cfee..38efc7bbce 100644 --- a/modules/loggers/mod_log_config.c +++ b/modules/loggers/mod_log_config.c @@ -1257,6 +1257,7 @@ static const char *add_custom_log(cmd_parms *cmd, void *dummy, const char *fn, if (err) return err; cls->condition_expr->module_index = APLOG_MODULE_INDEX; + cls->condition_expr->flags |= AP_EXPR_FLAGS_DONT_VARY; } else { return "error in condition clause"; diff --git a/modules/metadata/mod_setenvif.c b/modules/metadata/mod_setenvif.c index 3357963fc9..aa8db0b40c 100644 --- a/modules/metadata/mod_setenvif.c +++ b/modules/metadata/mod_setenvif.c @@ -651,7 +651,8 @@ static int match_headers(request_rec *r) if ((b->pattern && apr_strmatch(b->pattern, val, val_len)) || (b->preg && !ap_regexec(b->preg, val, AP_MAX_REG_MATCH, regm, 0)) || - (b->expr && (ap_expr_exec(r, b->expr, &err) > 0))) { + (b->expr && ap_expr_exec_re(r, b->expr, AP_MAX_REG_MATCH, regm, &val, &err) > 0)) + { const apr_array_header_t *arr = apr_table_elts(b->features); elts = (const apr_table_entry_t *) arr->elts; @@ -660,7 +661,7 @@ static int match_headers(request_rec *r) apr_table_unset(r->subprocess_env, elts[j].key); } else { - if (b->preg) { + if (!b->pattern) { char *replaced = ap_pregsub(r->pool, elts[j].val, val, AP_MAX_REG_MATCH, regm); if (replaced) { diff --git a/server/util_expr_eval.c b/server/util_expr_eval.c index 8e293e0498..9ab4160615 100644 --- a/server/util_expr_eval.c +++ b/server/util_expr_eval.c @@ -742,6 +742,8 @@ AP_DECLARE(int) ap_expr_exec_re(request_rec *r, const ap_expr_info_t *info, { ap_expr_eval_ctx ctx; int rc; + int dont_vary = (info->flags & AP_EXPR_FLAGS_DONT_VARY); + const char *vary_this = NULL; ctx.r = r; ctx.c = r->connection; ctx.s = r->server; @@ -751,6 +753,7 @@ AP_DECLARE(int) ap_expr_exec_re(request_rec *r, const ap_expr_info_t *info, ctx.re_nmatch = nmatch; ctx.re_pmatch = pmatch; ctx.re_source = source; + ctx.vary_this = dont_vary ? NULL : &vary_this; ap_regmatch_t tmp_pmatch[10]; const char *tmp_source; @@ -777,10 +780,28 @@ AP_DECLARE(int) ap_expr_exec_re(request_rec *r, const ap_expr_info_t *info, ap_log_rerror(__FILE__, __LINE__, info->module_index, APLOG_TRACE4, 0, r, "Evaluation of expression from %s:%d gave: %d", info->filename, info->line_number, rc); + + if (vary_this) + apr_table_merge(r->headers_out, "Vary", vary_this); + return rc; } } +static void add_vary(ap_expr_eval_ctx *ctx, const char *name) +{ + if (!ctx->vary_this) + return; + + if (*ctx->vary_this) { + *ctx->vary_this = apr_pstrcat(ctx->p, *ctx->vary_this, ", ", name, + NULL); + } + else { + *ctx->vary_this = name; + } +} + static const char *req_table_func(ap_expr_eval_ctx *ctx, const void *data, const char *arg) { @@ -789,14 +810,16 @@ static const char *req_table_func(ap_expr_eval_ctx *ctx, const void *data, if (!ctx->r) return ""; - if (name[3] == 's') /* resp */ + if (name[2] == 's') /* resp */ t = ctx->r->headers_out; - else if (name[4] == 'e') /* reqenv */ - t = ctx->r->subprocess_env; else if (name[0] == 'n') /* notes */ t = ctx->r->notes; - else + else if (name[3] == 'e') /* reqenv */ + t = ctx->r->subprocess_env; + else { /* req, http */ t = ctx->r->headers_in; + add_vary(ctx, arg); + } return apr_table_get(t, arg); } @@ -1042,8 +1065,8 @@ static const char *request_var_fn(ap_expr_eval_ctx *ctx, const void *data) } static const char *req_header_var_names[] = { - "HTTP_USER_AGENT", /* 0 */ - "HTTP_PROXY_CONNECTION", /* 1 */ + "HTTP_USER_AGENT", + "HTTP_PROXY_CONNECTION", "HTTP_REFERER", "HTTP_COOKIE", "HTTP_FORWARDED", @@ -1052,22 +1075,29 @@ static const char *req_header_var_names[] = { NULL }; +static const char *req_header_header_names[] = { + "User-Agent", + "Proxy-Connection", + "Referer", + "Cookie", + "Forwarded", + "Host", + "Accept" +}; + static const char *req_header_var_fn(ap_expr_eval_ctx *ctx, const void *data) { - const char **name = (const char **)data; - int index = (name - req_header_var_names); + const char **varname = (const char **)data; + int index = (varname - req_header_var_names); + const char *name; + + AP_DEBUG_ASSERT(index < 6); if (!ctx->r) return ""; - switch (index) { - case 0: - return apr_table_get(ctx->r->headers_in, "User-Agent"); - case 1: - return apr_table_get(ctx->r->headers_in, "Proxy-Connection"); - default: - /* apr_table_get is case insensitive, just skip leading "HTTP_" */ - return apr_table_get(ctx->r->headers_in, *name + 5); - } + name = req_header_header_names[index]; + add_vary(ctx, name); + return apr_table_get(ctx->r->headers_in, name); } static const char *misc_var_names[] = { @@ -1147,6 +1177,7 @@ static const struct expr_provider_single string_func_providers[] = { /* 'http' as alias for 'req' for compatibility with ssl_expr */ { req_table_func, "http" }, { req_table_func, "note" }, + { req_table_func, "reqenv" }, { tolower_func, "tolower" }, { toupper_func, "toupper" }, { escape_func, "escape" }, -- 2.40.0