/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* _ _
* ap_expr_eval.c, based on ssl_expr_eval.c from mod_ssl
*/
#include "httpd.h"
#include "http_log.h"
#include "http_core.h"
#include "http_protocol.h"
#include "http_request.h"
#include "ap_provider.h"
#include "util_varbuf.h"
#include "util_expr_private.h"
#include "util_md5.h"
#include "apr_lib.h"
#include "apr_fnmatch.h"
#include "apr_base64.h"
#include "apr_sha1.h"
#include "apr_version.h"
#include "apr_strings.h"
#include "apr_strmatch.h"
#include "apr_escape.h"
#endif
#include <limits.h> /* for INT_MAX */
/* we know core's module_index is 0 */
)
unsigned int n);
const void *data);
/* define AP_EXPR_DEBUG to log the parse tree when parsing an expression */
#ifdef AP_EXPR_DEBUG
#endif
/*
* To reduce counting overhead, we only count calls to
* ap_expr_eval_word() and ap_expr_eval(). The max number of
* stack frames is larger by some factor.
*/
{
return 0;
}
/* short circuit further evaluation */
return 1;
}
{
return result;
case op_Digit:
case op_String:
break;
case op_Var:
break;
case op_Concat:
if (!*s1)
else if (!*s2)
else
}
int n;
int i = 1;
do {
i++;
n = i;
i--;
do {
i--;
}
else {
int i = 1;
do {
i++;
i = 0;
do {
i++;
i++;
}
break;
case op_StringFuncCall: {
break;
}
case op_RegexBackref: {
break;
}
default:
break;
}
if (!result)
result = "";
return result;
}
const void *data)
{
}
{
int len;
return "";
if (len == 0)
return "";
}
{
/* Evaluate the list elements and store them in apr_array_header. */
do {
}
else {
}
}
{
return -1;
return 0;
else
return 1;
}
{
case op_EQ:
case op_NE:
case op_LT:
case op_LE:
case op_GT:
case op_GE:
case op_STR_EQ:
case op_STR_NE:
case op_STR_LT:
case op_STR_LE:
case op_STR_GT:
case op_STR_GE:
case op_IN: {
do {
return 1;
}
int i = 0;
return 0;
return 1;
}
}
return 0;
}
case op_REG:
case op_NRE: {
int result;
/*
* $0 ... $9 may contain stuff the user wants to keep. Therefore
* we only set them if there are capturing parens in the regex.
*/
}
else {
}
return result;
else
return !result;
}
default:
return -1;
}
}
{
return -1;
return +1;
return 1;
return -1;
for (i = 0; i < n1; i++) {
return 1;
return -1;
}
return 0;
}
{
case op_EQ:
case op_STR_EQ:
case op_NE:
case op_STR_NE:
case op_LT:
case op_STR_LT:
case op_LE:
case op_STR_LE:
case op_GT:
case op_STR_GT:
case op_GE:
case op_STR_GE:
default:
}
}
{
return ap_run_expr_lookup(parms);
}
{
int rc;
else
}
}
if (rc) /* XXX can this happen? */
return "syntax error";
#ifdef AP_EXPR_DEBUG
#endif
return NULL;
}
const char *expr,
unsigned int flags,
const char **err,
int module_index)
{
if (*err)
return NULL;
return info;
}
{
return node;
}
{
if (arg) {
case op_String:
break;
case op_ListElement:
do {
}
break;
default:
break;
}
}
return NULL;
return info;
}
{
if (!info)
return NULL;
}
{
if (!info)
return NULL;
}
{
if (!info)
return NULL;
}
{
arg2);
if (!info)
return NULL;
}
{
if (!node)
return NULL;
return node;
}
#ifdef AP_EXPR_DEBUG
} while (0)
} while (0)
{
switch (e->node_op) {
/* no arg */
case op_NOP:
case op_True:
case op_False:
{
char *name;
switch (e->node_op) {
default:
ap_assert(0);
}
}
break;
/* arg1: string, arg2: expr */
case op_UnaryOpCall:
case op_BinaryOpCall:
case op_BinaryOpArgs:
{
char *name;
switch (e->node_op) {
default:
ap_assert(0);
}
}
break;
/* arg1: expr, arg2: expr */
case op_Comp:
case op_Not:
case op_Or:
case op_And:
case op_EQ:
case op_NE:
case op_LT:
case op_LE:
case op_GT:
case op_GE:
case op_STR_EQ:
case op_STR_NE:
case op_STR_LT:
case op_STR_LE:
case op_STR_GT:
case op_STR_GE:
case op_IN:
case op_REG:
case op_NRE:
case op_Concat:
case op_StringFuncCall:
case op_ListFuncCall:
case op_ListElement:
{
char *name;
switch (e->node_op) {
default:
ap_assert(0);
}
}
break;
/* arg1: string */
case op_Digit:
case op_String:
{
char *name;
switch (e->node_op) {
default:
ap_assert(0);
}
}
break;
/* arg1: pointer, arg2: pointer */
case op_Var:
case op_StringFuncInfo:
case op_UnaryOpInfo:
case op_BinaryOpInfo:
case op_ListFuncInfo:
{
char *name;
switch (e->node_op) {
default:
ap_assert(0);
}
}
break;
/* arg1: pointer */
case op_Regex:
break;
/* arg1: pointer to int */
case op_RegexBackref:
break;
default:
break;
}
}
#endif /* AP_EXPR_DEBUG */
{
}
{
}
{
return result;
while (1) {
case op_True:
goto out;
case op_False:
goto out;
case op_Not:
break;
case op_Or:
do {
goto out;
}
}
else {
goto out;
}
}
break;
case op_And:
do {
goto out;
}
}
else {
goto out;
}
}
break;
case op_UnaryOpCall:
goto out;
case op_BinaryOpCall:
goto out;
case op_Comp:
else
goto out;
default:
goto out;
}
}
out:
return result;
}
const char **err)
{
}
{
int rc;
/* XXX: allow r, c == NULL */
}
"Evaluation of expression from %s:%d failed: %s",
return -1;
} else {
"Evaluation of string expression from %s:%d gave: %s",
*ctx->result_string);
return 1;
}
}
else {
"Evaluation of expression from %s:%d failed: %s",
return -1;
} else {
"Evaluation of expression from %s:%d gave: %d",
return rc;
}
}
}
{
ctx.r = r;
ctx.c = r->connection;
if (!pmatch) {
}
return ap_expr_exec_ctx(&ctx);
}
const ap_expr_info_t *info,
const char **source,
const char **err)
{
const char *result;
/* short-cut for constant strings */
}
tmp_source = NULL;
ctx.r = r;
ctx.c = r->connection;
if (!pmatch) {
}
if (rc > 0)
return result;
else if (rc < 0)
return NULL;
else
ap_assert(0);
/* Not reached */
return NULL;
}
const ap_expr_info_t *info,
const char **err)
{
}
{
return;
NULL);
}
else {
}
}
const char *arg)
{
apr_table_t *t;
if (!ctx->r)
return "";
/* Try r->headers_out first, fall back on err_headers_out. */
if (v) {
return v;
}
t = ctx->r->err_headers_out;
}
t = ctx->r->subprocess_env;
t = ctx->r->headers_in;
else { /* req, http */
t = ctx->r->headers_in;
}
return apr_table_get(t, arg);
}
const char *arg)
{
const char *res;
/* this order is for ssl_expr compatibility */
if (ctx->r) {
return res;
return res;
}
}
const char *arg)
{
}
const char *arg)
{
return result;
}
const char *arg)
{
return result;
}
const char *arg)
{
}
const char *arg)
{
}
const char *arg)
{
}
const char *arg)
{
char *out;
return out;
}
const char *arg)
{
}
const char *arg)
{
}
#endif
{
"exactly 3 arguments");
return !OK;
}
return OK;
}
const apr_array_header_t *args)
{
const char *repl;
"exactly 3 arguments");
return "";
}
}
}
char *arg)
{
char *buf;
return "";
}
return "";
}
if (len == 0) {
return "";
}
else {
return "";
}
offset = 0;
return "";
}
}
return buf;
}
char *arg)
{
else
return "0";
}
char *arg)
{
else
return "0";
}
const char *arg)
{
return result;
"%s %% escape in unescape('%s') at %s:%d",
return "";
}
{
if (name[0] == 'z')
return (arg[0] == '\0');
else
return (arg[0] != '\0');
}
{
return FALSE;
switch (name[0]) {
case 'd':
case 'e':
return TRUE;
case 'f':
case 's':
default:
ap_assert(0);
}
return FALSE;
}
{
#if !defined(OS2)
return TRUE;
}
#endif
return FALSE;
}
{
return TRUE;
}
return FALSE;
}
{
if (!r)
return FALSE;
/* avoid some infinite recursions */
return FALSE;
}
"Subrequest for -U %s at %s:%d gave status: %d",
return rc;
}
{
if (!r)
return FALSE;
/* double-check that file exists since default result is 200 */
}
"Subrequest for -F %s at %s:%d gave status: %d",
return rc;
}
static const char *conn_var_names[] = {
"HTTPS", /* 0 */
"IPV6", /* 1 */
"CONN_LOG_ID", /* 2 */
"CONN_REMOTE_ADDR", /* 3 */
};
{
if (!c)
return "";
switch (index) {
case 0:
return "on";
else
return "off";
case 1:
#if APR_HAVE_IPV6
{
return "on";
else
return "off";
}
#else
return "off";
#endif
case 2:
return c->log_id;
case 3:
return c->client_ip;
default:
ap_assert(0);
return NULL;
}
}
static const char *request_var_names[] = {
"REQUEST_METHOD", /* 0 */
"REQUEST_SCHEME", /* 1 */
"REQUEST_URI", /* 2 */
"REQUEST_FILENAME", /* 3 */
"REMOTE_HOST", /* 4 */
"REMOTE_IDENT", /* 5 */
"REMOTE_USER", /* 6 */
"SERVER_ADMIN", /* 7 */
"SERVER_NAME", /* 8 */
"SERVER_PORT", /* 9 */
"SERVER_PROTOCOL", /* 10 */
"SCRIPT_FILENAME", /* 11 */
"PATH_INFO", /* 12 */
"QUERY_STRING", /* 13 */
"IS_SUBREQ", /* 14 */
"DOCUMENT_ROOT", /* 15 */
"AUTH_TYPE", /* 16 */
"THE_REQUEST", /* 17 */
"CONTENT_TYPE", /* 18 */
"HANDLER", /* 19 */
"REQUEST_LOG_ID", /* 20 */
"SCRIPT_USER", /* 21 */
"SCRIPT_GROUP", /* 22 */
"DOCUMENT_URI", /* 23 */
"LAST_MODIFIED", /* 24 */
"CONTEXT_PREFIX", /* 25 */
"CONTEXT_DOCUMENT_ROOT", /* 26 */
"REQUEST_STATUS", /* 27 */
"REMOTE_ADDR", /* 28 */
"SERVER_PROTOCOL_VERSION", /* 29 */
"SERVER_PROTOCOL_VERSION_MAJOR", /* 30 */
"SERVER_PROTOCOL_VERSION_MINOR", /* 31 */
};
{
request_rec *r = ctx->r;
if (!r)
return "";
switch (index) {
case 0:
return r->method;
case 1:
return ap_http_scheme(r);
case 2:
return r->uri;
case 3:
return r->filename;
case 4:
REMOTE_NAME, NULL);
case 5:
return ap_get_remote_logname(r);
case 6:
return r->user;
case 7:
return r->server->server_admin;
case 8:
return ap_get_server_name_for_url(r);
case 9:
case 10:
return r->protocol;
case 11:
return r->filename;
case 12:
return r->path_info;
case 13:
return r->args;
case 14:
case 15:
return ap_document_root(r);
case 16:
return r->ap_auth_type;
case 17:
return r->the_request;
case 18:
return r->content_type;
case 19:
return r->handler;
case 20:
return r->log_id;
case 21:
{
return result;
}
case 22:
{
return result;
}
case 23:
return r->uri;
case 24:
{
}
case 25:
return ap_context_prefix(r);
case 26:
return ap_context_document_root(r);
case 27:
case 28:
return r->useragent_ip;
case 29:
switch (r->proto_num) {
case 1001: return "1001"; /* 1.1 */
case 1000: return "1000"; /* 1.0 */
case 9: return "9"; /* 0.9 */
}
case 30:
switch (HTTP_VERSION_MAJOR(r->proto_num)) {
case 0: return "0";
case 1: return "1";
}
case 31:
switch (HTTP_VERSION_MINOR(r->proto_num)) {
case 0: return "0";
case 1: return "1";
case 9: return "9";
}
default:
ap_assert(0);
return NULL;
}
}
static const char *req_header_var_names[] = {
"HTTP_USER_AGENT", /* 0 */
"HTTP_PROXY_CONNECTION", /* 1 */
"HTTP_REFERER", /* 2 */
"HTTP_COOKIE", /* 3 */
"HTTP_FORWARDED", /* 4 */
"HTTP_HOST", /* 5 */
"HTTP_ACCEPT", /* 6 */
};
static const char *req_header_header_names[] = {
"User-Agent",
"Proxy-Connection",
"Referer",
"Cookie",
"Forwarded",
"Host",
"Accept"
};
{
const char *name;
if (!ctx->r)
return "";
}
static const char *misc_var_names[] = {
"TIME_YEAR", /* 0 */
"TIME_MON", /* 1 */
"TIME_DAY", /* 2 */
"TIME_HOUR", /* 3 */
"TIME_MIN", /* 4 */
"TIME_SEC", /* 5 */
"TIME_WDAY", /* 6 */
"TIME", /* 7 */
"SERVER_SOFTWARE", /* 8 */
"API_VERSION", /* 9 */
};
{
switch (index) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
return ap_get_server_banner();
case 9:
default:
ap_assert(0);
}
return NULL;
}
{
const char *mask;
return !OK;
}
if (mask) {
mask++;
}
if (ret != APR_SUCCESS) {
return !OK;
}
return OK;
}
const char *arg2)
{
/* maybe log an error if this goes wrong? */
return FALSE;
}
{
if (!ctx->r)
return FALSE;
}
{
switch (arg[0]) {
case '\0':
return FALSE;
case 'o':
case 'O':
case 'n':
case 'N':
case 'f':
case 'F':
case '0':
default:
return TRUE;
}
}
{
}
{
}
{
}
struct expr_provider_single {
const void *func;
const char *name;
int restricted;
};
struct expr_provider_multi {
const void *func;
const char **names;
};
{ misc_var_fn, misc_var_names },
{ conn_var_fn, conn_var_names },
};
/* 'http' as alias for 'req' for compatibility with ssl_expr */
#endif
};
};
};
{
case AP_EXPR_FUNC_VAR: {
while (*name) {
return OK;
}
name++;
}
prov++;
}
}
break;
case AP_EXPR_FUNC_STRING:
case AP_EXPR_FUNC_OP_UNARY:
case AP_EXPR_FUNC_OP_BINARY: {
case AP_EXPR_FUNC_STRING:
break;
case AP_EXPR_FUNC_OP_UNARY:
break;
case AP_EXPR_FUNC_OP_BINARY:
break;
default:
ap_assert(0);
}
int match;
else
if (match) {
&& prov->restricted) {
"%s%s not available in restricted context",
return !OK;
}
if (prov->arg_parsing_func) {
}
else {
return OK;
}
}
prov++;
}
}
break;
default:
break;
}
return DECLINED;
}
{
const char *type;
case AP_EXPR_FUNC_VAR:
type = "Variable";
break;
case AP_EXPR_FUNC_STRING:
type = "Function";
break;
case AP_EXPR_FUNC_LIST:
type = "List-returning function";
break;
case AP_EXPR_FUNC_OP_UNARY:
type = "Unary operator";
break;
case AP_EXPR_FUNC_OP_BINARY:
type = "Binary operator";
break;
default:
return !OK;
}
prefix = "-";
}
return !OK;
}
{
return OK;
}
{
}