util_expr.c revision a69ee2f93830df6b1270cb9b66ec1a03f6b43640
/* 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.
*/
#include "apr.h"
#include "apr_strings.h"
#include "apr_lib.h"
#define APR_WANT_STRFUNC
#define APR_WANT_MEMFUNC
#include "apr_want.h"
#include "httpd.h"
#include "http_log.h"
#include "ap_expr.h"
#include <assert.h>
#if 1
/*
* +-------------------------------------------------------+
* | |
* | Debugging Utilities
* | |
* +-------------------------------------------------------+
*/
#ifdef DEBUG_INCLUDE
} while(0)
} while(0)
{
char *debug__str;
/*
APR_BRIGADE_INSERT_TAIL(ctx->intern->debug.bb, apr_bucket_pool_create(
debug__str, strlen(debug__str), ctx->pool,
ctx->intern->debug.f->c->bucket_alloc));
*/
}
if (d__c) { \
"NULL.\n"); \
} \
else { \
"points to another node (of type %s)!\n", \
} \
return; \
} \
continue; \
} \
} \
else { \
} \
}
{
char *is;
if (!root) {
return;
}
is = " ";
while (current) {
case TOKEN_STRING:
case TOKEN_RE:
continue;
case TOKEN_NOT:
case TOKEN_GROUP:
case TOKEN_RBRACE:
case TOKEN_LBRACE:
}
}
continue;
default:
}
}
continue;
}
}
/* it is possible to call this function within the parser loop, to see
* how the tree is built. That way, we must cleanup after us to dump
* always the whole tree
*/
return;
}
} while(0)
\
} \
else { \
} \
} while(0)
#define DEBUG_DUMP_EVAL(r, node) do { \
char c = '"'; \
case TOKEN_STRING: \
break; \
case TOKEN_AND: \
case TOKEN_OR: \
debug_printf((r), " Evaluate: %s (Left: %s; Right: %s) -> %c\n",\
: "short circuited"), \
: "short circuited"), \
break; \
case TOKEN_EQ: \
case TOKEN_NE: \
case TOKEN_GT: \
case TOKEN_GE: \
case TOKEN_LT: \
case TOKEN_LE: \
debug_printf((r), " Compare: %s (\"%s\" with %c%s%c) -> %c\n", \
break; \
default: \
break; \
} \
} while(0)
#define DEBUG_DUMP_UNMATCHED(r, unmatched) do { \
if (unmatched) { \
} \
} while(0)
#else /* DEBUG_INCLUDE */
} while(0)
#define DEBUG_PRINTF(arg)
#endif /* !DEBUG_INCLUDE */
#endif /* 0 */
/*
* +-------------------------------------------------------+
* | |
* | Conditional Expression Parser
* | |
* +-------------------------------------------------------+
*/
{
int rc;
if (!compiled) {
"compile pattern \"%s\"", rexp);
return -1;
}
if (!re) {
if (reptr) {
}
}
return rc;
}
{
const char *p;
int unmatched;
if (!*parse) {
return 0;
}
/* Skip leading white space */
while (apr_isspace(**parse)) {
++*parse;
}
if (!**parse) {
return 0;
}
p = *parse;
unmatched = 0;
switch (*(*parse)++) {
case '(':
return 0;
case ')':
return 0;
case '=':
return 0;
case '!':
if (**parse == '=') {
++*parse;
return 0;
}
return 0;
case '\'':
unmatched = '\'';
break;
case '/':
/* if last token was ACCESS, this token is STRING */
break;
}
unmatched = '/';
break;
case '|':
if (**parse == '|') {
++*parse;
return 0;
}
break;
case '&':
if (**parse == '&') {
++*parse;
return 0;
}
break;
case '>':
if (**parse == '=') {
++*parse;
return 0;
}
return 0;
case '<':
if (**parse == '=') {
++*parse;
return 0;
}
return 0;
case '-':
++*parse;
return 0;
}
break;
}
/* It's a string or regex token
* Now search for the next token, which finishes this string
*/
shift = 0;
if (**parse == '\\') {
if (!*(++*parse)) {
p = *parse;
break;
}
++shift;
}
else {
if (unmatched) {
unmatched = 0;
++*parse;
break;
}
}
else if (apr_isspace(**parse)) {
break;
}
else {
int found = 0;
switch (**parse) {
case '(':
case ')':
case '=':
case '!':
case '<':
case '>':
++found;
break;
case '|':
case '&':
++found;
}
break;
}
if (found) {
break;
}
}
}
}
if (unmatched) {
}
else {
while (shift--) {
const char *e = ap_strchr_c(p, '\\');
memcpy(c, p, e-p);
c += e-p;
*c++ = *++e;
len -= e-p;
p = e+1;
}
if (len) {
}
c[len] = '\0';
}
return unmatched;
}
/* This is what we export. We can split it in two. */
int *was_error)
{
const char *error = "Invalid expression \"%s\" in file %s";
int was_unmatched = 0;
unsigned regex = 0;
*was_error = 0;
if (!parse) {
return 0;
}
/* Create Parse Tree */
while (1) {
/* uncomment this to see how the tree a built:
*
* DEBUG_DUMP_TREE(ctx, root);
*/
if (!parse) {
break;
}
if (!current) {
case TOKEN_STRING:
case TOKEN_NOT:
case TOKEN_ACCESS:
case TOKEN_LBRACE:
continue;
default:
*was_error = 1;
return 0;
}
}
case TOKEN_STRING:
case TOKEN_STRING:
continue;
case TOKEN_RE:
case TOKEN_RBRACE:
case TOKEN_GROUP:
break;
default:
continue;
}
break;
case TOKEN_RE:
case TOKEN_EQ:
case TOKEN_NE:
++regex;
continue;
default:
break;
}
break;
case TOKEN_AND:
case TOKEN_OR:
case TOKEN_STRING:
case TOKEN_RE:
case TOKEN_GROUP:
while (current) {
case TOKEN_AND:
case TOKEN_OR:
case TOKEN_LBRACE:
break;
default:
continue;
}
break;
}
if (!current) {
continue;
}
continue;
default:
break;
}
break;
case TOKEN_EQ:
case TOKEN_NE:
case TOKEN_GE:
case TOKEN_GT:
case TOKEN_LE:
case TOKEN_LT:
if (!current) {
continue;
}
case TOKEN_LBRACE:
case TOKEN_AND:
case TOKEN_OR:
continue;
default:
break;
}
}
break;
case TOKEN_RBRACE:
}
if (current) {
continue;
}
error = "Unmatched ')' in \"%s\" in file %s";
break;
case TOKEN_NOT:
case TOKEN_ACCESS:
case TOKEN_LBRACE:
case TOKEN_STRING:
case TOKEN_RE:
case TOKEN_RBRACE:
case TOKEN_GROUP:
break;
default:
continue;
}
break;
default:
break;
}
*was_error = 1;
return 0;
}
return root;
}
{
}
}
return ret;
}
{
unsigned int regex = 0;
const char *val;
const char *lval;
const char *rval;
/* Evaluate Parse Tree */
while (current) {
case TOKEN_STRING:
break;
case TOKEN_AND:
case TOKEN_OR:
"Invalid expression in file %s", r->filename);
*was_error = 1;
return 0;
}
case TOKEN_STRING:
break;
default:
continue;
}
}
/* short circuit evaluation */
}
else {
case TOKEN_STRING:
break;
default:
continue;
}
}
}
else {
}
}
break;
case TOKEN_EQ:
case TOKEN_NE:
"Invalid expression in file %s", r->filename);
*was_error = 1;
return 0;
}
--regex;
}
else {
}
}
break;
case TOKEN_GE:
case TOKEN_GT:
case TOKEN_LE:
case TOKEN_LT:
"Invalid expression in file %s", r->filename);
*was_error = 1;
return 0;
}
}
break;
case TOKEN_NOT:
case TOKEN_GROUP:
continue;
}
}
else {
}
}
break;
case TOKEN_ACCESS:
if (eval_func) {
if (*was_error) {
return 0;
}
}
break;
case TOKEN_RE:
if (!error) {
error = "No operator before regex in file %s";
}
case TOKEN_LBRACE:
if (!error) {
error = "Unmatched '(' in file %s";
}
default:
if (!error) {
error = "internal parser error in file %s";
}
*was_error = 1;
return 0;
}
DEBUG_DUMP_EVAL(r, current);
}
}
{
"Error parsing expression in %s", r->filename);
return 0;
}
}
{
/* a default string evaluator: support headers and env */
table = r->headers_in;
}
table = r->headers_out;
}
table = r->subprocess_env;
}
}
}
else if (str[0] == '$') {
return r->handler;
}
return r->content_type;
}
}
/* TODO: provide a hook so modules can interpret other patterns */
/* OhBugger, where's the regexp for backreferences ? */
return str; /* default - literal string as-is */
}
{
if (isvar) {
}
return APR_SUCCESS;
}
{
static ap_regex_t var;
if (!isvar) {
}
else {
}
}
}