You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ni...@apache.org on 2008/03/29 18:18:26 UTC
svn commit: r642559 - in /httpd/httpd/trunk: CHANGES
modules/filters/mod_include.c
Author: niq
Date: Sat Mar 29 10:18:21 2008
New Revision: 642559
URL: http://svn.apache.org/viewvc?rev=642559&view=rev
Log:
Update mod_include to use ap_expr API
Modified:
httpd/httpd/trunk/CHANGES
httpd/httpd/trunk/modules/filters/mod_include.c
Modified: httpd/httpd/trunk/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/CHANGES?rev=642559&r1=642558&r2=642559&view=diff
==============================================================================
--- httpd/httpd/trunk/CHANGES [utf-8] (original)
+++ httpd/httpd/trunk/CHANGES [utf-8] Sat Mar 29 10:18:21 2008
@@ -3,6 +3,9 @@
[ When backported to 2.2.x, remove entry from this file ]
*) Introduced ap_expr API for expression evaluation.
+ This is adapted from mod_include, which is the first module
+ to use the new API.
+ [Nick Kew]
*) mod_authz_dbd: When redirecting after successful login/logout per
AuthzDBDRedirectQuery, do not report authorization failure, and use
Modified: httpd/httpd/trunk/modules/filters/mod_include.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/filters/mod_include.c?rev=642559&r1=642558&r2=642559&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/filters/mod_include.c (original)
+++ httpd/httpd/trunk/modules/filters/mod_include.c Sat Mar 29 10:18:21 2008
@@ -39,6 +39,7 @@
#include "util_script.h"
#include "http_core.h"
#include "mod_include.h"
+#include "ap_expr.h"
/* helper for Latin1 <-> entity encoding */
#if APR_CHARSET_EBCDIC
@@ -65,45 +66,6 @@
const char *string;
} result_item_t;
-/* 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;
-
typedef enum {
XBITHACK_OFF,
XBITHACK_ON,
@@ -154,13 +116,6 @@
} arg_item_t;
typedef struct {
- const char *source;
- const char *rexp;
- apr_size_t nsub;
- ap_regmatch_t match[AP_MAX_REG_MATCH];
-} backref_t;
-
-typedef struct {
unsigned int T[256];
unsigned int x;
apr_size_t pattern_len;
@@ -192,8 +147,10 @@
const char *undefined_echo;
apr_size_t undefined_echo_len;
- int accessenable; /* is using the access tests allowed? */
+ opt_func_t access_func; /* is using the access tests allowed? */
+ /* breadcrumb to track whether child request should have parent's env */
+ request_rec *kludge_child;
#ifdef DEBUG_INCLUDE
struct {
ap_filter_t *f;
@@ -909,633 +866,53 @@
return ret;
}
-
-/*
- * +-------------------------------------------------------+
- * | |
- * | 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)
+static char *ssi_parse_string(request_rec *r, const char *in)
{
- const char *p;
- apr_size_t shift;
- int unmatched;
-
- 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, "");
+ include_ctx_t *ctx = ap_get_module_config(r->request_config,
+ &include_module);
+ return ap_ssi_parse_string(ctx, in, NULL, 0, SSI_EXPAND_DROP_NAME);
+}
+static int ssi_access(request_rec *r, parse_node_t *current,
+ string_func_t parse_string)
+{
+ request_rec *rr;
+ include_ctx_t *ctx = ap_get_module_config(r->request_config,
+ &include_module);
+
+ /* if this arg isn't -A, just return */
+ if (current->token.type != TOKEN_ACCESS || current->token.value[0] != 'A') {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "Unsupported option -%s in file %s",
+ current->token.value, r->filename);
+ return 1;
+ }
+ if (current->left || !current->right ||
+ (current->right->token.type != TOKEN_STRING &&
+ current->right->token.type != TOKEN_RE)) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "Invalid expression in file %s: Token '-A' must be followed by a URI string.",
+ r->filename);
+ return 1; /* was_error */
+ }
+ current->right->token.value =
+ ap_ssi_parse_string(ctx, current->right->token.value, NULL, 0,
+ SSI_EXPAND_DROP_NAME);
+ rr = ap_sub_req_lookup_uri(current->right->token.value, r, NULL);
+ /* 400 and higher are considered access denied */
+ if (rr->status < HTTP_BAD_REQUEST) {
+ current->value = 1;
}
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;
-}
-
-static int parse_expr(include_ctx_t *ctx, const char *expr, int *was_error)
-{
- parse_node_t *new, *root = NULL, *current = NULL;
- request_rec *r = ctx->intern->r;
- request_rec *rr = NULL;
- 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;
+ current->value = 0;
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rr->status, r,
+ "mod_include: The tested "
+ "subrequest -A \"%s\" returned an error code.",
+ current->right->token.value);
}
-
- /* 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;
-
- case TOKEN_GE:
- case TOKEN_GT:
- case TOKEN_LE:
- case TOKEN_LT:
- if (!current->left || !current->right ||
- current->left->token.type != TOKEN_STRING ||
- current->right->token.type != TOKEN_STRING) {
- 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);
-
- 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:
- if (current->left || !current->right ||
- (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: Token '-A' must be followed by a URI string.",
- expr, r->filename);
- *was_error = 1;
- return 0;
- }
- current->right->token.value =
- ap_ssi_parse_string(ctx, current->right->token.value, NULL, 0,
- SSI_EXPAND_DROP_NAME);
- rr = ap_sub_req_lookup_uri(current->right->token.value, r, NULL);
- /* 400 and higher are considered access denied */
- if (rr->status < HTTP_BAD_REQUEST) {
- current->value = 1;
- }
- else {
- current->value = 0;
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rr->status, r,
- "mod_include: The tested "
- "subrequest -A \"%s\" returned an error code.",
- current->right->token.value);
- }
- 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;
- return 0;
- }
-
- DEBUG_DUMP_EVAL(ctx, current);
- current->done = 1;
- current = current->parent;
- }
-
- return (root ? root->value : 0);
+ ap_destroy_sub_req(rr);
+ return 0;
}
-
/*
* +-------------------------------------------------------+
* | |
@@ -1735,9 +1112,7 @@
* Basically, it puts a bread crumb in here, then looks
* for the crumb later to see if its been here.
*/
- if (rr) {
- ap_set_module_config(rr->request_config, &include_module, r);
- }
+ ctx->intern->kludge_child = rr;
if (!error_fmt && ap_run_sub_req(rr)) {
error_fmt = "unable to include \"%s\" in parsed file %s";
@@ -2144,7 +1519,8 @@
DEBUG_PRINTF((ctx, "**** if expr=\"%s\"\n", expr));
- expr_ret = parse_expr(ctx, expr, &was_error);
+ expr_ret = ap_expr_evalstring(r, expr, &was_error, &ctx->intern->re,
+ ssi_parse_string, ctx->intern->access_func);
if (was_error) {
SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
@@ -2218,7 +1594,8 @@
return APR_SUCCESS;
}
- expr_ret = parse_expr(ctx, expr, &was_error);
+ expr_ret = ap_expr_evalstring(r, expr, &was_error, &ctx->intern->re,
+ ssi_parse_string, ctx->intern->access_func);
if (was_error) {
SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
@@ -3549,7 +2926,6 @@
{
request_rec *r = f->r;
include_ctx_t *ctx = f->ctx;
- request_rec *parent;
include_dir_config *conf = ap_get_module_config(r->per_dir_config,
&include_module);
@@ -3581,7 +2957,7 @@
if (ap_allow_options(r) & OPT_INCNOEXEC) {
ctx->flags |= SSI_FLAG_NO_EXEC;
}
- intern->accessenable = conf->accessenable;
+ intern->access_func = conf->accessenable ? ssi_access : NULL;
ctx->if_nesting_level = 0;
intern->re = NULL;
@@ -3595,9 +2971,24 @@
intern->end_seq_len = strlen(intern->end_seq);
intern->undefined_echo = conf->undefined_echo;
intern->undefined_echo_len = strlen(conf->undefined_echo);
+ /* breadcrumb */
+ intern->kludge_child = NULL;
+ if (r->main != NULL) {
+ include_ctx_t *parent_ctx;
+ parent_ctx = ap_get_module_config(r->main->request_config,
+ &include_module);
+ /* if the subreq was created by mod_include then parent_ctx
+ * is not null. If not ... well, we need to check.
+ */
+ if (parent_ctx) {
+ intern->kludge_child = parent_ctx->intern->kludge_child;
+ }
+ }
+ /* we need to be able to look up ctx in r for ssi_parse_string */
+ ap_set_module_config(r->request_config, &include_module, ctx);
}
- if ((parent = ap_get_module_config(r->request_config, &include_module))) {
+ if (ctx->intern->kludge_child == r) {
/* Kludge --- for nested includes, we want to keep the subprocess
* environment of the base document (for compatibility); that means
* torquing our own last_modified date as well so that the