mod_include.c revision d4241d8dcd4cc3346c1184b7e0748322ba127d14
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding/* ====================================================================
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * The Apache Software License, Version 1.1
b99dbaab171d91e1b664397cc40e039d0c087c65fielding * Copyright (c) 2000-2003 The Apache Software Foundation. All rights
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * reserved.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Redistribution and use in source and binary forms, with or without
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * modification, are permitted provided that the following conditions
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * 1. Redistributions of source code must retain the above copyright
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * notice, this list of conditions and the following disclaimer.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * 2. Redistributions in binary form must reproduce the above copyright
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * notice, this list of conditions and the following disclaimer in
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * the documentation and/or other materials provided with the
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * distribution.
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * 3. The end-user documentation included with the redistribution,
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * if any, must include the following acknowledgment:
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * "This product includes software developed by the
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * Apache Software Foundation (http://www.apache.org/)."
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * Alternately, this acknowledgment may appear in the software itself,
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * if and wherever such third-party acknowledgments normally appear.
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * 4. The names "Apache" and "Apache Software Foundation" must
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * not be used to endorse or promote products derived from this
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * software without prior written permission. For written
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * permission, please contact apache@apache.org.
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * 5. Products derived from this software may not be called "Apache",
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * nor may "Apache" appear in their name, without prior written
64185f9824e42f21ca7b9ae6c004484215c031a7rbb * permission of the Apache Software Foundation.
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * SUCH DAMAGE.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * ====================================================================
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * This software consists of voluntary contributions made by many
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * individuals on behalf of the Apache Software Foundation. For more
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * information on the Apache Software Foundation, please see
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * Portions of this software are based upon public domain software
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * originally written at the National Center for Supercomputing Applications,
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * University of Illinois, Urbana-Champaign.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * http_include.c: Handles the server-parsed HTML documents
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Original by Rob McCool; substantial fixups by David Robinson;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * incorporated into the Apache module framework by rst.
178381ebc820fb4c429aa000240cc8ec42c99c58trawick/* helper for Latin1 <-> entity encoding */
f6e9f5600e77b78fb013bb543d364135961639d1rbb#define RAW_ASCII_CHAR(ch) apr_xlate_conv_byte(ap_hdrs_from_ascii, \
445997e06464e7625c7f0e22917f8f2d9876cfffrbb (unsigned char)ch)
445997e06464e7625c7f0e22917f8f2d9876cfffrbb#else /* APR_CHARSET_EBCDIC */
7c19ce86bbd72bba1d018522250f5f315ffbc0afjerenkrantz#endif /* !APR_CHARSET_EBCDIC */
7c19ce86bbd72bba1d018522250f5f315ffbc0afjerenkrantz * +-------------------------------------------------------+
7c19ce86bbd72bba1d018522250f5f315ffbc0afjerenkrantz * | Types and Structures
7c19ce86bbd72bba1d018522250f5f315ffbc0afjerenkrantz * +-------------------------------------------------------+
7c19ce86bbd72bba1d018522250f5f315ffbc0afjerenkrantz/* sll used for string expansion */
7c19ce86bbd72bba1d018522250f5f315ffbc0afjerenkrantztypedef struct result_item {
7c19ce86bbd72bba1d018522250f5f315ffbc0afjerenkrantz/* conditional expression parser stuff */
7c19ce86bbd72bba1d018522250f5f315ffbc0afjerenkrantztypedef enum {
30b9959208c26420c95d176e457ccc6b5f725194jerenkrantztypedef struct {
30b9959208c26420c95d176e457ccc6b5f725194jerenkrantz const char *value;
441bd066858500e75e4f63ef149120bcf523de58jerenkrantz const char *s;
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingtypedef struct parse_node {
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingtypedef enum {
7c19ce86bbd72bba1d018522250f5f315ffbc0afjerenkrantztypedef struct {
7c19ce86bbd72bba1d018522250f5f315ffbc0afjerenkrantztypedef struct {
7c19ce86bbd72bba1d018522250f5f315ffbc0afjerenkrantz/* main parser states */
7c19ce86bbd72bba1d018522250f5f315ffbc0afjerenkrantztypedef enum {
30b9959208c26420c95d176e457ccc6b5f725194jerenkrantztypedef struct arg_item {
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingtypedef struct {
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz const char *rexp;
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantztypedef struct {
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz unsigned int T[256];
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz unsigned int x;
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz apr_size_t parse_pos; /* parse position of partial matches */
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz char *directive; /* name of the current directive */
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz apr_size_t directive_len; /* length of the current directive name */
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz arg_item_t *current_arg; /* currently parsed argument */
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz backref_t *re; /* NULL if there wasn't a regex yet */
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz * +-------------------------------------------------------+
1627792f516dc22cf12ac193cc48441d0a3701dajerenkrantz * | Debugging Utilities
95ca1a6ff23adde7ae9cbbec7b6754d9aecacc2dbrianp * +-------------------------------------------------------+
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz (name) = apr_palloc((ctx)->dpool, sizeof(*(name))); \
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz (name)->parent = (name)->left = (name)->right = NULL; \
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantzstatic void debug_printf(include_ctx_t *ctx, const char *fmt, ...)
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz APR_BRIGADE_INSERT_TAIL(ctx->intern->debug.bb, apr_bucket_pool_create(
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz#define DUMP__CHILD(ctx, is, node, child) if (1) { \
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz debug_printf(ctx, "!!! Parse tree is not consistent !!!\n"); \
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz debug_printf(ctx, "Parent of " #child " child node is " \
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz "NULL.\n"); \
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz debug_printf(ctx, "Parent of " #child " child node " \
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz "points to another node (of type %s)!\n", \
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantzstatic void debug_dump_tree(include_ctx_t *ctx, parse_node_t *root)
e099672a13ea4ff4a11f130406f1baecba5949bajerenkrantz debug_printf(ctx, "%s%s\n", is, current->token.s);
e099672a13ea4ff4a11f130406f1baecba5949bajerenkrantz is = apr_pstrmemdup(ctx->dpool, is, strlen(is) - 4);
e099672a13ea4ff4a11f130406f1baecba5949bajerenkrantz if (current->right) current->right->dump_done = 0;
e099672a13ea4ff4a11f130406f1baecba5949bajerenkrantz debug_printf(ctx, "%s%s\n", is, current->token.s);
e099672a13ea4ff4a11f130406f1baecba5949bajerenkrantz (!current->right || current->right->dump_done)) {
e099672a13ea4ff4a11f130406f1baecba5949bajerenkrantz is = apr_pstrmemdup(ctx->dpool, is, strlen(is) - 4);
e099672a13ea4ff4a11f130406f1baecba5949bajerenkrantz if (current->left) current->left->dump_done = 0;
e099672a13ea4ff4a11f130406f1baecba5949bajerenkrantz if (current->right) current->right->dump_done = 0;
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz /* it is possible to call this function within the parser loop, to see
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz * how the tree is built. That way, we must cleanup after us to dump
e099672a13ea4ff4a11f130406f1baecba5949bajerenkrantz * always the whole tree
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz debug_printf(ctx, " --- End Parse Tree ---\n\n");
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz if (d__t->type == TOKEN_STRING || d__t->type == TOKEN_RE) { \
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz DEBUG_PRINTF(((ctx), " Found: %s (%s)\n", d__t->s, d__t->value)); \
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz char c = '"'; \
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz debug_printf((ctx), " Evaluate: %s (%s) -> %c\n", (node)->token.s,\
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz (node)->token.value, ((node)->value) ? '1':'0'); \
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz debug_printf((ctx), " Evaluate: %s (Left: %s; Right: %s) -> %c\n",\
e98a7a7acc2861a0987318b2580872d2c8ca1fe2brianp (((node)->left->done) ? ((node)->left->value ?"1":"0") \
e98a7a7acc2861a0987318b2580872d2c8ca1fe2brianp : "short circuited"), \
e98a7a7acc2861a0987318b2580872d2c8ca1fe2brianp (((node)->right->done) ? ((node)->right->value?"1":"0") \
e98a7a7acc2861a0987318b2580872d2c8ca1fe2brianp : "short circuited"), \
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz if ((node)->right->token.type == TOKEN_RE) c = '/'; \
18343797fadabacf01280b38ea7688690d12aec0rbb debug_printf((ctx), " Compare: %s (\"%s\" with %c%s%c) -> %c\n", \
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz debug_printf((ctx), " Evaluate: %s -> %c\n", (node)->token.s, \
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz#define DEBUG_DUMP_UNMATCHED(ctx, unmatched) do { \
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz DEBUG_PRINTF(((ctx), " Unmatched %c\n", (char)(unmatched))); \
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz DEBUG_PRINTF(((ctx), "**** %s cond status=\"%c\"\n", (text), \
f00d1e76bae896c2f6a520eec69b1d0d802d4108jerenkrantz ((ctx)->flags & SSI_FLAG_COND_TRUE) ? '1' : '0'))
18343797fadabacf01280b38ea7688690d12aec0rbb#define DEBUG_DUMP_TREE(ctx, root) debug_dump_tree(ctx, root)
18343797fadabacf01280b38ea7688690d12aec0rbb#else /* DEBUG_INCLUDE */
e099672a13ea4ff4a11f130406f1baecba5949bajerenkrantz#endif /* !DEBUG_INCLUDE */
18343797fadabacf01280b38ea7688690d12aec0rbb * +-------------------------------------------------------+
e099672a13ea4ff4a11f130406f1baecba5949bajerenkrantz * | Static Module Data
e099672a13ea4ff4a11f130406f1baecba5949bajerenkrantz * +-------------------------------------------------------+
e099672a13ea4ff4a11f130406f1baecba5949bajerenkrantz/* global module structure */
e099672a13ea4ff4a11f130406f1baecba5949bajerenkrantz/* function handlers for include directives */
e099672a13ea4ff4a11f130406f1baecba5949bajerenkrantz/* forward declaration of handler registry */
e099672a13ea4ff4a11f130406f1baecba5949bajerenkrantzstatic APR_OPTIONAL_FN_TYPE(ap_register_include_handler) *ssi_pfn_register;
e099672a13ea4ff4a11f130406f1baecba5949bajerenkrantz/* Sentinel value to store in subprocess_env for items that
e099672a13ea4ff4a11f130406f1baecba5949bajerenkrantz * shouldn't be evaluated until/unless they're actually used
e099672a13ea4ff4a11f130406f1baecba5949bajerenkrantzstatic const char lazy_eval_sentinel;
e099672a13ea4ff4a11f130406f1baecba5949bajerenkrantz/* default values */
e099672a13ea4ff4a11f130406f1baecba5949bajerenkrantz#define DEFAULT_ERROR_MSG "[an error occurred while processing this directive]"
e099672a13ea4ff4a11f130406f1baecba5949bajerenkrantz#define DEFAULT_TIME_FORMAT "%A, %d-%b-%Y %H:%M:%S %Z"
18343797fadabacf01280b38ea7688690d12aec0rbb * +-------------------------------------------------------+
18343797fadabacf01280b38ea7688690d12aec0rbb * | Environment/Expansion Functions
18343797fadabacf01280b38ea7688690d12aec0rbb * +-------------------------------------------------------+
18343797fadabacf01280b38ea7688690d12aec0rbb * decodes a string containing html entities or numeric character references.
51ced3b28ef430a96586284d4320f7dbdaf7225ebrianp * 's' is overwritten with the decoded string.
51ced3b28ef430a96586284d4320f7dbdaf7225ebrianp * If 's' is syntatically incorrect, then the followed fixups will be made:
51ced3b28ef430a96586284d4320f7dbdaf7225ebrianp * unknown entities will be left undecoded;
51ced3b28ef430a96586284d4320f7dbdaf7225ebrianp * references to unused numeric characters will be deleted.
51ced3b28ef430a96586284d4320f7dbdaf7225ebrianp * In particular, � will not be decoded, but will be deleted.
51ced3b28ef430a96586284d4320f7dbdaf7225ebrianp/* maximum length of any ISO-LATIN-1 HTML entity name. */
51ced3b28ef430a96586284d4320f7dbdaf7225ebrianp/* The following is a shrinking transformation, therefore safe. */
51ced3b28ef430a96586284d4320f7dbdaf7225ebrianpstatic void decodehtml(char *s)
18343797fadabacf01280b38ea7688690d12aec0rbb int val, i, j;
18343797fadabacf01280b38ea7688690d12aec0rbb const char *ents;
47d7b9019e57fbf3eaa4d2b19bbbcce087dd8389rbb "quot\042Auml\304Euml\313Iuml\317Ouml\326Uuml\334auml\344euml"
f6e9f5600e77b78fb013bb543d364135961639d1rbb "Acirc\302Aring\305AElig\306Ecirc\312Icirc\316Ocirc\324Ucirc"
f6e9f5600e77b78fb013bb543d364135961639d1rbb "\333THORN\336szlig\337acirc\342aring\345aelig\346ecirc\352"
f6e9f5600e77b78fb013bb543d364135961639d1rbb "Agrave\300Aacute\301Atilde\303Ccedil\307Egrave\310Eacute\311"
18343797fadabacf01280b38ea7688690d12aec0rbb "Igrave\314Iacute\315Ntilde\321Ograve\322Oacute\323Otilde"
47d7b9019e57fbf3eaa4d2b19bbbcce087dd8389rbb "\325Oslash\330Ugrave\331Uacute\332Yacute\335agrave\340"
47d7b9019e57fbf3eaa4d2b19bbbcce087dd8389rbb "aacute\341atilde\343ccedil\347egrave\350eacute\351igrave"
f6e9f5600e77b78fb013bb543d364135961639d1rbb "\354iacute\355ntilde\361ograve\362oacute\363otilde\365"
51ced3b28ef430a96586284d4320f7dbdaf7225ebrianp /* Do a fast scan through the string until we find anything
18343797fadabacf01280b38ea7688690d12aec0rbb * that needs more complicated handling
18343797fadabacf01280b38ea7688690d12aec0rbb for (; *s != '&'; s++) {
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz if (*s == '\0') {
18343797fadabacf01280b38ea7688690d12aec0rbb for (p = s; *s != '\0'; s++, p++) {
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz if (*s != '&') {
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz /* find end of entity */
18343797fadabacf01280b38ea7688690d12aec0rbb /* is it numeric ? */
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz for (j = 2, val = 0; j < i && apr_isdigit(s[j]); j++) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (j < i || val <= 8 || (val >= 11 && val <= 31) ||
47d7b9019e57fbf3eaa4d2b19bbbcce087dd8389rbb p--; /* no data to output */
18343797fadabacf01280b38ea7688690d12aec0rbb /* wrong length */
18343797fadabacf01280b38ea7688690d12aec0rbb continue; /* skip it */
18343797fadabacf01280b38ea7688690d12aec0rbb *p = '\0';
18343797fadabacf01280b38ea7688690d12aec0rbbstatic void add_include_vars(request_rec *r, const char *timefmt)
18343797fadabacf01280b38ea7688690d12aec0rbbstatic const char *add_include_vars_lazy(request_rec *r, const char *var)
18343797fadabacf01280b38ea7688690d12aec0rbb (include_dir_config *)ap_get_module_config(r->per_dir_config,
18343797fadabacf01280b38ea7688690d12aec0rbb val = ap_ht_time(r->pool, r->request_time, conf->default_time_fmt, 0);
18343797fadabacf01280b38ea7688690d12aec0rbb (include_dir_config *)ap_get_module_config(r->per_dir_config,
18343797fadabacf01280b38ea7688690d12aec0rbb val = ap_ht_time(r->pool, r->request_time, conf->default_time_fmt, 1);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding (include_dir_config *)ap_get_module_config(r->per_dir_config,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding val = ap_ht_time(r->pool, r->finfo.mtime, conf->default_time_fmt, 0);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (apr_get_username(&val, r->finfo.user, r->pool) != APR_SUCCESS) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic const char *get_include_var(const char *var, include_ctx_t *ctx)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *val;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* Handle $0 .. $9 from the last regex evaluated.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * The choice of returning NULL strings on not-found,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * v.s. empty strings on an empty match is deliberate.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "regex capture $%d "
450fd97bdb54ac69e2cb552f034697a10868be3cbrianp "regex capture $%d is out of range (last regex "
450fd97bdb54ac69e2cb552f034697a10868be3cbrianp if (re->match[idx].rm_so < 0 || re->match[idx].rm_eo < 0) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding val = apr_pstrmemdup(ctx->dpool, re->source + re->match[idx].rm_so,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Do variable substitution on strings
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * (Note: If out==NULL, this function allocs a buffer for the resulting
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * string from ctx->pool. The return value is always the parsed string)
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic char *ap_ssi_parse_string(include_ctx_t *ctx, const char *in, char *out,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *p;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* sanity check, out && !length is not supported */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* fast exit */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ret = apr_pstrmemdup(ctx->pool, in, (length && length <= inlen)
18343797fadabacf01280b38ea7688690d12aec0rbb /* well, actually something to do */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding memcpy(out, in, (out+span <= eout) ? span : (eout-out));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding current = result = apr_palloc(ctx->dpool, sizeof(*result));
18343797fadabacf01280b38ea7688690d12aec0rbb /* loop for specials */
0f6deff8fa9ad63fc576e8d91efc1d9afd068eccbrianp if ((out && out >= eout) || (length && outlen >= length)) {
0f6deff8fa9ad63fc576e8d91efc1d9afd068eccbrianp /* prepare next entry */
47d7b9019e57fbf3eaa4d2b19bbbcce087dd8389rbb current->next = apr_palloc(ctx->dpool, sizeof(*current->next));
18343797fadabacf01280b38ea7688690d12aec0rbb * escaped character
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz if (*p == '\\') {
18343797fadabacf01280b38ea7688690d12aec0rbb * variable expansion
18343797fadabacf01280b38ea7688690d12aec0rbb else { /* *p == '$' */
18343797fadabacf01280b38ea7688690d12aec0rbb if (*++p == '{') {
18343797fadabacf01280b38ea7688690d12aec0rbb ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Missing '}' on "
18343797fadabacf01280b38ea7688690d12aec0rbb if (p < ep) {
18343797fadabacf01280b38ea7688690d12aec0rbb if (p < ep) {
ff2fef0d709ee06646b3462cd3ef39648a54c7f7jwoolley /* empty name results in a copy of '$' in the output string */
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz memcpy(out, val, (out+len <= eout) ? len : (eout-out));
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz if ((out && out >= eout) || (length && outlen >= length)) {
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz /* check the remainder */
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz current->next = apr_palloc(ctx->dpool, sizeof(*current->next));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding memcpy(out, p, (out+span <= eout) ? span : (eout-out));
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz /* assemble result */
445997e06464e7625c7f0e22917f8f2d9876cfffrbb const char *ep;
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz memcpy(out, result->string, (out+result->len <= ep)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * +-------------------------------------------------------+
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz * | Conditional Expression Parser
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz * +-------------------------------------------------------+
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic APR_INLINE int re_check(include_ctx_t *ctx, const char *string,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *rexp)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding compiled = ap_pregcomp(ctx->dpool, rexp, REG_EXTENDED);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->intern->r, "unable to "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding re = ctx->intern->re = apr_palloc(ctx->pool, sizeof(*re));
f7e94f9555c0632e8a290a7e76d778e8c7daf425jerenkrantz rc = !ap_regexec(compiled, string, MAX_NMATCH, re->match, 0);
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic int get_ptoken(apr_pool_t *pool, const char **parse, token_t *token)
50e59a535cafd083838a173aedf9cfa6917d016dwrowe const char *p;
50e59a535cafd083838a173aedf9cfa6917d016dwrowe /* Skip leading white space */
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz TYPE_TOKEN(token, TOKEN_STRING); /* the default type */
18343797fadabacf01280b38ea7688690d12aec0rbb switch (*(*parse)++) {
93780c0e38edba46c1be32fd4c31c344c0a57286jwoolley /* It's a string or regex token
93780c0e38edba46c1be32fd4c31c344c0a57286jwoolley * Now search for the next token, which finishes this string
93780c0e38edba46c1be32fd4c31c344c0a57286jwoolley p = *parse = token->value = unmatched ? *parse : p;
93780c0e38edba46c1be32fd4c31c344c0a57286jwoolley if (!*(++*parse)) {
93780c0e38edba46c1be32fd4c31c344c0a57286jwoolley switch (**parse) {
18343797fadabacf01280b38ea7688690d12aec0rbb while (shift--) {
1f89ef1594d8a552f81e775be55cb9baeab32b77trawick *c++ = *++e;
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic int parse_expr(include_ctx_t *ctx, const char *expr, int *was_error)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char* buffer;
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz unsigned regex = 0;
3a9bc6532fbe8439fc748d8ffedb87415904d16ajim /* Create Parse Tree */
3a9bc6532fbe8439fc748d8ffedb87415904d16ajim while (1) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* uncomment this to see how the tree a built:
18343797fadabacf01280b38ea7688690d12aec0rbb * DEBUG_DUMP_TREE(ctx, root);
18343797fadabacf01280b38ea7688690d12aec0rbb was_unmatched = get_ptoken(ctx->dpool, &parse, &new->token);
7c19ce86bbd72bba1d018522250f5f315ffbc0afjerenkrantz "Invalid expression \"%s\" in file %s",
18343797fadabacf01280b38ea7688690d12aec0rbb "Invalid expression \"%s\" in file %s",
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz "Invalid expression \"%s\" in file %s",
18343797fadabacf01280b38ea7688690d12aec0rbb /* Percolate upwards */
18343797fadabacf01280b38ea7688690d12aec0rbb "Invalid expression \"%s\" in file %s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "Invalid expression \"%s\" in file %s",
5915dc3ebb03935b18b0d14088278d22eefe3553wrowe while (current && current->token.type != TOKEN_LBRACE) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "Unmatched ')' in \"%s\" in file %s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "Invalid expression \"%s\" in file %s",
f54da7877f9e092465df38bfda142f3e71dbb7aawrowe /* Evaluate Parse Tree */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding buffer = ap_ssi_parse_string(ctx, current->token.value, NULL, 0,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "No operator before regex of expr \"%s\" in file %s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "Invalid expression \"%s\" in file %s",
17bdb8862482dff763afd4d86a58de533afff4cajwoolley /* short circuit evaluation */
17bdb8862482dff763afd4d86a58de533afff4cajwoolley ((current->token.type == TOKEN_AND && !current->right->value) ||
17bdb8862482dff763afd4d86a58de533afff4cajwoolley (current->token.type == TOKEN_OR && current->right->value))) {
18343797fadabacf01280b38ea7688690d12aec0rbb "Invalid expression \"%s\" in file %s",
18343797fadabacf01280b38ea7688690d12aec0rbb buffer = ap_ssi_parse_string(ctx, current->left->token.value,
18343797fadabacf01280b38ea7688690d12aec0rbb buffer = ap_ssi_parse_string(ctx, current->right->token.value,
18343797fadabacf01280b38ea7688690d12aec0rbb current->value = re_check(ctx, current->left->token.value,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "Invalid expression \"%s\" in file %s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding buffer = ap_ssi_parse_string(ctx, current->left->token.value, NULL,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding buffer = ap_ssi_parse_string(ctx, current->right->token.value, NULL,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding current->value = strcmp(current->left->token.value,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding current->value = 0; /* Don't return -1 if unknown token */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "Unmatched '(' in \"%s\" in file %s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "Unmatched ')' in \"%s\" in file %s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "bad token type (internal parser error)");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * +-------------------------------------------------------+
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * | Action Handlers
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * +-------------------------------------------------------+
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Extract the next tag name and value.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * If there are no more tags, set the tag name to NULL.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * The tag value is html decoded if dodecode is non-zero.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * The tag value may be NULL if there is no tag value..
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic void ap_ssi_get_tag_and_value(include_ctx_t *ctx, char **tag,
18343797fadabacf01280b38ea7688690d12aec0rbbstatic int find_file(request_rec *r, const char *directive, const char *tag,
18343797fadabacf01280b38ea7688690d12aec0rbb /* be safe; only files in this directory or below allowed */
18343797fadabacf01280b38ea7688690d12aec0rbb "in parsed file %s";
18343797fadabacf01280b38ea7688690d12aec0rbb /* note: it is okay to pass NULL for the "next filter" since
18343797fadabacf01280b38ea7688690d12aec0rbb we never attempt to "run" this sub request. */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding APR_FINFO_GPROT | APR_FINFO_MIN, rr->pool)) != APR_SUCCESS
18343797fadabacf01280b38ea7688690d12aec0rbb "in parsed file %s";
18343797fadabacf01280b38ea7688690d12aec0rbb error_fmt = "unable to lookup information about \"%s\" "
18343797fadabacf01280b38ea7688690d12aec0rbb "in parsed file %s";
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* note: it is okay to pass NULL for the "next filter" since
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding we never attempt to "run" this sub request. */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (rr->status == HTTP_OK && rr->finfo.filetype != 0) {
18343797fadabacf01280b38ea7688690d12aec0rbb ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "unable to get "
18343797fadabacf01280b38ea7688690d12aec0rbb "information about \"%s\" in parsed file %s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "unknown parameter \"%s\" "
18343797fadabacf01280b38ea7688690d12aec0rbb * <!--#include virtual|file="..." [virtual|file="..."] ... -->
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic apr_status_t handle_include(include_ctx_t *ctx, ap_filter_t *f,
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm 0, r, "missing argument for include element in %s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, SSI_VALUE_DECODED);
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz if (strcmp(tag, "virtual") && strcmp(tag, "file")) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "unknown parameter "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding parsed_string = ap_ssi_parse_string(ctx, tag_val, NULL, 0,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* be safe; only files in this directory or below allowed */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding error_fmt = "unable to include file \"%s\" in parsed file %s";
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rr = ap_sub_req_lookup_uri(parsed_string, r, f->next);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding error_fmt = "unable to include \"%s\" in parsed file %s";
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rr->content_type && strncmp(rr->content_type, "text/", 5)) {
b79b743d4cff02d6a830bb7118826a2fd608742amartin error_fmt = "unable to include potential exec \"%s\" in parsed "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* try to avoid recursive includes. We do this by walking
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * up the r->main list of subrequests, and at each level
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * walking back through any internal redirects. At each
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * step, we compare the filenames and the URIs.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * The filename comparison catches a recursive include
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * with an ever-changing URL, eg.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * <!--#include virtual=
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * "$REQUEST_URI/$QUERY_STRING?$QUERY_STRING/x" -->
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * which, although they would eventually be caught because
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * we have a limit on the length of files, etc., can
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * recurse for a while.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * The URI comparison catches the case where the filename
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * is changed while processing the request, so the
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * current name is never the same as any previous one.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * This can happen with "DocumentRoot /foo" when you
b79b743d4cff02d6a830bb7118826a2fd608742amartin * request "/" on the server and it includes "/".
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * This only applies to modules such as mod_dir that
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * (somewhat improperly) mess with r->filename outside
18343797fadabacf01280b38ea7688690d12aec0rbb * of a filename translation phase.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding for (q = p; q; q = q->prev) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding error_fmt = "Recursive include of \"%s\" in parsed file %s";
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* See the Kludge in includes_filter for why.
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz * Basically, it puts a bread crumb in here, then looks
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz * for the crumb later to see if its been here.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_set_module_config(rr->request_config, &include_module, r);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding error_fmt = "unable to include \"%s\" in parsed file %s";
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, error_fmt, tag_val,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* destroy the sub request */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * <!--#echo [encoding="..."] var="..." [encoding="..."] var="..." ... -->
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic apr_status_t handle_echo(include_ctx_t *ctx, ap_filter_t *f,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding 0, r, "missing argument for echo element in %s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, SSI_VALUE_DECODED);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *val;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding val = get_include_var(ap_ssi_parse_string(ctx, tag_val, NULL,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding sconf = ap_get_module_config(r->server->module_config,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_pool_create(
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "unknown value "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "\"%s\" to parameter \"encoding\" of tag echo in "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "unknown parameter "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * <!--#config [timefmt="..."] [sizefmt="..."] [errmsg="..."] -->
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic apr_status_t handle_config(include_ctx_t *ctx, ap_filter_t *f,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding 0, r, "missing argument for config element in %s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding while (1) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, SSI_VALUE_RAW);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ctx->error_str = ap_ssi_parse_string(ctx, tag_val, NULL, 0,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ctx->time_str = ap_ssi_parse_string(ctx, tag_val, NULL, 0,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_table_setn(env, "DATE_LOCAL", ap_ht_time(r->pool, date,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_table_setn(env, "DATE_GMT", ap_ht_time(r->pool, date,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding parsed_string = ap_ssi_parse_string(ctx, tag_val, NULL, 0,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "unknown value "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "\"%s\" to parameter \"sizefmt\" of tag config "
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "unknown parameter "
445997e06464e7625c7f0e22917f8f2d9876cfffrbb * <!--#fsize virtual|file="..." [virtual|file="..."] ... -->
1ccd992d37d62c8cb2056126f2234f64ec189bfddougmstatic apr_status_t handle_fsize(include_ctx_t *ctx, ap_filter_t *f,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding 0, r, "missing argument for fsize element in %s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding while (1) {
18343797fadabacf01280b38ea7688690d12aec0rbb ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, SSI_VALUE_DECODED);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding parsed_string = ap_ssi_parse_string(ctx, tag_val, NULL, 0,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!find_file(r, "fsize", tag, parsed_string, &finfo)) {
18343797fadabacf01280b38ea7688690d12aec0rbb buf = apr_strfsize(finfo.size, apr_palloc(ctx->pool, 5));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding tmp = apr_psprintf(ctx->dpool, "%" APR_OFF_T_FMT, finfo.size);
18343797fadabacf01280b38ea7688690d12aec0rbb for (x = 0; x < l; ++x) {
18343797fadabacf01280b38ea7688690d12aec0rbb if (x && !((l - x) % 3)) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (len == l) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding for (pos = x = 0; x < l; ++x) {
445997e06464e7625c7f0e22917f8f2d9876cfffrbb if (x && !((l - x) % 3)) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_pool_create(buf, len,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * <!--#flastmod virtual|file="..." [virtual|file="..."] ... -->
18343797fadabacf01280b38ea7688690d12aec0rbbstatic apr_status_t handle_flastmod(include_ctx_t *ctx, ap_filter_t *f,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding 0, r, "missing argument for flastmod element in %s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding while (1) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, SSI_VALUE_DECODED);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding parsed_string = ap_ssi_parse_string(ctx, tag_val, NULL, 0,
18343797fadabacf01280b38ea7688690d12aec0rbb if (!find_file(r, "flastmod", tag, parsed_string, &finfo)) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding t_val = ap_ht_time(ctx->pool, finfo.mtime, ctx->time_str, 0);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_pool_create(t_val, t_len,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * <!--#if expr="..." -->
18343797fadabacf01280b38ea7688690d12aec0rbbstatic apr_status_t handle_if(include_ctx_t *ctx, ap_filter_t *f,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ? "too many arguments for if element in %s"
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding : "missing expr argument for if element in %s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_ssi_get_tag_and_value(ctx, &tag, &expr, SSI_VALUE_RAW);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "unknown parameter \"%s\" "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "missing expr value for if "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding DEBUG_PRINTF((ctx, "**** if expr=\"%s\"\n", expr));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ctx->flags |= (SSI_FLAG_PRINTING | SSI_FLAG_COND_TRUE);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * <!--#elif expr="..." -->
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic apr_status_t handle_elif(include_ctx_t *ctx, ap_filter_t *f,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding (!(ctx->if_nesting_level)) ? APLOG_ERR : APLOG_WARNING,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ? "too many arguments for if element in %s"
b79b743d4cff02d6a830bb7118826a2fd608742amartin : "missing expr argument for if element in %s",
18343797fadabacf01280b38ea7688690d12aec0rbb ap_ssi_get_tag_and_value(ctx, &tag, &expr, SSI_VALUE_RAW);
23801cf373ddaff5a5ba7692d2637d75bdffdc4btrawick ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "unknown parameter \"%s\" "
18343797fadabacf01280b38ea7688690d12aec0rbb ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "missing expr in elif "
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz * <!--#else -->
18343797fadabacf01280b38ea7688690d12aec0rbbstatic apr_status_t handle_else(include_ctx_t *ctx, ap_filter_t *f,
18343797fadabacf01280b38ea7688690d12aec0rbb 0, r, "else directive does not take tags in %s",
18343797fadabacf01280b38ea7688690d12aec0rbb * <!--#endif -->
18343797fadabacf01280b38ea7688690d12aec0rbbstatic apr_status_t handle_endif(include_ctx_t *ctx, ap_filter_t *f,
18343797fadabacf01280b38ea7688690d12aec0rbb 0, r, "endif directive does not take tags in %s",
18343797fadabacf01280b38ea7688690d12aec0rbb * <!--#set var="..." value="..." ... -->
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic apr_status_t handle_set(include_ctx_t *ctx, ap_filter_t *f,
b980ad7fdc218b4855cde9f75a747527f50c554dwrowe 0, r, "missing argument for set element in %s",
18343797fadabacf01280b38ea7688690d12aec0rbb /* we need to use the 'main' request pool to set notes as that is
18343797fadabacf01280b38ea7688690d12aec0rbb * a notes lifetime
18343797fadabacf01280b38ea7688690d12aec0rbb while (1) {
18343797fadabacf01280b38ea7688690d12aec0rbb ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, SSI_VALUE_DECODED);
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz var = ap_ssi_parse_string(ctx, tag_val, NULL, 0,
18343797fadabacf01280b38ea7688690d12aec0rbb ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "variable must "
18343797fadabacf01280b38ea7688690d12aec0rbb "precede value in set directive in %s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding parsed_string = ap_ssi_parse_string(ctx, tag_val, NULL, 0,
18343797fadabacf01280b38ea7688690d12aec0rbb ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Invalid tag for set "
18343797fadabacf01280b38ea7688690d12aec0rbb * <!--#printenv -->
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantzstatic apr_status_t handle_printenv(include_ctx_t *ctx, ap_filter_t *f,
18343797fadabacf01280b38ea7688690d12aec0rbb 0, r, "printenv directive does not take tags in %s",
18343797fadabacf01280b38ea7688690d12aec0rbb /* get key */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* get value */
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz val_text = ap_escape_html(ctx->dpool, elts[i].val);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* assemble result */
18343797fadabacf01280b38ea7688690d12aec0rbb APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_pool_create(key_val, kv_length-1,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * +-------------------------------------------------------+
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * | Main Includes-Filter Engine
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz * +-------------------------------------------------------+
18343797fadabacf01280b38ea7688690d12aec0rbb/* This is an implementation of the BNDM search algorithm.
18343797fadabacf01280b38ea7688690d12aec0rbb * Fast and Flexible String Matching by Combining Bit-parallelism and
b980ad7fdc218b4855cde9f75a747527f50c554dwrowe * Suffix Automata (2001)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Gonzalo Navarro, Mathieu Raffinot
18343797fadabacf01280b38ea7688690d12aec0rbb * http://www-igm.univ-mlv.fr/~raffinot/ftp/jea2001.ps.gz
18343797fadabacf01280b38ea7688690d12aec0rbb * Initial code submitted by Sascha Schumann.
18343797fadabacf01280b38ea7688690d12aec0rbb/* Precompile the bndm_t data structure. */
18343797fadabacf01280b38ea7688690d12aec0rbbstatic bndm_t *bndm_compile(apr_pool_t *pool, const char *n, apr_size_t nl)
18343797fadabacf01280b38ea7688690d12aec0rbb unsigned int x;
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz t->T[(unsigned char) *n++] |= x;
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz t->x = x - 1;
18343797fadabacf01280b38ea7688690d12aec0rbb/* Implements the BNDM search algorithm (as described above).
18343797fadabacf01280b38ea7688690d12aec0rbb * h - the string to look in
18343797fadabacf01280b38ea7688690d12aec0rbb * hl - length of the string to look for
b79b743d4cff02d6a830bb7118826a2fd608742amartin * t - precompiled bndm structure against the pattern
18343797fadabacf01280b38ea7688690d12aec0rbb * Returns the count of character that is the first match or hl if no
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * match is found.
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic apr_size_t bndm(bndm_t *t, const char *h, apr_size_t hl)
18343797fadabacf01280b38ea7688690d12aec0rbb const char *skip;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding unsigned int *T, x, d;
445997e06464e7625c7f0e22917f8f2d9876cfffrbb p = pi + nl; /* compare window right to left. point to the first char */
d4f351074a8f7af5e41aa0a70410816436608e3dianh while (p < he) {
93bb0ef3e7e11ddaa69377ac77157b029fa3645dbrianp d &= T[(unsigned char) *p--];
18343797fadabacf01280b38ea7688690d12aec0rbb if ((d & 1)) {
18343797fadabacf01280b38ea7688690d12aec0rbb if (p != pi) {
7c19ce86bbd72bba1d018522250f5f315ffbc0afjerenkrantz return p - h + 1;
93bb0ef3e7e11ddaa69377ac77157b029fa3645dbrianp } while (d);
93bb0ef3e7e11ddaa69377ac77157b029fa3645dbrianp * returns the index position of the first byte of start_seq (or the len of
93bb0ef3e7e11ddaa69377ac77157b029fa3645dbrianp * the buffer as non-match)
18343797fadabacf01280b38ea7688690d12aec0rbbstatic apr_size_t find_start_sequence(include_ctx_t *ctx, const char *data,
18343797fadabacf01280b38ea7688690d12aec0rbb const char *p, *ep;
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz p = data; /* try partial match at the end of the buffer (below) */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* try fast bndm search over the buffer
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * (hopefully the whole start sequence can be found in this buffer)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* wow, found it. ready. */
b980ad7fdc218b4855cde9f75a747527f50c554dwrowe /* ok, the pattern can't be found as whole in the buffer,
b980ad7fdc218b4855cde9f75a747527f50c554dwrowe * check the end for a partial match
18343797fadabacf01280b38ea7688690d12aec0rbb /* found a possible start_seq start */
18343797fadabacf01280b38ea7688690d12aec0rbb if (p < ep) {
18343797fadabacf01280b38ea7688690d12aec0rbb /* partial match found. Store the info for the next round */
18343797fadabacf01280b38ea7688690d12aec0rbb if (p == ep) {
38a4fbdc77aba93aba286e5ba2316d575430b45bjwoolley /* we must try all combinations; consider (e.g.) SSIStartTag "--->"
b980ad7fdc218b4855cde9f75a747527f50c554dwrowe * and a string data of "--.-" and the end of the buffer
18343797fadabacf01280b38ea7688690d12aec0rbb } while (p < ep);
18343797fadabacf01280b38ea7688690d12aec0rbb /* no match */
c0ae62021062bd9e2434c64db6763d22c703d48djwoolley * returns the first byte *after* the partial (or final) match.
c0ae62021062bd9e2434c64db6763d22c703d48djwoolley * If we had to trick with the start_seq start, 'release' returns the
c0ae62021062bd9e2434c64db6763d22c703d48djwoolley * number of chars of the start_seq which appeared not to be part of a
c0ae62021062bd9e2434c64db6763d22c703d48djwoolley * full tag and may have to be passed down the filter chain.
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic apr_size_t find_partial_start_sequence(include_ctx_t *ctx,
18343797fadabacf01280b38ea7688690d12aec0rbb const char *data,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_size_t slen = intern->start_seq_pat->pattern_len;
b980ad7fdc218b4855cde9f75a747527f50c554dwrowe const char *p, *ep;
81e5d74ef38fbf76853e1fbdd95c117e130e473frbb while (p < ep && pos < slen && *p == intern->start_seq[pos]) {
b42a7e46e4f80282bd27e96d43c9510b14ccb9aarbb /* full match */
e099672a13ea4ff4a11f130406f1baecba5949bajerenkrantz return (p - data);
e099672a13ea4ff4a11f130406f1baecba5949bajerenkrantz /* the whole buffer is a partial match */
18343797fadabacf01280b38ea7688690d12aec0rbb if (p == ep) {
18343797fadabacf01280b38ea7688690d12aec0rbb return (p - data);
f6e9f5600e77b78fb013bb543d364135961639d1rbb /* No match so far, but again:
f6e9f5600e77b78fb013bb543d364135961639d1rbb * We must try all combinations, since the start_seq is a random
b980ad7fdc218b4855cde9f75a747527f50c554dwrowe * user supplied string
e099672a13ea4ff4a11f130406f1baecba5949bajerenkrantz * So: look if the first char of start_seq appears somewhere within
e099672a13ea4ff4a11f130406f1baecba5949bajerenkrantz * the current partial match. If it does, try to start a match that
e099672a13ea4ff4a11f130406f1baecba5949bajerenkrantz * begins with this offset. (This can happen, if a strange
18343797fadabacf01280b38ea7688690d12aec0rbb * start_seq like "---->" spans buffers)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* if a matching beginning char was found, try to match the
e099672a13ea4ff4a11f130406f1baecba5949bajerenkrantz * remainder of the old buffer.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* yeah, another partial match found in the *old*
18343797fadabacf01280b38ea7688690d12aec0rbb * buffer, now test the *current* buffer for
18343797fadabacf01280b38ea7688690d12aec0rbb * continuing match
18343797fadabacf01280b38ea7688690d12aec0rbb /* no match at all, release all (wrongly) matched chars so far */
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz * returns the position after the directive
18343797fadabacf01280b38ea7688690d12aec0rbbstatic apr_size_t find_directive(include_ctx_t *ctx, const char *data,
38a4fbdc77aba93aba286e5ba2316d575430b45bjwoolley const char *p = data;
c0ae62021062bd9e2434c64db6763d22c703d48djwoolley /* we have to consider the case of missing space between directive
c0ae62021062bd9e2434c64db6763d22c703d48djwoolley * and end_seq (be somewhat lenient), e.g. <!--#printenv-->
18343797fadabacf01280b38ea7688690d12aec0rbb return (p - data);
53b8cdb3621b11b897438d8990d20e0b78f0d4b7rederpj /* full match, we're done */
f6e9f5600e77b78fb013bb543d364135961639d1rbb /* partial match, the buffer is too small to match fully */
18343797fadabacf01280b38ea7688690d12aec0rbb if (p == ep) {
18343797fadabacf01280b38ea7688690d12aec0rbb /* no match. continue normal parsing */
18343797fadabacf01280b38ea7688690d12aec0rbb /* continue immediately with the next state */
18343797fadabacf01280b38ea7688690d12aec0rbb ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, intern->r, "missing "
c0ae62021062bd9e2434c64db6763d22c703d48djwoolley "directive name in parsed document %s",
c0ae62021062bd9e2434c64db6763d22c703d48djwoolley char *sep = intern->directive + intern->directive_len;
c0ae62021062bd9e2434c64db6763d22c703d48djwoolley /* normalize directive name */
18343797fadabacf01280b38ea7688690d12aec0rbb /* get a rid of a gcc warning about unhandled enumerations */
18343797fadabacf01280b38ea7688690d12aec0rbb return (p - data);
18343797fadabacf01280b38ea7688690d12aec0rbb * find out whether the next token is (a possible) end_seq or an argument
f6e9f5600e77b78fb013bb543d364135961639d1rbbstatic apr_size_t find_arg_or_tail(include_ctx_t *ctx, const char *data,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *p = data;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* skip leading WS */
575c282719040a1614cb5185e61fe4e66d337f1dbrianp /* buffer doesn't consist of whitespaces only */
575c282719040a1614cb5185e61fe4e66d337f1dbrianp if (p < ep) {
575c282719040a1614cb5185e61fe4e66d337f1dbrianp intern->state = (*p == *intern->end_seq) ? PARSE_TAIL : PARSE_ARG;
575c282719040a1614cb5185e61fe4e66d337f1dbrianp return (p - data);
575c282719040a1614cb5185e61fe4e66d337f1dbrianp * test the stream for end_seq. If it doesn't match at all, it must be an
18343797fadabacf01280b38ea7688690d12aec0rbb * argument
18343797fadabacf01280b38ea7688690d12aec0rbbstatic apr_size_t find_tail(include_ctx_t *ctx, const char *data,
18343797fadabacf01280b38ea7688690d12aec0rbb const char *p = data;
c0ae62021062bd9e2434c64db6763d22c703d48djwoolley while (p < ep && pos < intern->end_seq_len && *p == intern->end_seq[pos]) {
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz /* bingo, full match */
81e5d74ef38fbf76853e1fbdd95c117e130e473frbb return (p - data);
18343797fadabacf01280b38ea7688690d12aec0rbb /* partial match, the buffer is too small to match fully */
18343797fadabacf01280b38ea7688690d12aec0rbb return (p - data);
18343797fadabacf01280b38ea7688690d12aec0rbb /* no match. It must be an argument string then
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz * The caller should cleanup and rewind to the reparse point
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz * extract name=value from the buffer
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz * A pcre-pattern could look (similar to):
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz * name\s*(?:=\s*(["'`]?)value\1(?>\s*))?
18343797fadabacf01280b38ea7688690d12aec0rbbstatic apr_size_t find_argument(include_ctx_t *ctx, const char *data,
81e5d74ef38fbf76853e1fbdd95c117e130e473frbb const char *p = data;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * create argument structure and append it to the current list
dfd4950edac888e671b96f62ff5382b7cb350d48rbb /* check whether it's a valid one. If it begins with a quote, we
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * can safely assume, someone forgot the name of the argument
dfd4950edac888e671b96f62ff5382b7cb350d48rbb switch (*p) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, intern->r, "missing "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "argument name for value to tag %s in %s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return (p - data);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* continue immediately with next state */
18343797fadabacf01280b38ea7688690d12aec0rbb return (p - data);
18343797fadabacf01280b38ea7688690d12aec0rbb ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, intern->r, "missing "
18343797fadabacf01280b38ea7688690d12aec0rbb "argument name for value to tag %s in %s",
db4293b97cc224d79164c1c092b0267af5d883c5jerenkrantz /* normalize the name */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* continue with next state immediately */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (*p == '=') {
27338fc39af80f2f0e4a8dbdc90c8a8179a5b2e4rbb else { /* no value */
27338fc39af80f2f0e4a8dbdc90c8a8179a5b2e4rbb return (p - data);
6f4c27ba6e152792f3729069e8d8313ebc87cc60jwoolley /* buffer doesn't consist of whitespaces only */
6f4c27ba6e152792f3729069e8d8313ebc87cc60jwoolley switch (*p) {
ba00c3b7c20f00ce631b89ae3b1cd3bae8d1b165rbb return (p - data);
f6e9f5600e77b78fb013bb543d364135961639d1rbb /* continue with next state immediately */
f6e9f5600e77b78fb013bb543d364135961639d1rbb for (; p < ep; ++p) {
dfd4950edac888e671b96f62ff5382b7cb350d48rbb return (p - data);
dfd4950edac888e671b96f62ff5382b7cb350d48rbb * The value is still the raw input string. Finally clean it up.
dfd4950edac888e671b96f62ff5382b7cb350d48rbb intern->current_arg->value[intern->current_arg->value_len] = '\0';
f6e9f5600e77b78fb013bb543d364135961639d1rbb /* strip quote escaping \ from the string */
ebe70c2684539a5fb2d899241d1601710dfa38a4trawick ep = intern->current_arg->value + intern->current_arg->value_len;
e49758465fbf67f29f9aeda996d09f7cc6fa9fe5rbb intern->current_arg->value[intern->current_arg->value_len] = '\0';
9f794fbe9d98f54c558879173cce489124617c90brianp /* get a rid of a gcc warning about unhandled enumerations */
e49758465fbf67f29f9aeda996d09f7cc6fa9fe5rbb * This is the main loop over the current bucket brigade.
e49758465fbf67f29f9aeda996d09f7cc6fa9fe5rbbstatic apr_status_t send_parsed_content(ap_filter_t *f, apr_bucket_brigade *bb)
a906160166014e14adc01c87a956d89de0d79918rbb /* fast exit */
47d7b9019e57fbf3eaa4d2b19bbbcce087dd8389rbb /* we may crash, since already cleaned up; hand over the responsibility
445997e06464e7625c7f0e22917f8f2d9876cfffrbb * to the next filter;-)
1296b2d30150ccb4ae9f6d690846b4e8f8571fd2rbb /* All stuff passed along has to be put into that brigade */
47d7b9019e57fbf3eaa4d2b19bbbcce087dd8389rbb pass_bb = apr_brigade_create(ctx->pool, f->c->bucket_alloc);
138c8f7cb8254e035c6f45288e3909cd9c21be5cmartin /* initialization for this loop */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* loop over the current bucket brigade */
if (APR_BUCKET_IS_METADATA(b)) {
if (APR_BUCKET_IS_EOS(b)) {
if (APR_BUCKET_IS_FLUSH(b)) {
b = newb;
return rv;
len = 0;
return rv;
b = APR_BUCKET_NEXT(b);
case PARSE_PRE_HEAD:
b = newb;
case PARSE_HEAD:
f->c->bucket_alloc);
b = newb;
case PARSE_DIRECTIVE:
case PARSE_DIRECTIVE_POSTNAME:
case PARSE_DIRECTIVE_TAIL:
case PARSE_DIRECTIVE_POSTTAIL:
if (index) {
if (store) {
if (index) {
b = newb;
else if (index) {
b = newb;
case PARSE_PRE_ARG:
b = newb;
case PARSE_ARG:
case PARSE_ARG_NAME:
case PARSE_ARG_POSTNAME:
case PARSE_ARG_EQ:
case PARSE_ARG_PREVAL:
case PARSE_ARG_VAL:
case PARSE_ARG_VAL_ESC:
case PARSE_ARG_POSTVAL:
if (index) {
if (store) {
if (index) {
b = newb;
else if (index) {
b = newb;
case PARSE_TAIL:
case PARSE_TAIL_SEQ:
b = newb;
b = newb;
case PARSE_EXECUTE:
if (handle_func) {
return rv;
r->filename);
f->c->bucket_alloc));
return rv;
return OK;
request_rec *r = f->r;
if (!f->ctx) {
ap_add_cgi_vars(r);
/* Always unset the ETag/Last-Modified fields - see RFC2616 - 13.3.4.
if (r->args) {
return send_parsed_content(f, b);
return DECLINED;
return DECLINED;
return DECLINED;
return DECLINED;
return DECLINED;
return result;
return result;
return NULL;
const char *tag)
const char *p = tag;
if (apr_isspace(*p)) {
return NULL;
const char *tag)
const char *p = tag;
if (apr_isspace(*p)) {
return NULL;
const char *msg)
return NULL;
const char *msg)
return NULL;
const char *fmt)
return NULL;
if(ssi_pfn_register) {
return OK;
{NULL}