util_expr_eval.c revision 8bc0214116f2225966cf4a806dc183f18e7c3803
/* 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 "ap_provider.h"
#include "util_expr_private.h"
#include "apr_lib.h"
)
const ap_expr_var_func_t *func,
const void *data);
/* define AP_EXPR_DEBUG to log the parse tree when parsing an expression */
#ifdef AP_EXPR_DEBUG
#endif
{
const char *result = "";
case op_Digit:
break;
case op_String:
break;
case op_Var:
break;
case op_Concat: {
if (!*s1)
else if (!*s2)
else
break;
}
case op_StringFuncCall: {
break;
}
case op_RegexBackref: {
break;
}
default:
break;
}
if (!result)
result = "";
return result;
}
const ap_expr_var_func_t *func,
const void *data)
{
}
{
int len;
return "";
if (len == 0)
return "";
}
{
}
{
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;
break;
}
}
int i = 0;
return 0;
return 1;
}
}
return 0;
}
case op_REG:
case op_NRE: {
const char *word;
const ap_regex_t *regex;
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:
}
}
{
int rc;
/*
* Be sure to avoid overflows in the scanner. In practice the input length
* will be limited by the config file parser, anyway.
* XXX: The scanner really should do proper buffer overflow checks
*/
return "Expression too long";
else
}
}
if (rc) /* XXX can this happen? */
return "syntax error";
#ifdef AP_EXPR_DEBUG
#endif
return NULL;
}
const char *expr,
const char **err,
{
if (*err)
return NULL;
return info;
}
{
return node;
}
{
return NULL;
return info;
}
{
if (!info)
return NULL;
}
{
if (!info)
return NULL;
}
{
if (!info)
return NULL;
}
{
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 */
{
}
{
}
{
case op_True: {
return 1;
}
case op_False: {
return 0;
}
case op_Not: {
return (!ap_expr_eval(ctx, e));
}
case op_Or: {
}
case op_And: {
}
case op_UnaryOpCall: {
}
case op_BinaryOpCall: {
}
case op_Comp: {
return ssl_expr_eval_comp(ctx, e);
else
return ap_expr_eval_comp(ctx, e);
}
default: {
return FALSE;
}
}
}
{
}
{
int rc;
ctx.r = r;
ctx.c = r->connection;
const char *tmp_source;
if (!pmatch) {
tmp_source = NULL;
}
else {
AP_DEBUG_ASSERT(nmatch > 0);
}
r, "Evaluation of expression from %s:%d failed: %s",
return -1;
} else {
r, "Evaluation of expression from %s:%d gave: %d",
return rc;
}
}
const char *arg)
{
apr_table_t *t;
if (!ctx->r)
return "";
t = ctx->r->headers_out;
t = ctx->r->subprocess_env;
else
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)
{
char *p;
for (p = result; *p; ++p) {
*p = apr_toupper(*p);
}
return result;
}
const char *arg)
{
}
{
apr_file_t *fp;
char *buf;
return "";
}
return "";
}
if (len == 0) {
return "";
}
else {
return "";
}
offset = 0;
return "";
}
}
return buf;
}
const char *arg)
{
if (ap_unescape_url(result))
return "";
else
return result;
}
{
if (name[0] == 'z')
return (arg[0] == '\0');
else
return (arg[0] != '\0');
}
static const char *conn_var_names[] = {
"REMOTE_ADDR", /* 0 */
"HTTPS", /* 1 */
"IPV6", /* 2 */
"CONN_LOG_ID", /* 3 */
};
{
if (!c)
return "";
switch (index) {
case 0:
return c->remote_ip;
case 1:
return "on";
else
return "off";
case 2:
#if APR_HAVE_IPV6
{
return "on";
else
return "off";
}
#else
return "off";
#endif
case 3:
return c->log_id;
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 */
};
{
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(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;
default:
ap_assert(0);
return NULL;
}
}
static const char *req_header_var_names[] = {
"HTTP_USER_AGENT", /* 0 */
"HTTP_PROXY_CONNECTION", /* 1 */
"HTTP_REFERER",
"HTTP_COOKIE",
"HTTP_FORWARDED",
"HTTP_HOST",
"HTTP_ACCEPT",
};
{
if (!ctx->r)
return "";
switch (index) {
case 0:
case 1:
default:
/* apr_table_get is case insensitive, just skip leading "HTTP_" */
}
}
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;
}
struct expr_provider_single {
const void *func;
const char *name;
};
struct expr_provider_multi {
const void *func;
const char **names;
};
static const struct expr_provider_multi var_providers[] = {
{ misc_var_fn, misc_var_names },
{ conn_var_fn, conn_var_names },
};
static const struct expr_provider_single string_func_providers[] = {
{ osenv_func, "osenv" },
{ env_func, "env" },
{ req_table_func, "resp" },
{ req_table_func, "req" },
/* 'http' as alias for 'req' for compatibility with ssl_expr */
{ req_table_func, "http" },
{ req_table_func, "note" },
{ tolower_func, "tolower" },
{ toupper_func, "toupper" },
{ escape_func, "escape" },
{ unescape_func, "unescape" },
{ file_func, "file" },
};
static const struct expr_provider_single unary_op_providers[] = {
{ op_nz, "n" },
{ op_nz, "z" },
};
{
case AP_EXPR_FUNC_VAR: {
while (*name) {
return OK;
}
name++;
}
prov++;
}
break;
}
case AP_EXPR_FUNC_STRING: {
return OK;
}
prov++;
}
break;
}
case AP_EXPR_FUNC_OP_UNARY: {
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;
}
return !OK;
}
{
return OK;
}
void ap_expr_init(apr_pool_t *p)
{
}