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
* @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,
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;
* 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" */
#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
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";
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;
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) {
{
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;
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;
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)
{
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);
}
}
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",
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[] = {
/* '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" },