| 39 |
#include "util_script.h" |
#include "util_script.h" |
| 40 |
#include "http_core.h" |
#include "http_core.h" |
| 41 |
#include "mod_include.h" |
#include "mod_include.h" |
| 42 |
|
#include "ap_expr.h" |
| 43 |
|
|
| 44 |
/* helper for Latin1 <-> entity encoding */ |
/* helper for Latin1 <-> entity encoding */ |
| 45 |
#if APR_CHARSET_EBCDIC |
#if APR_CHARSET_EBCDIC |
| 66 |
const char *string; |
const char *string; |
| 67 |
} result_item_t; |
} result_item_t; |
| 68 |
|
|
|
/* conditional expression parser stuff */ |
|
|
typedef enum { |
|
|
TOKEN_STRING, |
|
|
TOKEN_RE, |
|
|
TOKEN_AND, |
|
|
TOKEN_OR, |
|
|
TOKEN_NOT, |
|
|
TOKEN_EQ, |
|
|
TOKEN_NE, |
|
|
TOKEN_RBRACE, |
|
|
TOKEN_LBRACE, |
|
|
TOKEN_GROUP, |
|
|
TOKEN_GE, |
|
|
TOKEN_LE, |
|
|
TOKEN_GT, |
|
|
TOKEN_LT, |
|
|
TOKEN_ACCESS |
|
|
} token_type_t; |
|
|
|
|
|
typedef struct { |
|
|
token_type_t type; |
|
|
const char *value; |
|
|
#ifdef DEBUG_INCLUDE |
|
|
const char *s; |
|
|
#endif |
|
|
} token_t; |
|
|
|
|
|
typedef struct parse_node { |
|
|
struct parse_node *parent; |
|
|
struct parse_node *left; |
|
|
struct parse_node *right; |
|
|
token_t token; |
|
|
int value; |
|
|
int done; |
|
|
#ifdef DEBUG_INCLUDE |
|
|
int dump_done; |
|
|
#endif |
|
|
} parse_node_t; |
|
|
|
|
| 69 |
typedef enum { |
typedef enum { |
| 70 |
XBITHACK_OFF, |
XBITHACK_OFF, |
| 71 |
XBITHACK_ON, |
XBITHACK_ON, |
| 116 |
} arg_item_t; |
} arg_item_t; |
| 117 |
|
|
| 118 |
typedef struct { |
typedef struct { |
|
const char *source; |
|
|
const char *rexp; |
|
|
apr_size_t nsub; |
|
|
ap_regmatch_t match[AP_MAX_REG_MATCH]; |
|
|
} backref_t; |
|
|
|
|
|
typedef struct { |
|
| 119 |
unsigned int T[256]; |
unsigned int T[256]; |
| 120 |
unsigned int x; |
unsigned int x; |
| 121 |
apr_size_t pattern_len; |
apr_size_t pattern_len; |
| 147 |
const char *undefined_echo; |
const char *undefined_echo; |
| 148 |
apr_size_t undefined_echo_len; |
apr_size_t undefined_echo_len; |
| 149 |
|
|
| 150 |
int accessenable; /* is using the access tests allowed? */ |
opt_func_t access_func; /* is using the access tests allowed? */ |
| 151 |
|
|
| 152 |
|
/* breadcrumb to track whether child request should have parent's env */ |
| 153 |
|
request_rec *kludge_child; |
| 154 |
#ifdef DEBUG_INCLUDE |
#ifdef DEBUG_INCLUDE |
| 155 |
struct { |
struct { |
| 156 |
ap_filter_t *f; |
ap_filter_t *f; |
| 866 |
return ret; |
return ret; |
| 867 |
} |
} |
| 868 |
|
|
| 869 |
|
static char *ssi_parse_string(request_rec *r, const char *in) |
|
/* |
|
|
* +-------------------------------------------------------+ |
|
|
* | | |
|
|
* | Conditional Expression Parser |
|
|
* | | |
|
|
* +-------------------------------------------------------+ |
|
|
*/ |
|
|
|
|
|
static APR_INLINE int re_check(include_ctx_t *ctx, const char *string, |
|
|
const char *rexp) |
|
|
{ |
|
|
ap_regex_t *compiled; |
|
|
backref_t *re = ctx->intern->re; |
|
|
int rc; |
|
|
|
|
|
compiled = ap_pregcomp(ctx->dpool, rexp, AP_REG_EXTENDED); |
|
|
if (!compiled) { |
|
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->intern->r, "unable to " |
|
|
"compile pattern \"%s\"", rexp); |
|
|
return -1; |
|
|
} |
|
|
|
|
|
if (!re) { |
|
|
re = ctx->intern->re = apr_palloc(ctx->pool, sizeof(*re)); |
|
|
} |
|
|
|
|
|
re->source = apr_pstrdup(ctx->pool, string); |
|
|
re->rexp = apr_pstrdup(ctx->pool, rexp); |
|
|
re->nsub = compiled->re_nsub; |
|
|
rc = !ap_regexec(compiled, string, AP_MAX_REG_MATCH, re->match, 0); |
|
|
|
|
|
ap_pregfree(ctx->dpool, compiled); |
|
|
return rc; |
|
|
} |
|
|
|
|
|
static int get_ptoken(include_ctx_t *ctx, const char **parse, token_t *token, token_t *previous) |
|
| 870 |
{ |
{ |
| 871 |
const char *p; |
include_ctx_t *ctx = ap_get_module_config(r->request_config, |
| 872 |
apr_size_t shift; |
&include_module); |
| 873 |
int unmatched; |
return ap_ssi_parse_string(ctx, in, NULL, 0, SSI_EXPAND_DROP_NAME); |
|
|
|
|
token->value = NULL; |
|
|
|
|
|
if (!*parse) { |
|
|
return 0; |
|
|
} |
|
|
|
|
|
/* Skip leading white space */ |
|
|
while (apr_isspace(**parse)) { |
|
|
++*parse; |
|
|
} |
|
|
|
|
|
if (!**parse) { |
|
|
*parse = NULL; |
|
|
return 0; |
|
|
} |
|
|
|
|
|
TYPE_TOKEN(token, TOKEN_STRING); /* the default type */ |
|
|
p = *parse; |
|
|
unmatched = 0; |
|
|
|
|
|
switch (*(*parse)++) { |
|
|
case '(': |
|
|
TYPE_TOKEN(token, TOKEN_LBRACE); |
|
|
return 0; |
|
|
case ')': |
|
|
TYPE_TOKEN(token, TOKEN_RBRACE); |
|
|
return 0; |
|
|
case '=': |
|
|
if (**parse == '=') ++*parse; |
|
|
TYPE_TOKEN(token, TOKEN_EQ); |
|
|
return 0; |
|
|
case '!': |
|
|
if (**parse == '=') { |
|
|
TYPE_TOKEN(token, TOKEN_NE); |
|
|
++*parse; |
|
|
return 0; |
|
|
} |
|
|
TYPE_TOKEN(token, TOKEN_NOT); |
|
|
return 0; |
|
|
case '\'': |
|
|
unmatched = '\''; |
|
|
break; |
|
|
case '/': |
|
|
/* if last token was ACCESS, this token is STRING */ |
|
|
if (previous != NULL && TOKEN_ACCESS == previous->type) { |
|
|
break; |
|
|
} |
|
|
TYPE_TOKEN(token, TOKEN_RE); |
|
|
unmatched = '/'; |
|
|
break; |
|
|
case '|': |
|
|
if (**parse == '|') { |
|
|
TYPE_TOKEN(token, TOKEN_OR); |
|
|
++*parse; |
|
|
return 0; |
|
|
} |
|
|
break; |
|
|
case '&': |
|
|
if (**parse == '&') { |
|
|
TYPE_TOKEN(token, TOKEN_AND); |
|
|
++*parse; |
|
|
return 0; |
|
|
} |
|
|
break; |
|
|
case '>': |
|
|
if (**parse == '=') { |
|
|
TYPE_TOKEN(token, TOKEN_GE); |
|
|
++*parse; |
|
|
return 0; |
|
|
} |
|
|
TYPE_TOKEN(token, TOKEN_GT); |
|
|
return 0; |
|
|
case '<': |
|
|
if (**parse == '=') { |
|
|
TYPE_TOKEN(token, TOKEN_LE); |
|
|
++*parse; |
|
|
return 0; |
|
|
} |
|
|
TYPE_TOKEN(token, TOKEN_LT); |
|
|
return 0; |
|
|
case '-': |
|
|
if (**parse == 'A' && (ctx->intern->accessenable)) { |
|
|
TYPE_TOKEN(token, TOKEN_ACCESS); |
|
|
++*parse; |
|
|
return 0; |
|
|
} |
|
|
break; |
|
|
} |
|
|
|
|
|
/* It's a string or regex token |
|
|
* Now search for the next token, which finishes this string |
|
|
*/ |
|
|
shift = 0; |
|
|
p = *parse = token->value = unmatched ? *parse : p; |
|
|
|
|
|
for (; **parse; p = ++*parse) { |
|
|
if (**parse == '\\') { |
|
|
if (!*(++*parse)) { |
|
|
p = *parse; |
|
|
break; |
|
|
} |
|
|
|
|
|
++shift; |
|
|
} |
|
|
else { |
|
|
if (unmatched) { |
|
|
if (**parse == 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 '&': |
|
|
if ((*parse)[1] == **parse) { |
|
|
++found; |
|
|
} |
|
|
break; |
|
|
} |
|
|
|
|
|
if (found) { |
|
|
break; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
if (unmatched) { |
|
|
token->value = apr_pstrdup(ctx->dpool, ""); |
|
|
} |
|
|
else { |
|
|
apr_size_t len = p - token->value - shift; |
|
|
char *c = apr_palloc(ctx->dpool, len + 1); |
|
|
|
|
|
p = token->value; |
|
|
token->value = c; |
|
|
|
|
|
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) { |
|
|
memcpy(c, p, len); |
|
|
} |
|
|
c[len] = '\0'; |
|
|
} |
|
|
|
|
|
return unmatched; |
|
| 874 |
} |
} |
| 875 |
|
static int ssi_access(request_rec *r, parse_node_t *current, |
| 876 |
static int parse_expr(include_ctx_t *ctx, const char *expr, int *was_error) |
string_func_t parse_string) |
| 877 |
{ |
{ |
| 878 |
parse_node_t *new, *root = NULL, *current = NULL; |
request_rec *rr; |
| 879 |
request_rec *r = ctx->intern->r; |
include_ctx_t *ctx = ap_get_module_config(r->request_config, |
| 880 |
request_rec *rr = NULL; |
&include_module); |
|
const char *error = "Invalid expression \"%s\" in file %s"; |
|
|
const char *parse = expr; |
|
|
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); |
|
|
*/ |
|
|
CREATE_NODE(ctx, new); |
|
|
|
|
|
was_unmatched = get_ptoken(ctx, &parse, &new->token, |
|
|
(current != NULL ? ¤t->token : NULL)); |
|
|
if (!parse) { |
|
|
break; |
|
|
} |
|
|
|
|
|
DEBUG_DUMP_UNMATCHED(ctx, was_unmatched); |
|
|
DEBUG_DUMP_TOKEN(ctx, &new->token); |
|
|
|
|
|
if (!current) { |
|
|
switch (new->token.type) { |
|
|
case TOKEN_STRING: |
|
|
case TOKEN_NOT: |
|
|
case TOKEN_ACCESS: |
|
|
case TOKEN_LBRACE: |
|
|
root = current = new; |
|
|
continue; |
|
|
|
|
|
default: |
|
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, error, expr, |
|
|
r->filename); |
|
|
*was_error = 1; |
|
|
return 0; |
|
|
} |
|
|
} |
|
|
|
|
|
switch (new->token.type) { |
|
|
case TOKEN_STRING: |
|
|
switch (current->token.type) { |
|
|
case TOKEN_STRING: |
|
|
current->token.value = |
|
|
apr_pstrcat(ctx->dpool, current->token.value, |
|
|
*current->token.value ? " " : "", |
|
|
new->token.value, NULL); |
|
|
continue; |
|
|
|
|
|
case TOKEN_RE: |
|
|
case TOKEN_RBRACE: |
|
|
case TOKEN_GROUP: |
|
|
break; |
|
|
|
|
|
default: |
|
|
new->parent = current; |
|
|
current = current->right = new; |
|
|
continue; |
|
|
} |
|
|
break; |
|
|
|
|
|
case TOKEN_RE: |
|
|
switch (current->token.type) { |
|
|
case TOKEN_EQ: |
|
|
case TOKEN_NE: |
|
|
new->parent = current; |
|
|
current = current->right = new; |
|
|
++regex; |
|
|
continue; |
|
|
|
|
|
default: |
|
|
break; |
|
|
} |
|
|
break; |
|
|
|
|
|
case TOKEN_AND: |
|
|
case TOKEN_OR: |
|
|
switch (current->token.type) { |
|
|
case TOKEN_STRING: |
|
|
case TOKEN_RE: |
|
|
case TOKEN_GROUP: |
|
|
current = current->parent; |
|
|
|
|
|
while (current) { |
|
|
switch (current->token.type) { |
|
|
case TOKEN_AND: |
|
|
case TOKEN_OR: |
|
|
case TOKEN_LBRACE: |
|
|
break; |
|
|
|
|
|
default: |
|
|
current = current->parent; |
|
|
continue; |
|
|
} |
|
|
break; |
|
|
} |
|
|
|
|
|
if (!current) { |
|
|
new->left = root; |
|
|
root->parent = new; |
|
|
current = root = new; |
|
|
continue; |
|
|
} |
|
|
|
|
|
new->left = current->right; |
|
|
new->left->parent = new; |
|
|
new->parent = current; |
|
|
current = current->right = new; |
|
|
continue; |
|
|
|
|
|
default: |
|
|
break; |
|
|
} |
|
|
break; |
|
|
|
|
|
case TOKEN_EQ: |
|
|
case TOKEN_NE: |
|
|
case TOKEN_GE: |
|
|
case TOKEN_GT: |
|
|
case TOKEN_LE: |
|
|
case TOKEN_LT: |
|
|
if (current->token.type == TOKEN_STRING) { |
|
|
current = current->parent; |
|
|
|
|
|
if (!current) { |
|
|
new->left = root; |
|
|
root->parent = new; |
|
|
current = root = new; |
|
|
continue; |
|
|
} |
|
|
|
|
|
switch (current->token.type) { |
|
|
case TOKEN_LBRACE: |
|
|
case TOKEN_AND: |
|
|
case TOKEN_OR: |
|
|
new->left = current->right; |
|
|
new->left->parent = new; |
|
|
new->parent = current; |
|
|
current = current->right = new; |
|
|
continue; |
|
|
|
|
|
default: |
|
|
break; |
|
|
} |
|
|
} |
|
|
break; |
|
|
|
|
|
case TOKEN_RBRACE: |
|
|
while (current && current->token.type != TOKEN_LBRACE) { |
|
|
current = current->parent; |
|
|
} |
|
|
|
|
|
if (current) { |
|
|
TYPE_TOKEN(¤t->token, TOKEN_GROUP); |
|
|
continue; |
|
|
} |
|
|
|
|
|
error = "Unmatched ')' in \"%s\" in file %s"; |
|
|
break; |
|
|
|
|
|
case TOKEN_NOT: |
|
|
case TOKEN_ACCESS: |
|
|
case TOKEN_LBRACE: |
|
|
switch (current->token.type) { |
|
|
case TOKEN_STRING: |
|
|
case TOKEN_RE: |
|
|
case TOKEN_RBRACE: |
|
|
case TOKEN_GROUP: |
|
|
break; |
|
|
|
|
|
default: |
|
|
current->right = new; |
|
|
new->parent = current; |
|
|
current = new; |
|
|
continue; |
|
|
} |
|
|
break; |
|
|
|
|
|
default: |
|
|
break; |
|
|
} |
|
|
|
|
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, error, expr, r->filename); |
|
|
*was_error = 1; |
|
|
return 0; |
|
|
} |
|
|
|
|
|
DEBUG_DUMP_TREE(ctx, root); |
|
|
|
|
|
/* Evaluate Parse Tree */ |
|
|
current = root; |
|
|
error = NULL; |
|
|
while (current) { |
|
|
switch (current->token.type) { |
|
|
case TOKEN_STRING: |
|
|
current->token.value = |
|
|
ap_ssi_parse_string(ctx, current->token.value, NULL, 0, |
|
|
SSI_EXPAND_DROP_NAME); |
|
|
current->value = !!*current->token.value; |
|
|
break; |
|
|
|
|
|
case TOKEN_AND: |
|
|
case TOKEN_OR: |
|
|
if (!current->left || !current->right) { |
|
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, |
|
|
"Invalid expression \"%s\" in file %s", |
|
|
expr, r->filename); |
|
|
*was_error = 1; |
|
|
return 0; |
|
|
} |
|
|
|
|
|
if (!current->left->done) { |
|
|
switch (current->left->token.type) { |
|
|
case TOKEN_STRING: |
|
|
current->left->token.value = |
|
|
ap_ssi_parse_string(ctx, current->left->token.value, |
|
|
NULL, 0, SSI_EXPAND_DROP_NAME); |
|
|
current->left->value = !!*current->left->token.value; |
|
|
DEBUG_DUMP_EVAL(ctx, current->left); |
|
|
current->left->done = 1; |
|
|
break; |
|
|
|
|
|
default: |
|
|
current = current->left; |
|
|
continue; |
|
|
} |
|
|
} |
|
|
|
|
|
/* short circuit evaluation */ |
|
|
if (!current->right->done && !regex && |
|
|
((current->token.type == TOKEN_AND && !current->left->value) || |
|
|
(current->token.type == TOKEN_OR && current->left->value))) { |
|
|
current->value = current->left->value; |
|
|
} |
|
|
else { |
|
|
if (!current->right->done) { |
|
|
switch (current->right->token.type) { |
|
|
case TOKEN_STRING: |
|
|
current->right->token.value = |
|
|
ap_ssi_parse_string(ctx,current->right->token.value, |
|
|
NULL, 0, SSI_EXPAND_DROP_NAME); |
|
|
current->right->value = !!*current->right->token.value; |
|
|
DEBUG_DUMP_EVAL(ctx, current->right); |
|
|
current->right->done = 1; |
|
|
break; |
|
|
|
|
|
default: |
|
|
current = current->right; |
|
|
continue; |
|
|
} |
|
|
} |
|
|
|
|
|
if (current->token.type == TOKEN_AND) { |
|
|
current->value = current->left->value && |
|
|
current->right->value; |
|
|
} |
|
|
else { |
|
|
current->value = current->left->value || |
|
|
current->right->value; |
|
|
} |
|
|
} |
|
|
break; |
|
|
|
|
|
case TOKEN_EQ: |
|
|
case TOKEN_NE: |
|
|
if (!current->left || !current->right || |
|
|
current->left->token.type != TOKEN_STRING || |
|
|
(current->right->token.type != TOKEN_STRING && |
|
|
current->right->token.type != TOKEN_RE)) { |
|
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, |
|
|
"Invalid expression \"%s\" in file %s", |
|
|
expr, r->filename); |
|
|
*was_error = 1; |
|
|
return 0; |
|
|
} |
|
|
current->left->token.value = |
|
|
ap_ssi_parse_string(ctx, current->left->token.value, NULL, 0, |
|
|
SSI_EXPAND_DROP_NAME); |
|
|
current->right->token.value = |
|
|
ap_ssi_parse_string(ctx, current->right->token.value, NULL, 0, |
|
|
SSI_EXPAND_DROP_NAME); |
|
|
|
|
|
if (current->right->token.type == TOKEN_RE) { |
|
|
current->value = re_check(ctx, current->left->token.value, |
|
|
current->right->token.value); |
|
|
--regex; |
|
|
} |
|
|
else { |
|
|
current->value = !strcmp(current->left->token.value, |
|
|
current->right->token.value); |
|
|
} |
|
|
|
|
|
if (current->token.type == TOKEN_NE) { |
|
|
current->value = !current->value; |
|
|
} |
|
|
break; |
|
| 881 |
|
|
| 882 |
case TOKEN_GE: |
/* if this arg isn't -A, just return */ |
| 883 |
case TOKEN_GT: |
if (current->token.type != TOKEN_ACCESS || current->token.value[0] != 'A') { |
|
case TOKEN_LE: |
|
|
case TOKEN_LT: |
|
|
if (!current->left || !current->right || |
|
|
current->left->token.type != TOKEN_STRING || |
|
|
current->right->token.type != TOKEN_STRING) { |
|
| 884 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, |
| 885 |
"Invalid expression \"%s\" in file %s", |
"Unsupported option -%s in file %s", |
| 886 |
expr, r->filename); |
current->token.value, r->filename); |
| 887 |
*was_error = 1; |
return 1; |
|
return 0; |
|
| 888 |
} |
} |
|
|
|
|
current->left->token.value = |
|
|
ap_ssi_parse_string(ctx, current->left->token.value, NULL, 0, |
|
|
SSI_EXPAND_DROP_NAME); |
|
|
current->right->token.value = |
|
|
ap_ssi_parse_string(ctx, current->right->token.value, NULL, 0, |
|
|
SSI_EXPAND_DROP_NAME); |
|
|
|
|
|
current->value = strcmp(current->left->token.value, |
|
|
current->right->token.value); |
|
|
|
|
|
switch (current->token.type) { |
|
|
case TOKEN_GE: current->value = current->value >= 0; break; |
|
|
case TOKEN_GT: current->value = current->value > 0; break; |
|
|
case TOKEN_LE: current->value = current->value <= 0; break; |
|
|
case TOKEN_LT: current->value = current->value < 0; break; |
|
|
default: current->value = 0; break; /* should not happen */ |
|
|
} |
|
|
break; |
|
|
|
|
|
case TOKEN_NOT: |
|
|
case TOKEN_GROUP: |
|
|
if (current->right) { |
|
|
if (!current->right->done) { |
|
|
current = current->right; |
|
|
continue; |
|
|
} |
|
|
current->value = current->right->value; |
|
|
} |
|
|
else { |
|
|
current->value = 1; |
|
|
} |
|
|
|
|
|
if (current->token.type == TOKEN_NOT) { |
|
|
current->value = !current->value; |
|
|
} |
|
|
break; |
|
|
|
|
|
case TOKEN_ACCESS: |
|
| 889 |
if (current->left || !current->right || |
if (current->left || !current->right || |
| 890 |
(current->right->token.type != TOKEN_STRING && |
(current->right->token.type != TOKEN_STRING && |
| 891 |
current->right->token.type != TOKEN_RE)) { |
current->right->token.type != TOKEN_RE)) { |
| 892 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, |
| 893 |
"Invalid expression \"%s\" in file %s: Token '-A' must be followed by a URI string.", |
"Invalid expression in file %s: Token '-A' must be followed by a URI string.", |
| 894 |
expr, r->filename); |
r->filename); |
| 895 |
*was_error = 1; |
return 1; /* was_error */ |
|
return 0; |
|
| 896 |
} |
} |
| 897 |
current->right->token.value = |
current->right->token.value = |
| 898 |
ap_ssi_parse_string(ctx, current->right->token.value, NULL, 0, |
ap_ssi_parse_string(ctx, current->right->token.value, NULL, 0, |
| 910 |
current->right->token.value); |
current->right->token.value); |
| 911 |
} |
} |
| 912 |
ap_destroy_sub_req(rr); |
ap_destroy_sub_req(rr); |
|
break; |
|
|
|
|
|
case TOKEN_RE: |
|
|
if (!error) { |
|
|
error = "No operator before regex in expr \"%s\" in file %s"; |
|
|
} |
|
|
case TOKEN_LBRACE: |
|
|
if (!error) { |
|
|
error = "Unmatched '(' in \"%s\" in file %s"; |
|
|
} |
|
|
default: |
|
|
if (!error) { |
|
|
error = "internal parser error in \"%s\" in file %s"; |
|
|
} |
|
|
|
|
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, error, expr,r->filename); |
|
|
*was_error = 1; |
|
| 913 |
return 0; |
return 0; |
| 914 |
} |
} |
| 915 |
|
|
|
DEBUG_DUMP_EVAL(ctx, current); |
|
|
current->done = 1; |
|
|
current = current->parent; |
|
|
} |
|
|
|
|
|
return (root ? root->value : 0); |
|
|
} |
|
|
|
|
|
|
|
| 916 |
/* |
/* |
| 917 |
* +-------------------------------------------------------+ |
* +-------------------------------------------------------+ |
| 918 |
* | | |
* | | |
| 1112 |
* Basically, it puts a bread crumb in here, then looks |
* Basically, it puts a bread crumb in here, then looks |
| 1113 |
* for the crumb later to see if its been here. |
* for the crumb later to see if its been here. |
| 1114 |
*/ |
*/ |
| 1115 |
if (rr) { |
ctx->intern->kludge_child = rr; |
|
ap_set_module_config(rr->request_config, &include_module, r); |
|
|
} |
|
| 1116 |
|
|
| 1117 |
if (!error_fmt && ap_run_sub_req(rr)) { |
if (!error_fmt && ap_run_sub_req(rr)) { |
| 1118 |
error_fmt = "unable to include \"%s\" in parsed file %s"; |
error_fmt = "unable to include \"%s\" in parsed file %s"; |
| 1519 |
|
|
| 1520 |
DEBUG_PRINTF((ctx, "**** if expr=\"%s\"\n", expr)); |
DEBUG_PRINTF((ctx, "**** if expr=\"%s\"\n", expr)); |
| 1521 |
|
|
| 1522 |
expr_ret = parse_expr(ctx, expr, &was_error); |
expr_ret = ap_expr_evalstring(r, expr, &was_error, &ctx->intern->re, |
| 1523 |
|
ssi_parse_string, ctx->intern->access_func); |
| 1524 |
|
|
| 1525 |
if (was_error) { |
if (was_error) { |
| 1526 |
SSI_CREATE_ERROR_BUCKET(ctx, f, bb); |
SSI_CREATE_ERROR_BUCKET(ctx, f, bb); |
| 1594 |
return APR_SUCCESS; |
return APR_SUCCESS; |
| 1595 |
} |
} |
| 1596 |
|
|
| 1597 |
expr_ret = parse_expr(ctx, expr, &was_error); |
expr_ret = ap_expr_evalstring(r, expr, &was_error, &ctx->intern->re, |
| 1598 |
|
ssi_parse_string, ctx->intern->access_func); |
| 1599 |
|
|
| 1600 |
if (was_error) { |
if (was_error) { |
| 1601 |
SSI_CREATE_ERROR_BUCKET(ctx, f, bb); |
SSI_CREATE_ERROR_BUCKET(ctx, f, bb); |
| 2926 |
{ |
{ |
| 2927 |
request_rec *r = f->r; |
request_rec *r = f->r; |
| 2928 |
include_ctx_t *ctx = f->ctx; |
include_ctx_t *ctx = f->ctx; |
|
request_rec *parent; |
|
| 2929 |
include_dir_config *conf = ap_get_module_config(r->per_dir_config, |
include_dir_config *conf = ap_get_module_config(r->per_dir_config, |
| 2930 |
&include_module); |
&include_module); |
| 2931 |
|
|
| 2957 |
if (ap_allow_options(r) & OPT_INCNOEXEC) { |
if (ap_allow_options(r) & OPT_INCNOEXEC) { |
| 2958 |
ctx->flags |= SSI_FLAG_NO_EXEC; |
ctx->flags |= SSI_FLAG_NO_EXEC; |
| 2959 |
} |
} |
| 2960 |
intern->accessenable = conf->accessenable; |
intern->access_func = conf->accessenable ? ssi_access : NULL; |
| 2961 |
|
|
| 2962 |
ctx->if_nesting_level = 0; |
ctx->if_nesting_level = 0; |
| 2963 |
intern->re = NULL; |
intern->re = NULL; |
| 2971 |
intern->end_seq_len = strlen(intern->end_seq); |
intern->end_seq_len = strlen(intern->end_seq); |
| 2972 |
intern->undefined_echo = conf->undefined_echo; |
intern->undefined_echo = conf->undefined_echo; |
| 2973 |
intern->undefined_echo_len = strlen(conf->undefined_echo); |
intern->undefined_echo_len = strlen(conf->undefined_echo); |
| 2974 |
|
/* breadcrumb */ |
| 2975 |
|
intern->kludge_child = NULL; |
| 2976 |
|
if (r->main != NULL) { |
| 2977 |
|
include_ctx_t *parent_ctx; |
| 2978 |
|
parent_ctx = ap_get_module_config(r->main->request_config, |
| 2979 |
|
&include_module); |
| 2980 |
|
/* if the subreq was created by mod_include then parent_ctx |
| 2981 |
|
* is not null. If not ... well, we need to check. |
| 2982 |
|
*/ |
| 2983 |
|
if (parent_ctx) { |
| 2984 |
|
intern->kludge_child = parent_ctx->intern->kludge_child; |
| 2985 |
|
} |
| 2986 |
|
} |
| 2987 |
|
/* we need to be able to look up ctx in r for ssi_parse_string */ |
| 2988 |
|
ap_set_module_config(r->request_config, &include_module, ctx); |
| 2989 |
} |
} |
| 2990 |
|
|
| 2991 |
if ((parent = ap_get_module_config(r->request_config, &include_module))) { |
if (ctx->intern->kludge_child == r) { |
| 2992 |
/* Kludge --- for nested includes, we want to keep the subprocess |
/* Kludge --- for nested includes, we want to keep the subprocess |
| 2993 |
* environment of the base document (for compatibility); that means |
* environment of the base document (for compatibility); that means |
| 2994 |
* torquing our own last_modified date as well so that the |
* torquing our own last_modified date as well so that the |