#endif /* !APR_CHARSET_EBCDIC */
-/*
- * +-------------------------------------------------------+
- * | |
- * | Debugging Macros
- * | |
- * +-------------------------------------------------------+
- */
-
-#ifdef DEBUG_INCLUDE
-
-#define MAX_DEBUG_SIZE MAX_STRING_LEN
-
-#define LOG_COND_STATUS(ctx, f, bb, text) \
-do { \
- char *cond_txt = apr_pstrcat((ctx)->dpool, "**** ", (text), \
- " conditional_status=\"", ((ctx)->flags & SSI_FLAG_COND_TRUE)?"1":"0", \
- "\"\n", NULL); \
- APR_BRIGADE_INSERT_TAIL((bb), apr_bucket_heap_create(cond_txt, \
- strlen(cond_txt), NULL, (f)->c->bucket_alloc)); \
-} while(0)
-
-#define DUMP_PARSE_EXPR_DEBUG(buf, f, bb) \
-do { \
- APR_BRIGADE_INSERT_TAIL((bb), apr_bucket_heap_create((buf), \
- strlen((buf)), NULL, (f)->c->bucket_alloc)); \
-} while(0)
-
-#else
-
-#define MAX_DEBUG_SIZE 10
-#define LOG_COND_STATUS(ctx, f, bb, text)
-#define DUMP_PARSE_EXPR_DEBUG(buf, f, bb)
-
-#endif
-
-
/*
* +-------------------------------------------------------+
* | |
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_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,
XBITHACK_FULL
} xbithack_t;
-typedef struct {
- unsigned int T[256];
- unsigned int x;
- apr_size_t pattern_len;
-} bndm_t;
-
typedef struct {
const char *default_error_msg;
const char *default_time_fmt;
+ const char *undefined_echo;
xbithack_t xbithack;
} include_dir_config;
typedef struct {
const char *default_start_tag;
const char *default_end_tag;
- const char *undefined_echo;
- apr_size_t undefined_echo_len;
} include_server_config;
/* main parser states */
regmatch_t match[MAX_NMATCH];
} backref_t;
+typedef struct {
+ unsigned int T[256];
+ unsigned int x;
+ apr_size_t pattern_len;
+} bndm_t;
+
struct ssi_internal_ctx {
parse_state_t state;
int seen_eos;
arg_item_t *argv; /* all arguments */
backref_t *re; /* NULL if there wasn't a regex yet */
+
+ const char *undefined_echo;
+ apr_size_t undefined_echo_len;
+
+#ifdef DEBUG_INCLUDE
+ struct {
+ ap_filter_t *f;
+ apr_bucket_brigade *bb;
+ } debug;
+#endif
};
+/*
+ * +-------------------------------------------------------+
+ * | |
+ * | Debugging Utilities
+ * | |
+ * +-------------------------------------------------------+
+ */
+
+#ifdef DEBUG_INCLUDE
+
+#define TYPE_TOKEN(token, ttype) do { \
+ (token)->type = ttype; \
+ (token)->s = #ttype; \
+} while(0)
+
+#define CREATE_NODE(ctx, name) do { \
+ (name) = apr_palloc((ctx)->dpool, sizeof(*(name))); \
+ (name)->parent = (name)->left = (name)->right = NULL; \
+ (name)->done = 0; \
+ (name)->dump_done = 0; \
+} while(0)
+
+static void debug_printf(include_ctx_t *ctx, const char *fmt, ...)
+{
+ va_list ap;
+ char *debug__str;
+
+ va_start(ap, fmt);
+ debug__str = apr_pvsprintf(ctx->pool, fmt, ap);
+ va_end(ap);
+
+ 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));
+}
+
+#define DUMP__CHILD(ctx, is, node, child) if (1) { \
+ parse_node_t *d__c = node->child; \
+ if (d__c) { \
+ if (!d__c->dump_done) { \
+ if (d__c->parent != node) { \
+ debug_printf(ctx, "!!! Parse tree is not consistent !!!\n"); \
+ if (!d__c->parent) { \
+ debug_printf(ctx, "Parent of " #child " child node is " \
+ "NULL.\n"); \
+ } \
+ else { \
+ debug_printf(ctx, "Parent of " #child " child node " \
+ "points to another node (of type %s)!\n", \
+ d__c->parent->token.s); \
+ } \
+ return; \
+ } \
+ node = d__c; \
+ continue; \
+ } \
+ } \
+ else { \
+ debug_printf(ctx, "%s(missing)\n", is); \
+ } \
+}
+
+static void debug_dump_tree(include_ctx_t *ctx, parse_node_t *root)
+{
+ parse_node_t *current;
+ char *is;
+
+ if (!root) {
+ debug_printf(ctx, " -- Parse Tree empty --\n\n");
+ return;
+ }
+
+ debug_printf(ctx, " ----- Parse Tree -----\n");
+ current = root;
+ is = " ";
+
+ while (current) {
+ switch (current->token.type) {
+ case TOKEN_STRING:
+ case TOKEN_RE:
+ debug_printf(ctx, "%s%s (%s)\n", is, current->token.s,
+ current->token.value);
+ current->dump_done = 1;
+ current = current->parent;
+ continue;
+
+ case TOKEN_NOT:
+ case TOKEN_GROUP:
+ case TOKEN_RBRACE:
+ case TOKEN_LBRACE:
+ if (!current->dump_done) {
+ debug_printf(ctx, "%s%s\n", is, current->token.s);
+ is = apr_pstrcat(ctx->dpool, is, " ", NULL);
+ current->dump_done = 1;
+ }
+
+ DUMP__CHILD(ctx, is, current, right)
+
+ if (!current->right || current->right->dump_done) {
+ is = apr_pstrmemdup(ctx->dpool, is, strlen(is) - 4);
+ if (current->right) current->right->dump_done = 0;
+ current = current->parent;
+ }
+ continue;
+
+ default:
+ if (!current->dump_done) {
+ debug_printf(ctx, "%s%s\n", is, current->token.s);
+ is = apr_pstrcat(ctx->dpool, is, " ", NULL);
+ current->dump_done = 1;
+ }
+
+ DUMP__CHILD(ctx, is, current, left)
+ DUMP__CHILD(ctx, is, current, right)
+
+ if ((!current->left || current->left->dump_done) &&
+ (!current->right || current->right->dump_done)) {
+
+ is = apr_pstrmemdup(ctx->dpool, is, strlen(is) - 4);
+ if (current->left) current->left->dump_done = 0;
+ if (current->right) current->right->dump_done = 0;
+ current = current->parent;
+ }
+ 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
+ */
+ root->dump_done = 0;
+ if (root->left) root->left->dump_done = 0;
+ if (root->right) root->right->dump_done = 0;
+
+ debug_printf(ctx, " --- End Parse Tree ---\n\n");
+
+ return;
+}
+
+#define DEBUG_INIT(ctx, filter, brigade) do { \
+ (ctx)->intern->debug.f = filter; \
+ (ctx)->intern->debug.bb = brigade; \
+} while(0)
+
+#define DEBUG_PRINTF(arg) debug_printf arg
+
+#define DEBUG_DUMP_TOKEN(ctx, token) do { \
+ token_t *d__t = (token); \
+ \
+ if (d__t->type == TOKEN_STRING || d__t->type == TOKEN_RE) { \
+ DEBUG_PRINTF(((ctx), " Found: %s (%s)\n", d__t->s, d__t->value)); \
+ } \
+ else { \
+ DEBUG_PRINTF((ctx, " Found: %s\n", d__t->s)); \
+ } \
+} while(0)
+
+#define DEBUG_DUMP_EVAL(ctx, node) do { \
+ char c = '"'; \
+ switch ((node)->token.type) { \
+ case TOKEN_STRING: \
+ debug_printf((ctx), " Evaluate: %s (%s) -> %c\n", (node)->token.s,\
+ (node)->token.value, ((node)->value) ? '1':'0'); \
+ break; \
+ case TOKEN_AND: \
+ case TOKEN_OR: \
+ debug_printf((ctx), " Evaluate: %s (Left: %s; Right: %s) -> %c\n",\
+ (node)->token.s, \
+ (((node)->left->done) ? ((node)->left->value ?"1":"0") \
+ : "short circuited"), \
+ (((node)->right->done) ? ((node)->right->value?"1":"0") \
+ : "short circuited"), \
+ (node)->value ? '1' : '0'); \
+ break; \
+ case TOKEN_EQ: \
+ case TOKEN_NE: \
+ case TOKEN_GT: \
+ case TOKEN_GE: \
+ case TOKEN_LT: \
+ case TOKEN_LE: \
+ if ((node)->right->token.type == TOKEN_RE) c = '/'; \
+ debug_printf((ctx), " Compare: %s (\"%s\" with %c%s%c) -> %c\n", \
+ (node)->token.s, \
+ (node)->left->token.value, \
+ c, (node)->right->token.value, c, \
+ (node)->value ? '1' : '0'); \
+ break; \
+ default: \
+ debug_printf((ctx), " Evaluate: %s -> %c\n", (node)->token.s, \
+ (node)->value ? '1' : '0'); \
+ break; \
+ } \
+} while(0)
+
+#define DEBUG_DUMP_UNMATCHED(ctx, unmatched) do { \
+ if (unmatched) { \
+ DEBUG_PRINTF(((ctx), " Unmatched %c\n", (char)(unmatched))); \
+ } \
+} while(0)
+
+#define DEBUG_DUMP_COND(ctx, text) \
+ DEBUG_PRINTF(((ctx), "**** %s cond status=\"%c\"\n", (text), \
+ ((ctx)->flags & SSI_FLAG_COND_TRUE) ? '1' : '0'))
+
+#define DEBUG_DUMP_TREE(ctx, root) debug_dump_tree(ctx, root)
+
+#else /* DEBUG_INCLUDE */
+
+#define TYPE_TOKEN(token, ttype) (token)->type = ttype
+
+#define CREATE_NODE(ctx, name) do { \
+ (name) = apr_palloc((ctx)->dpool, sizeof(*(name))); \
+ (name)->parent = (name)->left = (name)->right = NULL; \
+ (name)->done = 0; \
+} while(0)
+
+#define DEBUG_INIT(ctx, f, bb)
+#define DEBUG_PRINTF(arg)
+#define DEBUG_DUMP_TOKEN(ctx, token)
+#define DEBUG_DUMP_EVAL(ctx, node)
+#define DEBUG_DUMP_UNMATCHED(ctx, unmatched)
+#define DEBUG_DUMP_COND(ctx, text)
+#define DEBUG_DUMP_TREE(ctx, root)
+
+#endif /* !DEBUG_INCLUDE */
+
+
/*
* +-------------------------------------------------------+
* | |
const char *ents;
static const char * const entlist[MAXENTLEN + 1] =
{
- NULL, /* 0 */
- NULL, /* 1 */
- "lt\074gt\076", /* 2 */
- "amp\046ETH\320eth\360", /* 3 */
- "quot\042Auml\304Euml\313Iuml\317Ouml\326Uuml\334auml\344euml\353\
-iuml\357ouml\366uuml\374yuml\377", /* 4 */
- "Acirc\302Aring\305AElig\306Ecirc\312Icirc\316Ocirc\324Ucirc\333\
-THORN\336szlig\337acirc\342aring\345aelig\346ecirc\352icirc\356ocirc\364\
-ucirc\373thorn\376", /* 5 */
- "Agrave\300Aacute\301Atilde\303Ccedil\307Egrave\310Eacute\311\
-Igrave\314Iacute\315Ntilde\321Ograve\322Oacute\323Otilde\325Oslash\330\
-Ugrave\331Uacute\332Yacute\335agrave\340aacute\341atilde\343ccedil\347\
-egrave\350eacute\351igrave\354iacute\355ntilde\361ograve\362oacute\363\
-otilde\365oslash\370ugrave\371uacute\372yacute\375" /* 6 */
+ NULL, /* 0 */
+ NULL, /* 1 */
+ "lt\074gt\076", /* 2 */
+ "amp\046ETH\320eth\360", /* 3 */
+ "quot\042Auml\304Euml\313Iuml\317Ouml\326Uuml\334auml\344euml"
+ "\353iuml\357ouml\366uuml\374yuml\377", /* 4 */
+
+ "Acirc\302Aring\305AElig\306Ecirc\312Icirc\316Ocirc\324Ucirc"
+ "\333THORN\336szlig\337acirc\342aring\345aelig\346ecirc\352"
+ "icirc\356ocirc\364ucirc\373thorn\376", /* 5 */
+
+ "Agrave\300Aacute\301Atilde\303Ccedil\307Egrave\310Eacute\311"
+ "Igrave\314Iacute\315Ntilde\321Ograve\322Oacute\323Otilde"
+ "\325Oslash\330Ugrave\331Uacute\332Yacute\335agrave\340"
+ "aacute\341atilde\343ccedil\347egrave\350eacute\351igrave"
+ "\354iacute\355ntilde\361ograve\362oacute\363otilde\365"
+ "oslash\370ugrave\371uacute\372yacute\375" /* 6 */
};
/* Do a fast scan through the string until we find anything
val = ap_ht_time(r->pool, r->finfo.mtime, conf->default_time_fmt, 0);
}
else if (!strcasecmp(var, "USER_NAME")) {
- if (apr_get_username(&val, r->finfo.user, r->pool) != APR_SUCCESS) {
+ if (apr_uid_name_get(&val, r->finfo.user, r->pool) != APR_SUCCESS) {
val = "<unknown>";
}
}
request_rec *r = ctx->intern->r;
if (apr_isdigit(*var) && !var[1]) {
- int idx = *var - '0';
+ apr_size_t idx = *var - '0';
backref_t *re = ctx->intern->re;
/* Handle $0 .. $9 from the last regex evaluated.
* +-------------------------------------------------------+
*/
-static APR_INLINE int re_check(include_ctx_t *ctx, char *string, char *rexp)
+static APR_INLINE int re_check(include_ctx_t *ctx, const char *string,
+ const char *rexp)
{
regex_t *compiled;
backref_t *re = ctx->intern->re;
re = ctx->intern->re = apr_palloc(ctx->pool, sizeof(*re));
}
- re->source = string;
- re->rexp = rexp;
+ re->source = apr_pstrdup(ctx->pool, string);
+ re->rexp = apr_pstrdup(ctx->pool, rexp);
re->nsub = compiled->re_nsub;
rc = !ap_regexec(compiled, string, MAX_NMATCH, re->match, 0);
return rc;
}
-enum token_type {
- 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
-};
-struct token {
- enum token_type type;
- char* value;
-};
-
-static const char *get_ptoken(request_rec *r, const char *string,
- struct token *token, int *unmatched)
+static int get_ptoken(apr_pool_t *pool, const char **parse, token_t *token)
{
- char ch;
- int next = 0;
- char qs = 0;
- int tkn_fnd = 0;
+ const char *p;
+ apr_size_t shift;
+ int unmatched;
token->value = NULL;
- /* Skip leading white space */
- if (string == (char *) NULL) {
- return (char *) NULL;
+ if (!*parse) {
+ return 0;
}
- while ((ch = *string++)) {
- if (!apr_isspace(ch)) {
- break;
- }
+
+ /* Skip leading white space */
+ while (apr_isspace(**parse)) {
+ ++*parse;
}
- if (ch == '\0') {
- return (char *) NULL;
+
+ if (!**parse) {
+ *parse = NULL;
+ return 0;
}
- token->type = token_string; /* the default type */
- switch (ch) {
+ TYPE_TOKEN(token, TOKEN_STRING); /* the default type */
+ p = *parse;
+ unmatched = 0;
+
+ switch (*(*parse)++) {
case '(':
- token->type = token_lbrace;
- return (string);
+ TYPE_TOKEN(token, TOKEN_LBRACE);
+ return 0;
case ')':
- token->type = token_rbrace;
- return (string);
+ TYPE_TOKEN(token, TOKEN_RBRACE);
+ return 0;
case '=':
- token->type = token_eq;
- return (string);
+ if (**parse == '=') ++*parse;
+ TYPE_TOKEN(token, TOKEN_EQ);
+ return 0;
case '!':
- if (*string == '=') {
- token->type = token_ne;
- return (string + 1);
- }
- else {
- token->type = token_not;
- return (string);
+ if (**parse == '=') {
+ TYPE_TOKEN(token, TOKEN_NE);
+ ++*parse;
+ return 0;
}
+ TYPE_TOKEN(token, TOKEN_NOT);
+ return 0;
case '\'':
- /* already token->type == token_string */
- qs = '\'';
+ unmatched = '\'';
break;
case '/':
- token->type = token_re;
- qs = '/';
+ TYPE_TOKEN(token, TOKEN_RE);
+ unmatched = '/';
break;
case '|':
- if (*string == '|') {
- token->type = token_or;
- return (string + 1);
+ if (**parse == '|') {
+ TYPE_TOKEN(token, TOKEN_OR);
+ ++*parse;
+ return 0;
}
break;
case '&':
- if (*string == '&') {
- token->type = token_and;
- return (string + 1);
+ if (**parse == '&') {
+ TYPE_TOKEN(token, TOKEN_AND);
+ ++*parse;
+ return 0;
}
break;
case '>':
- if (*string == '=') {
- token->type = token_ge;
- return (string + 1);
- }
- else {
- token->type = token_gt;
- return (string);
+ if (**parse == '=') {
+ TYPE_TOKEN(token, TOKEN_GE);
+ ++*parse;
+ return 0;
}
+ TYPE_TOKEN(token, TOKEN_GT);
+ return 0;
case '<':
- if (*string == '=') {
- token->type = token_le;
- return (string + 1);
- }
- else {
- token->type = token_lt;
- return (string);
+ if (**parse == '=') {
+ TYPE_TOKEN(token, TOKEN_LE);
+ ++*parse;
+ return 0;
}
- default:
- /* already token->type == token_string */
- break;
- }
- /* We should only be here if we are in a string */
- token->value = apr_palloc(r->pool, strlen(string) + 2); /* 2 for ch plus
- trailing null */
- if (!qs) {
- token->value[next++] = ch;
+ TYPE_TOKEN(token, TOKEN_LT);
+ return 0;
}
- /*
- * I used the ++string throughout this section so that string
- * ends up pointing to the next token and I can just return it
+ /* It's a string or regex token
+ * Now search for the next token, which finishes this string
*/
- for (ch = *string; ((ch != '\0') && (!tkn_fnd)); ch = *++string) {
- if (ch == '\\') {
- if ((ch = *++string) == '\0') {
- tkn_fnd = 1;
- }
- else {
- token->value[next++] = ch;
+ shift = 0;
+ p = *parse = token->value = unmatched ? *parse : p;
+
+ for (; **parse; p = ++*parse) {
+ if (**parse == '\\') {
+ if (!*(++*parse)) {
+ p = *parse;
+ break;
}
+
+ ++shift;
}
else {
- if (!qs) {
- if (apr_isspace(ch)) {
- tkn_fnd = 1;
- }
- else {
- switch (ch) {
- case '(':
- case ')':
- case '=':
- case '!':
- case '<':
- case '>':
- tkn_fnd = 1;
- break;
- case '|':
- if (*(string + 1) == '|') {
- tkn_fnd = 1;
- }
- break;
- case '&':
- if (*(string + 1) == '&') {
- tkn_fnd = 1;
- }
- break;
- }
- if (!tkn_fnd) {
- token->value[next++] = ch;
- }
+ if (unmatched) {
+ if (**parse == unmatched) {
+ unmatched = 0;
+ ++*parse;
+ break;
}
+ } else if (apr_isspace(**parse)) {
+ break;
}
else {
- if (ch == qs) {
- qs = 0;
- tkn_fnd = 1;
- string++;
+ int found = 0;
+
+ switch (**parse) {
+ case '(':
+ case ')':
+ case '=':
+ case '!':
+ case '<':
+ case '>':
+ ++found;
+ break;
+
+ case '|':
+ case '&':
+ if ((*parse)[1] == **parse) {
+ ++found;
+ }
+ break;
}
- else {
- token->value[next++] = ch;
+
+ if (found) {
+ break;
}
}
}
- if (tkn_fnd) {
- break;
- }
}
- /* If qs is still set, we have an unmatched quote */
- if (qs) {
- *unmatched = 1;
- next = 0;
+ if (unmatched) {
+ token->value = apr_pstrdup(pool, "");
}
- token->value[next] = '\0';
+ else {
+ apr_size_t len = p - token->value - shift;
+ char *c = apr_palloc(pool, len + 1);
- return (string);
-}
+ p = token->value;
+ token->value = c;
+ while (shift--) {
+ const char *e = ap_strchr_c(p, '\\');
-/* there is an implicit assumption here that expr is at most MAX_STRING_LEN-1
- * characters long...
- */
-static int parse_expr(request_rec *r, include_ctx_t *ctx, const char *expr,
- int *was_error, int *was_unmatched, char *debug)
+ 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)
{
- struct parse_node {
- struct parse_node *left, *right, *parent;
- struct token token;
- int value, done;
- } *root, *current, *new;
- const char *parse;
- char* buffer;
- int retval = 0;
- apr_size_t debug_pos = 0;
-
- debug[debug_pos] = '\0';
- *was_error = 0;
- *was_unmatched = 0;
- if ((parse = expr) == (char *) NULL) {
- return (0);
- }
- root = current = (struct parse_node *) NULL;
+ parse_node_t *new, *root = NULL, *current = NULL;
+ request_rec *r = ctx->intern->r;
+ 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) {
- new = (struct parse_node *) apr_palloc(r->pool,
- sizeof(struct parse_node));
- new->parent = new->left = new->right = (struct parse_node *) NULL;
- new->done = 0;
- if ((parse = get_ptoken(r, parse, &new->token, was_unmatched)) ==
- (char *) NULL) {
+ /* uncomment this to see how the tree a built:
+ *
+ * DEBUG_DUMP_TREE(ctx, root);
+ */
+ CREATE_NODE(ctx, new);
+
+ was_unmatched = get_ptoken(ctx->dpool, &parse, &new->token);
+ if (!parse) {
break;
}
- switch (new->token.type) {
- case token_string:
-#ifdef DEBUG_INCLUDE
- debug_pos += sprintf (&debug[debug_pos],
- " Token: string (%s)\n",
- new->token.value);
-#endif
- if (current == (struct parse_node *) NULL) {
+ 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_LBRACE:
root = current = new;
- break;
+ 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(r->pool,
- current->token.value,
- current->token.value[0] ? " " : "",
- new->token.value,
- NULL);
-
+ 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;
- case token_eq:
- case token_ne:
- case token_and:
- case token_or:
- case token_lbrace:
- case token_not:
- case token_ge:
- case token_gt:
- case token_le:
- case token_lt:
+
+ default:
new->parent = current;
current = current->right = new;
- break;
- default:
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "Invalid expression \"%s\" in file %s",
- expr, r->filename);
- *was_error = 1;
- return retval;
+ continue;
}
break;
- case token_re:
-#ifdef DEBUG_INCLUDE
- debug_pos += sprintf (&debug[debug_pos],
- " Token: regex (%s)\n",
- new->token.value);
-#endif
- if (current == (struct parse_node *) NULL) {
- root = current = new;
- break;
- }
+ case TOKEN_RE:
switch (current->token.type) {
- case token_eq:
- case token_ne:
- case token_and:
- case token_or:
- case token_lbrace:
- case token_not:
+ case TOKEN_EQ:
+ case TOKEN_NE:
new->parent = current;
current = current->right = new;
- break;
+ ++regex;
+ continue;
+
default:
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "Invalid expression \"%s\" in file %s",
- expr, r->filename);
- *was_error = 1;
- return retval;
+ break;
}
break;
- case token_and:
- case token_or:
-#ifdef DEBUG_INCLUDE
- memcpy (&debug[debug_pos], " Token: and/or\n",
- sizeof (" Token: and/or\n"));
- debug_pos += sizeof (" Token: and/or\n");
-#endif
- if (current == (struct parse_node *) NULL) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "Invalid expression \"%s\" in file %s",
- expr, r->filename);
- *was_error = 1;
- return retval;
- }
- /* Percolate upwards */
- while (current != (struct parse_node *) NULL) {
- switch (current->token.type) {
- case token_string:
- case token_re:
- case token_group:
- case token_not:
- case token_eq:
- case token_ne:
- case token_and:
- case token_or:
- case token_ge:
- case token_gt:
- case token_le:
- case token_lt:
- current = current->parent;
- continue;
- case token_lbrace:
+ 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;
- default:
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "Invalid expression \"%s\" in file %s",
- expr, r->filename);
- *was_error = 1;
- return retval;
}
- break;
- }
- if (current == (struct parse_node *) NULL) {
- new->left = root;
- new->left->parent = new;
- new->parent = (struct parse_node *) NULL;
- root = new;
- }
- else {
- new->left = current->right;
- current->right = new;
- new->parent = current;
- }
- current = new;
- break;
- case token_not:
-#ifdef DEBUG_INCLUDE
- memcpy(&debug[debug_pos], " Token: not\n",
- sizeof(" Token: not\n"));
- debug_pos += sizeof(" Token: not\n");
-#endif
- if (current == (struct parse_node *) NULL) {
- root = current = new;
- break;
- }
- /* Percolate upwards */
- if (current != (struct parse_node *) NULL) {
- switch (current->token.type) {
- case token_not:
- case token_eq:
- case token_ne:
- case token_and:
- case token_or:
- case token_lbrace:
- case token_ge:
- case token_gt:
- case token_le:
- case token_lt:
- break;
- default:
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "Invalid expression \"%s\" in file %s",
- expr, r->filename);
- *was_error = 1;
- return retval;
+ if (!current) {
+ new->left = root;
+ root->parent = new;
+ current = root = new;
+ continue;
}
- }
- if (current == (struct parse_node *) NULL) {
- new->left = root;
- new->left->parent = new;
- new->parent = (struct parse_node *) NULL;
- root = new;
- }
- else {
+
new->left = current->right;
- current->right = new;
+ new->left->parent = new;
new->parent = current;
+ current = current->right = new;
+ continue;
+
+ default:
+ break;
}
- current = new;
break;
- case token_eq:
- case token_ne:
- case token_ge:
- case token_gt:
- case token_le:
- case token_lt:
-#ifdef DEBUG_INCLUDE
- memcpy(&debug[debug_pos], " Token: eq/ne/ge/gt/le/lt\n",
- sizeof(" Token: eq/ne/ge/gt/le/lt\n"));
- debug_pos += sizeof(" Token: eq/ne/ge/gt/le/lt\n");
-#endif
- if (current == (struct parse_node *) NULL) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "Invalid expression \"%s\" in file %s",
- expr, r->filename);
- *was_error = 1;
- return retval;
- }
- /* Percolate upwards */
- while (current != (struct parse_node *) NULL) {
+ 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_string:
- case token_re:
- case token_group:
- current = current->parent;
+ 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;
- case token_lbrace:
- case token_and:
- case token_or:
- break;
- case token_not:
- case token_eq:
- case token_ne:
- case token_ge:
- case token_gt:
- case token_le:
- case token_lt:
+
default:
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "Invalid expression \"%s\" in file %s",
- expr, r->filename);
- *was_error = 1;
- return retval;
+ break;
}
- break;
- }
- if (current == (struct parse_node *) NULL) {
- new->left = root;
- new->left->parent = new;
- new->parent = (struct parse_node *) NULL;
- root = new;
}
- else {
- new->left = current->right;
- current->right = new;
- new->parent = current;
- }
- current = new;
break;
- case token_rbrace:
-#ifdef DEBUG_INCLUDE
- memcpy (&debug[debug_pos], " Token: rbrace\n",
- sizeof (" Token: rbrace\n"));
- debug_pos += sizeof (" Token: rbrace\n");
-#endif
- while (current != (struct parse_node *) NULL) {
- if (current->token.type == token_lbrace) {
- current->token.type = token_group;
- break;
- }
+ case TOKEN_RBRACE:
+ while (current && current->token.type != TOKEN_LBRACE) {
current = current->parent;
}
- if (current == (struct parse_node *) NULL) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "Unmatched ')' in \"%s\" in file %s",
- expr, r->filename);
- *was_error = 1;
- return retval;
+
+ if (current) {
+ TYPE_TOKEN(¤t->token, TOKEN_GROUP);
+ continue;
}
+
+ error = "Unmatched ')' in \"%s\" in file %s";
break;
- case token_lbrace:
-#ifdef DEBUG_INCLUDE
- memcpy (&debug[debug_pos], " Token: lbrace\n",
- sizeof (" Token: lbrace\n"));
- debug_pos += sizeof (" Token: lbrace\n");
-#endif
- if (current == (struct parse_node *) NULL) {
- root = current = new;
+ case TOKEN_NOT:
+ case TOKEN_LBRACE:
+ switch (current->token.type) {
+ case TOKEN_STRING:
+ case TOKEN_RE:
+ case TOKEN_RBRACE:
+ case TOKEN_GROUP:
break;
- }
- /* Percolate upwards */
- if (current != (struct parse_node *) NULL) {
- switch (current->token.type) {
- case token_not:
- case token_eq:
- case token_ne:
- case token_and:
- case token_or:
- case token_lbrace:
- case token_ge:
- case token_gt:
- case token_le:
- case token_lt:
- break;
- case token_string:
- case token_re:
- case token_group:
- default:
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "Invalid expression \"%s\" in file %s",
- expr, r->filename);
- *was_error = 1;
- return retval;
- }
- }
- if (current == (struct parse_node *) NULL) {
- new->left = root;
- new->left->parent = new;
- new->parent = (struct parse_node *) NULL;
- root = new;
- }
- else {
- new->left = current->right;
+
+ default:
current->right = new;
new->parent = current;
+ current = new;
+ continue;
}
- current = new;
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;
- while (current != (struct parse_node *) NULL) {
+ error = NULL;
+ while (current) {
switch (current->token.type) {
- case token_string:
-#ifdef DEBUG_INCLUDE
- memcpy (&debug[debug_pos], " Evaluate string\n",
- sizeof (" Evaluate string\n"));
- debug_pos += sizeof (" Evaluate string\n");
-#endif
- buffer = ap_ssi_parse_string(ctx, current->token.value, NULL,
- MAX_STRING_LEN, 0);
- current->token.value = buffer;
- current->value = (current->token.value[0] != '\0');
- current->done = 1;
- current = current->parent;
+ 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_re:
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "No operator before regex of expr \"%s\" in file %s",
- expr, r->filename);
- *was_error = 1;
- return retval;
-
- case token_and:
- case token_or:
-#ifdef DEBUG_INCLUDE
- memcpy(&debug[debug_pos], " Evaluate and/or\n",
- sizeof(" Evaluate and/or\n"));
- debug_pos += sizeof(" Evaluate and/or\n");
-#endif
- if (current->left == (struct parse_node *) NULL ||
- current->right == (struct parse_node *) NULL) {
+ 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 retval;
+ return 0;
}
+
if (!current->left->done) {
switch (current->left->token.type) {
- case token_string:
- buffer = ap_ssi_parse_string(ctx, current->left->token.value,
- NULL, MAX_STRING_LEN, 0);
- current->left->token.value = buffer;
- current->left->value =
- (current->left->token.value[0] != '\0');
+ 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;
}
}
- if (!current->right->done) {
- switch (current->right->token.type) {
- case token_string:
- buffer = ap_ssi_parse_string(ctx, current->right->token.value,
- NULL, MAX_STRING_LEN, 0);
- current->right->token.value = buffer;
- current->right->value =
- (current->right->token.value[0] != '\0');
- current->right->done = 1;
- break;
- default:
- current = current->right;
- continue;
- }
- }
-#ifdef DEBUG_INCLUDE
- debug_pos += sprintf (&debug[debug_pos], " Left: %c\n",
- current->left->value ? '1' : '0');
- debug_pos += sprintf (&debug[debug_pos], " Right: %c\n",
- current->right->value ? '1' : '0');
-#endif
- if (current->token.type == token_and) {
- current->value = current->left->value && current->right->value;
+
+ /* 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 {
- current->value = current->left->value || current->right->value;
+ 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;
+ }
}
-#ifdef DEBUG_INCLUDE
- debug_pos += sprintf (&debug[debug_pos], " Returning %c\n",
- current->value ? '1' : '0');
-#endif
- current->done = 1;
- current = current->parent;
break;
- case token_eq:
- case token_ne:
-#ifdef DEBUG_INCLUDE
- memcpy (&debug[debug_pos], " Evaluate eq/ne\n",
- sizeof (" Evaluate eq/ne\n"));
- debug_pos += sizeof (" Evaluate eq/ne\n");
-#endif
- if ((current->left == (struct parse_node *) NULL) ||
- (current->right == (struct parse_node *) NULL) ||
- (current->left->token.type != token_string) ||
- ((current->right->token.type != token_string) &&
- (current->right->token.type != token_re))) {
+ 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 retval;
- }
- buffer = ap_ssi_parse_string(ctx, current->left->token.value,
- NULL, MAX_STRING_LEN, 0);
- current->left->token.value = buffer;
- buffer = ap_ssi_parse_string(ctx, current->right->token.value,
- NULL, MAX_STRING_LEN, 0);
- current->right->token.value = buffer;
- if (current->right->token.type == token_re) {
-#ifdef DEBUG_INCLUDE
- debug_pos += sprintf (&debug[debug_pos],
- " Re Compare (%s) with /%s/\n",
- current->left->token.value,
- current->right->token.value);
-#endif
- current->value =
- re_check(ctx, current->left->token.value,
- current->right->token.value);
+ 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 {
-#ifdef DEBUG_INCLUDE
- debug_pos += sprintf (&debug[debug_pos],
- " Compare (%s) with (%s)\n",
- current->left->token.value,
- current->right->token.value);
-#endif
- current->value =
- (strcmp(current->left->token.value,
- current->right->token.value) == 0);
+ current->value = !strcmp(current->left->token.value,
+ current->right->token.value);
}
- if (current->token.type == token_ne) {
+
+ if (current->token.type == TOKEN_NE) {
current->value = !current->value;
}
-#ifdef DEBUG_INCLUDE
- debug_pos += sprintf (&debug[debug_pos], " Returning %c\n",
- current->value ? '1' : '0');
-#endif
- current->done = 1;
- current = current->parent;
break;
- case token_ge:
- case token_gt:
- case token_le:
- case token_lt:
-#ifdef DEBUG_INCLUDE
- memcpy (&debug[debug_pos], " Evaluate ge/gt/le/lt\n",
- sizeof (" Evaluate ge/gt/le/lt\n"));
- debug_pos += sizeof (" Evaluate ge/gt/le/lt\n");
-#endif
- if ((current->left == (struct parse_node *) NULL) ||
- (current->right == (struct parse_node *) NULL) ||
- (current->left->token.type != token_string) ||
- (current->right->token.type != token_string)) {
+
+ 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);
+ "Invalid expression \"%s\" in file %s",
+ expr, r->filename);
*was_error = 1;
- return retval;
- }
- buffer = ap_ssi_parse_string(ctx, current->left->token.value, NULL,
- MAX_STRING_LEN, 0);
- current->left->token.value = buffer;
- buffer = ap_ssi_parse_string(ctx, current->right->token.value, NULL,
- MAX_STRING_LEN, 0);
- current->right->token.value = buffer;
-#ifdef DEBUG_INCLUDE
- debug_pos += sprintf (&debug[debug_pos],
- " Compare (%s) with (%s)\n",
- current->left->token.value,
- current->right->token.value);
-#endif
- current->value =
- strcmp(current->left->token.value,
- current->right->token.value);
- if (current->token.type == token_ge) {
- current->value = current->value >= 0;
+ return 0;
}
- else if (current->token.type == token_gt) {
- current->value = current->value > 0;
- }
- else if (current->token.type == token_le) {
- current->value = current->value <= 0;
- }
- else if (current->token.type == token_lt) {
- current->value = current->value < 0;
- }
- else {
- current->value = 0; /* Don't return -1 if unknown token */
- }
-#ifdef DEBUG_INCLUDE
- debug_pos += sprintf (&debug[debug_pos], " Returning %c\n",
- current->value ? '1' : '0');
-#endif
- current->done = 1;
- current = current->parent;
- break;
- case token_not:
- if (current->right != (struct parse_node *) NULL) {
- if (!current->right->done) {
- current = current->right;
- continue;
- }
- current->value = !current->right->value;
- }
- else {
- current->value = 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 */
}
-#ifdef DEBUG_INCLUDE
- debug_pos += sprintf (&debug[debug_pos], " Evaluate !: %c\n",
- current->value ? '1' : '0');
-#endif
- current->done = 1;
- current = current->parent;
break;
- case token_group:
- if (current->right != (struct parse_node *) NULL) {
+ case TOKEN_NOT:
+ case TOKEN_GROUP:
+ if (current->right) {
if (!current->right->done) {
current = current->right;
continue;
else {
current->value = 1;
}
-#ifdef DEBUG_INCLUDE
- debug_pos += sprintf (&debug[debug_pos], " Evaluate (): %c\n",
- current->value ? '1' : '0');
-#endif
- current->done = 1;
- current = current->parent;
- break;
- case token_lbrace:
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "Unmatched '(' in \"%s\" in file %s",
- expr, r->filename);
- *was_error = 1;
- return retval;
-
- case token_rbrace:
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "Unmatched ')' in \"%s\" in file %s",
- expr, r->filename);
- *was_error = 1;
- return retval;
+ if (current->token.type == TOKEN_NOT) {
+ current->value = !current->value;
+ }
+ 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:
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "bad token type");
+ 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 retval;
+ return 0;
}
+
+ DEBUG_DUMP_EVAL(ctx, current);
+ current->done = 1;
+ current = current->parent;
}
- retval = (root == (struct parse_node *) NULL) ? 0 : root->value;
- return (retval);
+ return (root ? root->value : 0);
}
return;
}
-/* ensure that path is relative, and does not contain ".." elements
- * ensentially ensure that it does not match the regex:
- * (^/|(^|/)\.\.(/|$))
- * XXX: Simply replace with apr_filepath_merge
- */
-static int is_only_below(const char *path)
-{
-#ifdef HAVE_DRIVE_LETTERS
- if (path[1] == ':')
- return 0;
-#endif
-#ifdef NETWARE
- if (ap_strchr_c(path, ':'))
- return 0;
-#endif
- if (path[0] == '/') {
- return 0;
- }
- while (*path) {
- int dots = 0;
- while (path[dots] == '.')
- ++dots;
-#if defined(WIN32)
- /* If the name is canonical this is redundant
- * but in security, redundancy is worthwhile.
- * Does OS2 belong here (accepts ... for ..)?
- */
- if (dots > 1 && (!path[dots] || path[dots] == '/'))
- return 0;
-#else
- if (dots == 2 && (!path[dots] || path[dots] == '/'))
- return 0;
-#endif
- path += dots;
- /* Advance to either the null byte at the end of the
- * string or the character right after the next slash,
- * whichever comes first
- */
- while (*path && (*path++ != '/')) {
- continue;
- }
- }
- return 1;
-}
-
static int find_file(request_rec *r, const char *directive, const char *tag,
char *tag_val, apr_finfo_t *finfo)
{
apr_status_t rv = APR_SUCCESS;
if (!strcmp(tag, "file")) {
- /* XXX: Port to apr_filepath_merge
- * be safe; only files in this directory or below allowed
- */
- if (!is_only_below(tag_val)) {
+ char *newpath;
+
+ /* be safe; only files in this directory or below allowed */
+ rv = apr_filepath_merge(&newpath, NULL, tag_val,
+ APR_FILEPATH_NOTABOVEROOT |
+ APR_FILEPATH_SECUREROOTTEST |
+ APR_FILEPATH_NOTABSOLUTE, r->pool);
+
+ if (!APR_STATUS_IS_SUCCESS(rv)) {
error_fmt = "unable to access file \"%s\" "
"in parsed file %s";
}
else {
- ap_getparents(tag_val); /* get rid of any nasties */
-
/* note: it is okay to pass NULL for the "next filter" since
we never attempt to "run" this sub request. */
- rr = ap_sub_req_lookup_file(tag_val, r, NULL);
+ rr = ap_sub_req_lookup_file(newpath, r, NULL);
if (rr->status == HTTP_OK && rr->finfo.filetype != 0) {
to_send = rr->filename;
return 0;
}
else {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "unable to get information about \"%s\" "
- "in parsed file %s",
- tag_val, r->filename);
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "unable to get "
+ "information about \"%s\" in parsed file %s",
+ tag_val, r->filename);
ap_destroy_sub_req(rr);
return -1;
}
}
else {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "unknown parameter \"%s\" to tag %s in %s",
- tag, directive, r->filename);
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "unknown parameter \"%s\" "
+ "to tag %s in %s", tag, directive, r->filename);
return -1;
}
}
break;
}
- parsed_string = ap_ssi_parse_string(ctx, tag_val, NULL, MAX_STRING_LEN,
+ parsed_string = ap_ssi_parse_string(ctx, tag_val, NULL, 0,
SSI_EXPAND_DROP_NAME);
if (tag[0] == 'f') {
- /* XXX: Port to apr_filepath_merge
- * be safe; only files in this directory or below allowed
- */
- if (!is_only_below(parsed_string)) {
+ char *newpath;
+ apr_status_t rv;
+
+ /* be safe; only files in this directory or below allowed */
+ rv = apr_filepath_merge(&newpath, NULL, tag_val,
+ APR_FILEPATH_NOTABOVEROOT |
+ APR_FILEPATH_SECUREROOTTEST |
+ APR_FILEPATH_NOTABSOLUTE, ctx->dpool);
+
+ if (!APR_STATUS_IS_SUCCESS(rv)) {
error_fmt = "unable to include file \"%s\" in parsed file %s";
}
else {
- rr = ap_sub_req_lookup_uri(parsed_string, r, f->next);
+ rr = ap_sub_req_lookup_file(newpath, r, f->next);
}
}
else {
apr_size_t e_len;
val = get_include_var(ap_ssi_parse_string(ctx, tag_val, NULL,
- MAX_STRING_LEN,
- SSI_EXPAND_DROP_NAME),
+ 0, SSI_EXPAND_DROP_NAME),
ctx);
if (val) {
e_len = strlen(echo_text);
}
else {
- include_server_config *sconf;
-
- sconf = ap_get_module_config(r->server->module_config,
- &include_module);
- echo_text = sconf->undefined_echo;
- e_len = sconf->undefined_echo_len;
+ echo_text = ctx->intern->undefined_echo;
+ e_len = ctx->intern->undefined_echo_len;
}
APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_pool_create(
- apr_pstrmemdup(ctx->pool, echo_text, e_len),
+ apr_pmemdup(ctx->pool, echo_text, e_len),
e_len, ctx->pool, f->c->bucket_alloc));
}
else if (!strcmp(tag, "encoding")) {
}
/*
- * <!--#config [timefmt="..."] [sizefmt="..."] [errmsg="..."] -->
+ * <!--#config [timefmt="..."] [sizefmt="..."] [errmsg="..."]
+ * [echomsg="..."] -->
*/
static apr_status_t handle_config(include_ctx_t *ctx, ap_filter_t *f,
apr_bucket_brigade *bb)
while (1) {
char *tag = NULL;
char *tag_val = NULL;
- char *parsed_string;
ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, SSI_VALUE_RAW);
if (!tag || !tag_val) {
ctx->error_str = ap_ssi_parse_string(ctx, tag_val, NULL, 0,
SSI_EXPAND_DROP_NAME);
}
+ else if (!strcmp(tag, "echomsg")) {
+ ctx->intern->undefined_echo =
+ ap_ssi_parse_string(ctx, tag_val, NULL, 0,SSI_EXPAND_DROP_NAME);
+ ctx->intern->undefined_echo_len=strlen(ctx->intern->undefined_echo);
+ }
else if (!strcmp(tag, "timefmt")) {
apr_time_t date = r->request_time;
ctx->time_str, 0));
}
else if (!strcmp(tag, "sizefmt")) {
- parsed_string = ap_ssi_parse_string(ctx, tag_val, NULL,
- MAX_STRING_LEN,
+ char *parsed_string;
+
+ parsed_string = ap_ssi_parse_string(ctx, tag_val, NULL, 0,
SSI_EXPAND_DROP_NAME);
if (!strcmp(parsed_string, "bytes")) {
ctx->flags |= SSI_FLAG_SIZE_IN_BYTES;
break;
}
- parsed_string = ap_ssi_parse_string(ctx, tag_val, NULL, MAX_STRING_LEN,
+ parsed_string = ap_ssi_parse_string(ctx, tag_val, NULL, 0,
SSI_EXPAND_DROP_NAME);
if (!find_file(r, "fsize", tag, parsed_string, &finfo)) {
break;
}
- parsed_string = ap_ssi_parse_string(ctx, tag_val, NULL, MAX_STRING_LEN,
+ parsed_string = ap_ssi_parse_string(ctx, tag_val, NULL, 0,
SSI_EXPAND_DROP_NAME);
if (!find_file(r, "flastmod", tag, parsed_string, &finfo)) {
{
char *tag = NULL;
char *expr = NULL;
- char debug_buf[MAX_DEBUG_SIZE];
request_rec *r = f->r;
- int expr_ret, was_error, was_unmatched;
+ int expr_ret, was_error;
if (ctx->argc != 1) {
ap_log_rerror(APLOG_MARK,
SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
return APR_SUCCESS;
}
-#ifdef DEBUG_INCLUDE
- do {
- apr_size_t d_len = 0;
- d_len = sprintf(debug_buf, "**** if expr=\"%s\"\n", expr);
- APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_heap_create(debug_buf, d_len,
- NULL, f->c->bucket_alloc));
- } while (0);
-#endif
+ DEBUG_PRINTF((ctx, "**** if expr=\"%s\"\n", expr));
- expr_ret = parse_expr(r, ctx, expr, &was_error, &was_unmatched, debug_buf);
+ expr_ret = parse_expr(ctx, expr, &was_error);
if (was_error) {
SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
return APR_SUCCESS;
}
- if (was_unmatched) {
- DUMP_PARSE_EXPR_DEBUG("\nUnmatched '\n", f, bb);
- }
- DUMP_PARSE_EXPR_DEBUG(debug_buf, f, bb);
-
if (expr_ret) {
ctx->flags |= (SSI_FLAG_PRINTING | SSI_FLAG_COND_TRUE);
}
ctx->flags &= SSI_FLAG_CLEAR_PRINT_COND;
}
- LOG_COND_STATUS(ctx, f, bb, " if");
+ DEBUG_DUMP_COND(ctx, " if");
+
ctx->if_nesting_level = 0;
return APR_SUCCESS;
char *tag = NULL;
char *expr = NULL;
request_rec *r = f->r;
- char debug_buf[MAX_DEBUG_SIZE];
- int expr_ret, was_error, was_unmatched;
+ int expr_ret, was_error;
if (ctx->argc != 1) {
ap_log_rerror(APLOG_MARK,
SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
return APR_SUCCESS;
}
-#ifdef DEBUG_INCLUDE
- do {
- apr_size_t d_len = 0;
- d_len = sprintf(debug_buf, "**** elif expr=\"%s\"\n", expr);
- APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_heap_create(debug_buf, d_len,
- NULL, f->c->bucket_alloc));
- } while (0);
-#endif
- LOG_COND_STATUS(ctx, f, bb, " elif");
+ DEBUG_PRINTF((ctx, "**** elif expr=\"%s\"\n", expr));
+ DEBUG_DUMP_COND(ctx, " elif");
if (ctx->flags & SSI_FLAG_COND_TRUE) {
ctx->flags &= SSI_FLAG_CLEAR_PRINTING;
return APR_SUCCESS;
}
- expr_ret = parse_expr(r, ctx, expr, &was_error, &was_unmatched, debug_buf);
+ expr_ret = parse_expr(ctx, expr, &was_error);
if (was_error) {
SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
return APR_SUCCESS;
}
- if (was_unmatched) {
- DUMP_PARSE_EXPR_DEBUG("\nUnmatched '\n", f, bb);
- }
- DUMP_PARSE_EXPR_DEBUG(debug_buf, f, bb);
-
if (expr_ret) {
ctx->flags |= (SSI_FLAG_PRINTING | SSI_FLAG_COND_TRUE);
}
ctx->flags &= SSI_FLAG_CLEAR_PRINT_COND;
}
- LOG_COND_STATUS(ctx, f, bb, " elif");
+ DEBUG_DUMP_COND(ctx, " elif");
return APR_SUCCESS;
}
return APR_SUCCESS;
}
- LOG_COND_STATUS(ctx, f, bb, " else");
+ DEBUG_DUMP_COND(ctx, " else");
if (ctx->flags & SSI_FLAG_COND_TRUE) {
ctx->flags &= SSI_FLAG_CLEAR_PRINTING;
return APR_SUCCESS;
}
- LOG_COND_STATUS(ctx, f, bb, "endif");
+ DEBUG_DUMP_COND(ctx, "endif");
+
ctx->flags |= (SSI_FLAG_PRINTING | SSI_FLAG_COND_TRUE);
return APR_SUCCESS;
}
if (!strcmp(tag, "var")) {
- var = ap_ssi_parse_string(ctx, tag_val, NULL, MAX_STRING_LEN,
+ var = ap_ssi_parse_string(ctx, tag_val, NULL, 0,
SSI_EXPAND_DROP_NAME);
}
else if (!strcmp(tag, "value")) {
break;
}
- parsed_string = ap_ssi_parse_string(ctx, tag_val, NULL,
- MAX_STRING_LEN,
+ parsed_string = ap_ssi_parse_string(ctx, tag_val, NULL, 0,
SSI_EXPAND_DROP_NAME);
apr_table_setn(r->subprocess_env, apr_pstrdup(p, var),
apr_pstrdup(p, parsed_string));
intern->directive_len);
if (handle_func) {
+ DEBUG_INIT(ctx, f, pass_bb);
rv = handle_func(ctx, f, pass_bb);
if (!APR_STATUS_IS_SUCCESS(rv)) {
apr_brigade_destroy(pass_bb);
strlen(intern->start_seq));
intern->end_seq = sconf->default_end_tag;
intern->end_seq_len = strlen(intern->end_seq);
+ intern->undefined_echo = conf->undefined_echo;
+ intern->undefined_echo_len = strlen(conf->undefined_echo);
}
if ((parent = ap_get_module_config(r->request_config, &include_module))) {
result->default_error_msg = DEFAULT_ERROR_MSG;
result->default_time_fmt = DEFAULT_TIME_FORMAT;
+ result->undefined_echo = DEFAULT_UNDEFINED_ECHO;
result->xbithack = DEFAULT_XBITHACK;
return result;
result = apr_palloc(p, sizeof(include_server_config));
result->default_end_tag = DEFAULT_END_SEQUENCE;
result->default_start_tag = DEFAULT_START_SEQUENCE;
- result->undefined_echo = DEFAULT_UNDEFINED_ECHO;
- result->undefined_echo_len = sizeof(DEFAULT_UNDEFINED_ECHO) - 1;
return result;
}
static const char *set_undefined_echo(cmd_parms *cmd, void *mconfig,
const char *msg)
{
- include_server_config *conf;
-
- conf = ap_get_module_config(cmd->server->module_config, &include_module);
+ include_dir_config *conf = mconfig;
conf->undefined_echo = msg;
- conf->undefined_echo_len = strlen(msg);
return NULL;
}
"SSI Start String Tag"),
AP_INIT_TAKE1("SSIEndTag", set_default_end_tag, NULL, RSRC_CONF,
"SSI End String Tag"),
- AP_INIT_TAKE1("SSIUndefinedEcho", set_undefined_echo, NULL, RSRC_CONF,
+ AP_INIT_TAKE1("SSIUndefinedEcho", set_undefined_echo, NULL, OR_ALL,
"String to be displayed if an echoed variable is undefined"),
{NULL}
};