httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From n.@apache.org
Subject cvs commit: httpd-2.0/modules/filters mod_include.c mod_include.h
Date Thu, 21 Aug 2003 22:01:34 GMT
nd          2003/08/21 15:01:34

  Modified:    modules/filters mod_include.c mod_include.h
  Log:
  bump mod_include's external API. The API is now more simple and expected
  to be better extensible without breaking binary compatibility, since an
  opaque pointer to internal structures is part of the public context.
  (We can easily add APi functions that operate on this internal struct).
  
  I've tried to keep this change as small as possible - sorry for the big
  diff though, but the commit should be atomic. mod_cgi and mod_cgid won't
  compile until the next commit, anyway.
  
  Revision  Changes    Path
  1.237     +438 -473  httpd-2.0/modules/filters/mod_include.c
  
  Index: mod_include.c
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/modules/filters/mod_include.c,v
  retrieving revision 1.236
  retrieving revision 1.237
  diff -u -r1.236 -r1.237
  --- mod_include.c	20 Aug 2003 16:41:27 -0000	1.236
  +++ mod_include.c	21 Aug 2003 22:01:33 -0000	1.237
  @@ -92,7 +92,41 @@
   
   #define MOD_INCLUDE_REDESIGN
   #include "mod_include.h"
  +
  +#if APR_CHARSET_EBCDIC
   #include "util_ebcdic.h"
  +#define RAW_ASCII_CHAR(ch)  apr_xlate_conv_byte(ap_hdrs_from_ascii, \
  +                                                (unsigned char)ch)
  +#else /*APR_CHARSET_EBCDIC*/
  +#define RAW_ASCII_CHAR(ch)  (ch)
  +#endif /*APR_CHARSET_EBCDIC*/
  +
  +#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 & 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
   
   module AP_MODULE_DECLARE_DATA include_module;
   static apr_hash_t *include_hash;
  @@ -108,10 +142,10 @@
       xbithack_off, xbithack_on, xbithack_full
   };
   
  -struct bndm_t {
  +typedef struct {
       unsigned int T[256];
       unsigned int x;
  -} ;
  +} bndm_t;
   
   typedef struct {
       char *default_error_msg;
  @@ -158,32 +192,40 @@
       apr_size_t           value_len;
   } ssi_arg_item_t;
   
  -typedef struct {
  +struct ssi_internal_ctx {
       parse_state_t state;
       int           seen_eos;
       int           error;
       char          quote;         /* quote character value (or \0) */
  +    apr_size_t    parse_pos;   /* parse position of partial matches */
  +    apr_size_t    bytes_read;
   
       apr_bucket_brigade *tmp_bb;
   
  +    request_rec  *r;
  +    const char   *start_seq;
  +    bndm_t       *start_seq_pat;
  +    apr_size_t    start_seq_len;
  +    const char   *end_seq;
       apr_size_t    end_seq_len;
       char         *directive;     /* name of the current directive */
  +    apr_size_t    directive_len; /* length of the current directive name */
  +
  +    ssi_arg_item_t   *current_arg;   /* currently parsed argument */
  +    ssi_arg_item_t   *argv;          /* all arguments */
  +
  +    char         *error_str_override;
  +    char         *time_str_override;
  +    char         *re_string;
  +    regmatch_t   (*re_result)[10];
  +};
   
  -    unsigned        argc;        /* argument counter (of the current
  -                                  * directive)
  -                                  */
  -    ssi_arg_item_t *argv;        /* all arguments */
  -    ssi_arg_item_t *current_arg; /* currently parsed argument */
  -    request_rec    *r;
  -    include_ctx_t  *ctx;         /* public part of the context structure */
  -
  -    apr_pool_t     *dpool;
  -} ssi_ctx_t;
  -
  -#define SSI_CREATE_ERROR_BUCKET(ctx, f, bb) APR_BRIGADE_INSERT_TAIL((bb),   \
  -    apr_bucket_pool_create(apr_pstrdup((ctx)->pool, (ctx)->error_str),  \
  -                           strlen((ctx)->error_str), (ctx)->pool,       \
  -                           (f)->c->bucket_alloc))
  +/* some defaults */
  +#define STARTING_SEQUENCE "<!--#"
  +#define ENDING_SEQUENCE "-->"
  +#define DEFAULT_ERROR_MSG "[an error occurred while processing this directive]"
  +#define DEFAULT_TIME_FORMAT "%A, %d-%b-%Y %H:%M:%S %Z"
  +#define DEFAULT_UNDEFINED_ECHO "(none)"
   
   #ifdef XBITHACK
   #define DEFAULT_XBITHACK xbithack_full
  @@ -193,6 +235,16 @@
   
   #define BYTE_COUNT_THRESHOLD AP_MIN_BYTES_TO_WRITE
   
  +/* for better diffs (fixed later): */
  +#define SPLIT_AND_PASS_PRETAG_BUCKETS(a, b, c, d)
  +#define FLAG_PRINTING SSI_FLAG_PRINTING
  +#define FLAG_COND_TRUE SSI_FLAG_COND_TRUE
  +#define FLAG_CLEAR_PRINTING SSI_FLAG_CLEAR_PRINTING
  +#define FLAG_CLEAR_PRINT_COND SSI_FLAG_CLEAR_PRINT_COND
  +#define FLAG_NO_EXEC SSI_FLAG_NO_EXEC
  +#define FLAG_SIZE_IN_BYTES SSI_FLAG_SIZE_IN_BYTES
  +#define FLAG_SIZE_ABBREV SSI_FLAG_SIZE_ABBREV
  +
   /* ------------------------ Environment function -------------------------- */
   
   /* Sentinel value to store in subprocess_env for items that
  @@ -274,19 +326,19 @@
            * The choice of returning NULL strings on not-found,
            * v.s. empty strings on an empty match is deliberate.
            */
  -        if (!ctx->re_result || !ctx->re_string) {
  +        if (!ctx->intern->re_result || !ctx->intern->re_string) {
               return NULL;
           }
           else {
               int idx = atoi(var);
  -            apr_size_t len = (*ctx->re_result)[idx].rm_eo
  -                           - (*ctx->re_result)[idx].rm_so;
  -            if (    (*ctx->re_result)[idx].rm_so < 0
  -                 || (*ctx->re_result)[idx].rm_eo < 0) {
  +            apr_size_t len = (*ctx->intern->re_result)[idx].rm_eo
  +                           - (*ctx->intern->re_result)[idx].rm_so;
  +            if (    (*ctx->intern->re_result)[idx].rm_so < 0
  +                 || (*ctx->intern->re_result)[idx].rm_eo < 0) {
                   return NULL;
               }
  -            val = apr_pstrmemdup(r->pool, ctx->re_string 
  -                                        + (*ctx->re_result)[idx].rm_so, len);
  +            val = apr_pstrmemdup(r->pool, ctx->intern->re_string
  +                                 + (*ctx->intern->re_result)[idx].rm_so, len);
           }
       }
       else {
  @@ -492,32 +544,21 @@
   static void ap_ssi_get_tag_and_value(include_ctx_t *ctx, char **tag,
                                        char **tag_val, int dodecode)
   {
  -    *tag_val = NULL;
  -    if (ctx->curr_tag_pos >= ctx->combined_tag + ctx->tag_length) {
  -        *tag = NULL;
  -        return;
  -    }
  +    char *p;
   
  -    *tag = ctx->curr_tag_pos;
  -    if (!**tag) {
  +    if (!ctx->intern->argv) {
           *tag = NULL;
  -        return;
  -    }
  +        *tag_val = NULL;
   
  -    *tag_val = ap_strchr(*tag, '=');
  -    if (!*tag_val) {
           return;
       }
   
  -    if (*tag_val == *tag) {
  -        *tag = NULL;
  -    }
  +    *tag_val = ctx->intern->argv->value;
  +    p = *tag = ctx->intern->argv->name;
   
  -    **tag_val = '\0';
  -    ++(*tag_val);
  -    ctx->curr_tag_pos = *tag_val + strlen(*tag_val) + 1;
  +    ctx->intern->argv = ctx->intern->argv->next;
   
  -    if (dodecode) {
  +    if (dodecode && *tag_val) {
           decodehtml(*tag_val);
       }
   
  @@ -749,26 +790,25 @@
       return 1;
   }
   
  -static int handle_include(include_ctx_t *ctx, apr_bucket_brigade **bb, 
  -                         request_rec *r, ap_filter_t *f, apr_bucket *head_ptr, 
  -                         apr_bucket **inserted_head)
  +static apr_status_t handle_include(include_ctx_t *ctx, ap_filter_t *f,
  +                                   apr_bucket_brigade *bb)
   {
       char *tag     = NULL;
       char *tag_val = NULL;
       apr_bucket  *tmp_buck;
       char *parsed_string;
       int loglevel = APLOG_ERR;
  +    request_rec *r = f->r;
   
  -    *inserted_head = NULL;
       if (ctx->flags & FLAG_PRINTING) {
           while (1) {
               ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1);
               if (tag_val == NULL) {
                   if (tag == NULL) {
  -                    return (0);
  +                    return APR_SUCCESS;
                   }
                   else {
  -                    return (1);
  +                    return APR_SUCCESS;
                   }
               }
               if (!strcmp(tag, "virtual") || !strcmp(tag, "file")) {
  @@ -867,8 +907,7 @@
                   if (error_fmt) {
                       ap_log_rerror(APLOG_MARK, loglevel,
                                     0, r, error_fmt, tag_val, r->filename);
  -                    CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, 
  -                                        *inserted_head);
  +                    SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
                   }
   
                   /* destroy the sub request */
  @@ -880,17 +919,16 @@
                   ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                               "unknown parameter \"%s\" to tag include in %s",
                               tag, r->filename);
  -                CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head);
  +                SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
               }
           }
       }
  -    return 0;
  +    return APR_SUCCESS;
   }
   
   
  -static int handle_echo(include_ctx_t *ctx, apr_bucket_brigade **bb, 
  -                       request_rec *r, ap_filter_t *f, apr_bucket *head_ptr, 
  -                       apr_bucket **inserted_head)
  +static apr_status_t handle_echo(include_ctx_t *ctx, ap_filter_t *f,
  +                                apr_bucket_brigade *bb)
   {
       char       *tag       = NULL;
       char       *tag_val   = NULL;
  @@ -898,19 +936,19 @@
       apr_bucket  *tmp_buck;
       apr_size_t e_len;
       enum {E_NONE, E_URL, E_ENTITY} encode;
  +    request_rec *r = f->r;
   
       encode = E_ENTITY;
   
  -    *inserted_head = NULL;
       if (ctx->flags & FLAG_PRINTING) {
           while (1) {
               ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1);
               if (tag_val == NULL) {
                   if (tag != NULL) {
  -                    return 1;
  +                    return APR_SUCCESS;
                   }
                   else {
  -                    return 0;
  +                    return APR_SUCCESS;
                   }
               }
               if (!strcmp(tag, "var")) {
  @@ -944,10 +982,7 @@
                                                         sconf->undefinedEchoLen,
                                                         r->pool, c->bucket_alloc);
                   }
  -                APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
  -                if (*inserted_head == NULL) {
  -                    *inserted_head = tmp_buck;
  -                }
  +                APR_BRIGADE_INSERT_TAIL(bb, tmp_buck);
               }
               else if (!strcmp(tag, "encoding")) {
                   if (!strcasecmp(tag_val, "none")) encode = E_NONE;
  @@ -957,64 +992,65 @@
                       ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                              "unknown value \"%s\" to parameter \"encoding\" of "
                              "tag echo in %s", tag_val, r->filename);
  -                    CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, 
  -                                        *inserted_head);
  +                    SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
                   }
               }
               else {
                   ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                               "unknown parameter \"%s\" in tag echo of %s",
                               tag, r->filename);
  -                CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head);
  +                SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
               }
   
           }
       }
  -    return 0;
  +    return APR_SUCCESS;
   }
   
   /* error and tf must point to a string with room for at 
    * least MAX_STRING_LEN characters 
    */
  -static int handle_config(include_ctx_t *ctx, apr_bucket_brigade **bb, 
  -                         request_rec *r, ap_filter_t *f, apr_bucket *head_ptr, 
  -                         apr_bucket **inserted_head)
  +static apr_status_t handle_config(include_ctx_t *ctx, ap_filter_t *f,
  +                                  apr_bucket_brigade *bb)
   {
       char *tag     = NULL;
       char *tag_val = NULL;
       char *parsed_string;
  +    request_rec *r = f->r;
       apr_table_t *env = r->subprocess_env;
   
  -    *inserted_head = NULL;
       if (ctx->flags & FLAG_PRINTING) {
           while (1) {
               ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 0);
               if (tag_val == NULL) {
                   if (tag == NULL) {
  -                    return 0;  /* Reached the end of the string. */
  +                    return APR_SUCCESS;
                   }
                   else {
  -                    return 1;  /* tags must have values. */
  +                    return APR_SUCCESS;
                   }
               }
               if (!strcmp(tag, "errmsg")) {
  -                if (ctx->error_str_override == NULL) {
  -                    ctx->error_str_override = (char *)apr_palloc(ctx->pool,
  -                                                              MAX_STRING_LEN);
  -                    ctx->error_str = ctx->error_str_override;
  +                if (ctx->intern->error_str_override == NULL) {
  +                    ctx->intern->error_str_override = apr_palloc(ctx->pool,
  +                                                                MAX_STRING_LEN);
  +                    ctx->error_str = ctx->intern->error_str_override;
                   }
  -                ap_ssi_parse_string(r, ctx, tag_val, ctx->error_str_override,
  +                ap_ssi_parse_string(r, ctx, tag_val,
  +                                    ctx->intern->error_str_override,
                                       MAX_STRING_LEN, 0);
               }
               else if (!strcmp(tag, "timefmt")) {
                   apr_time_t date = r->request_time;
  -                if (ctx->time_str_override == NULL) {
  -                    ctx->time_str_override = (char *)apr_palloc(ctx->pool,
  -                                                              MAX_STRING_LEN);
  -                    ctx->time_str = ctx->time_str_override;
  +                if (ctx->intern->time_str_override == NULL) {
  +                    ctx->intern->time_str_override = apr_palloc(ctx->pool,
  +                                                                MAX_STRING_LEN);
  +                    ctx->time_str = ctx->intern->time_str_override;
                   }
  -                ap_ssi_parse_string(r, ctx, tag_val, ctx->time_str_override,
  +                ap_ssi_parse_string(r, ctx, tag_val,
  +                                    ctx->intern->time_str_override,
                                       MAX_STRING_LEN, 0);
  +
                   apr_table_setn(env, "DATE_LOCAL", ap_ht_time(r->pool, date, 
                                  ctx->time_str, 0));
                   apr_table_setn(env, "DATE_GMT", ap_ht_time(r->pool, date, 
  @@ -1040,11 +1076,11 @@
                   ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                                 "unknown parameter \"%s\" to tag config in %s",
                                 tag, r->filename);
  -                CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head);
  +                SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
               }
           }
       }
  -    return 0;
  +    return APR_SUCCESS;
   }
   
   
  @@ -1125,9 +1161,8 @@
       }
   }
   
  -static int handle_fsize(include_ctx_t *ctx, apr_bucket_brigade **bb, 
  -                        request_rec *r, ap_filter_t *f, apr_bucket *head_ptr, 
  -                        apr_bucket **inserted_head)
  +static apr_status_t handle_fsize(include_ctx_t *ctx, ap_filter_t *f,
  +                                 apr_bucket_brigade *bb)
   {
       char *tag     = NULL;
       char *tag_val = NULL;
  @@ -1135,17 +1170,17 @@
       apr_size_t  s_len;
       apr_bucket   *tmp_buck;
       char *parsed_string;
  +    request_rec *r = f->r;
   
  -    *inserted_head = NULL;
       if (ctx->flags & FLAG_PRINTING) {
           while (1) {
               ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1);
               if (tag_val == NULL) {
                   if (tag == NULL) {
  -                    return 0;
  +                    return APR_SUCCESS;
                   }
                   else {
  -                    return 1;
  +                    return APR_SUCCESS;
                   }
               }
               else {
  @@ -1182,24 +1217,19 @@
   
                       tmp_buck = apr_bucket_heap_create(buff, s_len, NULL,
                                                     r->connection->bucket_alloc);
  -                    APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
  -                    if (*inserted_head == NULL) {
  -                        *inserted_head = tmp_buck;
  -                    }
  +                    APR_BRIGADE_INSERT_TAIL(bb, tmp_buck);
                   }
                   else {
  -                    CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, 
  -                                        *inserted_head);
  +                    SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
                   }
               }
           }
       }
  -    return 0;
  +    return APR_SUCCESS;
   }
   
  -static int handle_flastmod(include_ctx_t *ctx, apr_bucket_brigade **bb, 
  -                           request_rec *r, ap_filter_t *f, 
  -                           apr_bucket *head_ptr, apr_bucket **inserted_head)
  +static apr_status_t handle_flastmod(include_ctx_t *ctx, ap_filter_t *f,
  +                                    apr_bucket_brigade *bb)
   {
       char *tag     = NULL;
       char *tag_val = NULL;
  @@ -1207,17 +1237,17 @@
       apr_size_t  t_len;
       apr_bucket   *tmp_buck;
       char *parsed_string;
  +    request_rec *r = f->r;
   
  -    *inserted_head = NULL;
       if (ctx->flags & FLAG_PRINTING) {
           while (1) {
               ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1);
               if (tag_val == NULL) {
                   if (tag == NULL) {
  -                    return 0;
  +                    return APR_SUCCESS;
                   }
                   else {
  -                    return 1;
  +                    return APR_SUCCESS;
                   }
               }
               else {
  @@ -1231,26 +1261,22 @@
   
                       tmp_buck = apr_bucket_pool_create(t_val, t_len, r->pool,
                                                     r->connection->bucket_alloc);
  -                    APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
  -                    if (*inserted_head == NULL) {
  -                        *inserted_head = tmp_buck;
  -                    }
  +                    APR_BRIGADE_INSERT_TAIL(bb, tmp_buck);
                   }
                   else {
  -                    CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, 
  -                                        *inserted_head);
  +                    SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
                   }
               }
           }
       }
  -    return 0;
  +    return APR_SUCCESS;
   }
   
   static int re_check(request_rec *r, include_ctx_t *ctx, 
                       char *string, char *rexp)
   {
       regex_t *compiled;
  -    const apr_size_t nres = sizeof(*ctx->re_result) / sizeof(regmatch_t);
  +    const apr_size_t nres = sizeof(*ctx->intern->re_result) / sizeof(regmatch_t);
       int regex_error;
   
       compiled = ap_pregcomp(r->pool, rexp, REG_EXTENDED | REG_NOSUB);
  @@ -1259,11 +1285,11 @@
                         "unable to compile pattern \"%s\"", rexp);
           return -1;
       }
  -    if (!ctx->re_result) {
  -        ctx->re_result = apr_pcalloc(r->pool, sizeof(*ctx->re_result));
  +    if (!ctx->intern->re_result) {
  +        ctx->intern->re_result = apr_pcalloc(r->pool, sizeof(*ctx->intern->re_result));
       }
  -    ctx->re_string = string;
  -    regex_error = ap_regexec(compiled, string, nres, *ctx->re_result, 0);
  +    ctx->intern->re_string = string;
  +    regex_error = ap_regexec(compiled, string, nres, *ctx->intern->re_result, 0);
       ap_pregfree(r->pool, compiled);
       return (!regex_error);
   }
  @@ -2053,6 +2079,7 @@
   }
   
   /*-------------------------------------------------------------------------*/
  +#if 0
   #ifdef DEBUG_INCLUDE
   
   #define MAX_DEBUG_SIZE MAX_STRING_LEN
  @@ -2091,12 +2118,12 @@
   #define DUMP_PARSE_EXPR_DEBUG(t_buck, h_ptr, d_buf, ins_head)
   
   #endif
  +#endif
   /*-------------------------------------------------------------------------*/
   
   /* pjr - These seem to allow expr="fred" expr="joe" where joe overwrites fred. */
  -static int handle_if(include_ctx_t *ctx, apr_bucket_brigade **bb, 
  -                     request_rec *r, ap_filter_t *f, apr_bucket *head_ptr, 
  -                     apr_bucket **inserted_head)
  +static apr_status_t handle_if(include_ctx_t *ctx, ap_filter_t *f,
  +                              apr_bucket_brigade *bb)
   {
       char *tag     = NULL;
       char *tag_val = NULL;
  @@ -2104,8 +2131,8 @@
       int   expr_ret, was_error, was_unmatched;
       apr_bucket *tmp_buck;
       char debug_buf[MAX_DEBUG_SIZE];
  +    request_rec *r = f->r;
   
  -    *inserted_head = NULL;
       if (!(ctx->flags & FLAG_PRINTING)) {
           ctx->if_nesting_level++;
       }
  @@ -2117,34 +2144,29 @@
                       ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                                     "missing expr in if statement: %s", 
                                     r->filename);
  -                    CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, 
  -                                        *inserted_head);
  -                    return 1;
  +                    SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
  +                    return APR_SUCCESS;
                   }
                   expr_ret = parse_expr(r, ctx, expr, &was_error, 
                                         &was_unmatched, debug_buf);
                   if (was_error) {
  -                    CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, 
  -                                        *inserted_head);
  -                    return 1;
  +                    SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
  +                    return APR_SUCCESS;
                   }
                   if (was_unmatched) {
  -                    DUMP_PARSE_EXPR_DEBUG(tmp_buck, head_ptr, 
  -                                          "\nUnmatched '\n", *inserted_head);
  +                    DUMP_PARSE_EXPR_DEBUG("\nUnmatched '\n", f, bb);
                   }
  -                DUMP_PARSE_EXPR_DEBUG(tmp_buck, head_ptr, debug_buf, 
  -                                      *inserted_head);
  -                
  +                DUMP_PARSE_EXPR_DEBUG(debug_buf, f, bb);
  +
                   if (expr_ret) {
                       ctx->flags |= (FLAG_PRINTING | FLAG_COND_TRUE);
                   }
                   else {
                       ctx->flags &= FLAG_CLEAR_PRINT_COND;
                   }
  -                LOG_COND_STATUS(ctx, tmp_buck, head_ptr, *inserted_head, 
  -                                "   if");
  +                LOG_COND_STATUS(ctx, f, bb, "   if");
                   ctx->if_nesting_level = 0;
  -                return 0;
  +                return APR_SUCCESS;
               }
               else if (!strcmp(tag, "expr")) {
                   expr = tag_val;
  @@ -2154,11 +2176,7 @@
                       d_len = sprintf(debug_buf, "**** if expr=\"%s\"\n", expr);
                       tmp_buck = apr_bucket_heap_create(debug_buf, d_len, NULL,
                                                     r->connection->bucket_alloc);
  -                    APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
  -
  -                    if (*inserted_head == NULL) {
  -                        *inserted_head = tmp_buck;
  -                    }
  +                    APR_BRIGADE_INSERT_TAIL(bb, tmp_buck);
                   }
   #endif
               }
  @@ -2166,17 +2184,16 @@
                   ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                               "unknown parameter \"%s\" to tag if in %s", tag, 
                               r->filename);
  -                CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head);
  +                SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
               }
   
           }
       }
  -    return 0;
  +    return APR_SUCCESS;
   }
   
  -static int handle_elif(include_ctx_t *ctx, apr_bucket_brigade **bb, 
  -                       request_rec *r, ap_filter_t *f, apr_bucket *head_ptr, 
  -                       apr_bucket **inserted_head)
  +static apr_status_t handle_elif(include_ctx_t *ctx, ap_filter_t *f,
  +                                apr_bucket_brigade *bb)
   {
       char *tag     = NULL;
       char *tag_val = NULL;
  @@ -2184,40 +2201,35 @@
       int   expr_ret, was_error, was_unmatched;
       apr_bucket *tmp_buck;
       char debug_buf[MAX_DEBUG_SIZE];
  +    request_rec *r = f->r;
   
  -    *inserted_head = NULL;
       if (!ctx->if_nesting_level) {
           while (1) {
               ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 0);
               if (tag == '\0') {
  -                LOG_COND_STATUS(ctx, tmp_buck, head_ptr, *inserted_head, 
  -                                " elif");
  +                LOG_COND_STATUS(ctx, f, bb, " elif");
                   
                   if (ctx->flags & FLAG_COND_TRUE) {
                       ctx->flags &= FLAG_CLEAR_PRINTING;
  -                    return (0);
  +                    return APR_SUCCESS;
                   }
                   if (expr == NULL) {
                       ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                                     "missing expr in elif statement: %s", 
                                     r->filename);
  -                    CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, 
  -                                        *inserted_head);
  -                    return (1);
  +                    SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
  +                    return APR_SUCCESS;
                   }
                   expr_ret = parse_expr(r, ctx, expr, &was_error, 
                                         &was_unmatched, debug_buf);
                   if (was_error) {
  -                    CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, 
  -                                        *inserted_head);
  -                    return 1;
  +                    SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
  +                    return APR_SUCCESS;
                   }
                   if (was_unmatched) {
  -                    DUMP_PARSE_EXPR_DEBUG(tmp_buck, head_ptr, 
  -                                          "\nUnmatched '\n", *inserted_head);
  +                    DUMP_PARSE_EXPR_DEBUG("\nUnmatched '\n", f, bb);
                   }
  -                DUMP_PARSE_EXPR_DEBUG(tmp_buck, head_ptr, debug_buf, 
  -                                      *inserted_head);
  +                DUMP_PARSE_EXPR_DEBUG(debug_buf, f, bb);
                   
                   if (expr_ret) {
                       ctx->flags |= (FLAG_PRINTING | FLAG_COND_TRUE);
  @@ -2225,9 +2237,8 @@
                   else {
                       ctx->flags &= FLAG_CLEAR_PRINT_COND;
                   }
  -                LOG_COND_STATUS(ctx, tmp_buck, head_ptr, *inserted_head, 
  -                                " elif");
  -                return (0);
  +                LOG_COND_STATUS(ctx, f, bb, " elif");
  +                return APR_SUCCESS;
               }
               else if (!strcmp(tag, "expr")) {
                   expr = tag_val;
  @@ -2237,11 +2248,7 @@
                       d_len = sprintf(debug_buf, "**** elif expr=\"%s\"\n", expr);
                       tmp_buck = apr_bucket_heap_create(debug_buf, d_len, NULL,
                                                     r->connection->bucket_alloc);
  -                    APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
  -
  -                    if (*inserted_head == NULL) {
  -                        *inserted_head = tmp_buck;
  -                    }
  +                    APR_BRIGADE_INSERT_TAIL(bb, tmp_buck);
                   }
   #endif
               }
  @@ -2249,34 +2256,33 @@
                   ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                                  "unknown parameter \"%s\" to tag if in %s", tag, 
                                  r->filename);
  -                CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head);
  +                SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
               }
           }
       }
  -    return 0;
  +    return APR_SUCCESS;
   }
   
  -static int handle_else(include_ctx_t *ctx, apr_bucket_brigade **bb, 
  -                       request_rec *r, ap_filter_t *f, apr_bucket *head_ptr, 
  -                       apr_bucket **inserted_head)
  +static apr_status_t handle_else(include_ctx_t *ctx, ap_filter_t *f,
  +                                apr_bucket_brigade *bb)
   {
       char *tag = NULL;
       char *tag_val = NULL;
       apr_bucket *tmp_buck;
  +    request_rec *r = f->r;
   
  -    *inserted_head = NULL;
       if (!ctx->if_nesting_level) {
           ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1);
           if ((tag != NULL) || (tag_val != NULL)) {
               ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                           "else directive does not take tags in %s", r->filename);
               if (ctx->flags & FLAG_PRINTING) {
  -                CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head);
  +                SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
               }
  -            return -1;
  +            return APR_SUCCESS;
           }
           else {
  -            LOG_COND_STATUS(ctx, tmp_buck, head_ptr, *inserted_head, " else");
  +            LOG_COND_STATUS(ctx, f, bb, " else");
               
               if (ctx->flags & FLAG_COND_TRUE) {
                   ctx->flags &= FLAG_CLEAR_PRINTING;
  @@ -2284,50 +2290,49 @@
               else {
                   ctx->flags |= (FLAG_PRINTING | FLAG_COND_TRUE);
               }
  -            return 0;
  +            return APR_SUCCESS;
           }
       }
  -    return 0;
  +    return APR_SUCCESS;
   }
   
  -static int handle_endif(include_ctx_t *ctx, apr_bucket_brigade **bb, 
  -                        request_rec *r, ap_filter_t *f, apr_bucket *head_ptr, 
  -                        apr_bucket **inserted_head)
  +static apr_status_t handle_endif(include_ctx_t *ctx, ap_filter_t *f,
  +                                 apr_bucket_brigade *bb)
   {
       char *tag     = NULL;
       char *tag_val = NULL;
       apr_bucket *tmp_buck;
  +    request_rec *r = f->r;
   
  -    *inserted_head = NULL;
       if (!ctx->if_nesting_level) {
           ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1);
           if ((tag != NULL) || (tag_val != NULL)) {
               ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                          "endif directive does not take tags in %s", r->filename);
  -            CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head);
  -            return -1;
  +            SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
  +            return APR_SUCCESS;
           }
           else {
  -            LOG_COND_STATUS(ctx, tmp_buck, head_ptr, *inserted_head, "endif");
  +            LOG_COND_STATUS(ctx, f, bb, "endif");
               ctx->flags |= (FLAG_PRINTING | FLAG_COND_TRUE);
  -            return 0;
  +            return APR_SUCCESS;
           }
       }
       else {
           ctx->if_nesting_level--;
  -        return 0;
  +        return APR_SUCCESS;
       }
   }
   
  -static int handle_set(include_ctx_t *ctx, apr_bucket_brigade **bb, 
  -                      request_rec *r, ap_filter_t *f, apr_bucket *head_ptr, 
  -                      apr_bucket **inserted_head)
  +static apr_status_t handle_set(include_ctx_t *ctx, ap_filter_t *f,
  +                               apr_bucket_brigade *bb)
   {
       char *tag     = NULL;
       char *tag_val = NULL;
       char *var     = NULL;
       apr_bucket *tmp_buck;
       char *parsed_string;
  +    request_rec *r = f->r;
       request_rec *sub = r->main;
       apr_pool_t *p = r->pool;
   
  @@ -2339,15 +2344,14 @@
           sub = sub->main;
       }
   
  -    *inserted_head = NULL;
       if (ctx->flags & FLAG_PRINTING) {
           while (1) {
               ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1);
               if ((tag == NULL) && (tag_val == NULL)) {
  -                return 0;
  +                return APR_SUCCESS;
               }
               else if (tag_val == NULL) {
  -                return 1;
  +                return APR_SUCCESS;
               }
               else if (!strcmp(tag, "var")) {
                   var = ap_ssi_parse_string(r, ctx, tag_val, NULL,
  @@ -2358,9 +2362,8 @@
                       ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                              "variable must precede value in set directive in %s",
                              r->filename);
  -                    CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, 
  -                                        *inserted_head);
  -                    return (-1);
  +                    SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
  +                    return APR_SUCCESS;
                   }
                   parsed_string = ap_ssi_parse_string(r, ctx, tag_val, NULL, 
                                                       MAX_STRING_LEN, 0);
  @@ -2370,21 +2373,21 @@
               else {
                   ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                               "Invalid tag for set directive in %s", r->filename);
  -                CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head);
  -                return -1;
  +                SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
  +                return APR_SUCCESS;
               }
           }
       }
  -    return 0;
  +    return APR_SUCCESS;
   }
   
  -static int handle_printenv(include_ctx_t *ctx, apr_bucket_brigade **bb, 
  -                           request_rec *r, ap_filter_t *f, 
  -                           apr_bucket *head_ptr, apr_bucket **inserted_head)
  +static apr_status_t handle_printenv(include_ctx_t *ctx, ap_filter_t *f,
  +                                    apr_bucket_brigade *bb)
   {
       char *tag     = NULL;
       char *tag_val = NULL;
       apr_bucket *tmp_buck;
  +    request_rec *r = f->r;
   
       if (ctx->flags & FLAG_PRINTING) {
           ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1);
  @@ -2396,7 +2399,6 @@
               char *key_val, *next;
               apr_size_t   k_len, v_len, kv_length;
   
  -            *inserted_head = NULL;
               for (i = 0; i < arr->nelts; ++i) {
                   key_text = ap_escape_html(r->pool, elts[i].key);
                   val_text = elts[i].val;
  @@ -2419,22 +2421,19 @@
                   tmp_buck = apr_bucket_pool_create(key_val, kv_length - 1,
                                                     r->pool,
                                                     r->connection->bucket_alloc);
  -                APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
  -                if (*inserted_head == NULL) {
  -                    *inserted_head = tmp_buck;
  -                }
  +                APR_BRIGADE_INSERT_TAIL(bb, tmp_buck);
               }
  -            return 0;
  +            return APR_SUCCESS;
           }
           else {
               ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                           "printenv directive does not take tags in %s", 
                           r->filename);
  -            CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head);
  -            return -1;
  +            SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
  +            return APR_SUCCESS;
           }
       }
  -    return 0;
  +    return APR_SUCCESS;
   }
   
   /* -------------------------- The main function --------------------------- */
  @@ -2443,10 +2442,11 @@
    * returns the index position of the first byte of start_seq (or the len of
    * the buffer as non-match)
    */
  -static apr_size_t find_start_sequence(ssi_ctx_t *ctx, const char *data,
  +static apr_size_t find_start_sequence(include_ctx_t *ctx, const char *data,
                                         apr_size_t len)
   {
  -    apr_size_t slen = ctx->ctx->start_seq_len;
  +    struct ssi_internal_ctx *intern = ctx->intern;
  +    apr_size_t slen = intern->start_seq_len;
       apr_size_t index;
       const char *p, *ep;
   
  @@ -2457,12 +2457,12 @@
           /* try fast bndm search over the buffer
            * (hopefully the whole start sequence can be found in this buffer)
            */
  -        index = bndm(ctx->ctx->start_seq, ctx->ctx->start_seq_len, data, len,
  -                     ctx->ctx->start_seq_pat);
  +        index = bndm(intern->start_seq, intern->start_seq_len, data, len,
  +                     intern->start_seq_pat);
   
           /* wow, found it. ready. */
           if (index < len) {
  -            ctx->state = PARSE_DIRECTIVE;
  +            intern->state = PARSE_DIRECTIVE;
               return index;
           }
           else {
  @@ -2475,7 +2475,7 @@
   
       ep = data + len;
       do {
  -        while (p < ep && *p != *ctx->ctx->start_seq) {
  +        while (p < ep && *p != *intern->start_seq) {
               ++p;
           }
   
  @@ -2486,15 +2486,15 @@
               apr_size_t pos = 1;
   
               ++p;
  -            while (p < ep && *p == ctx->ctx->start_seq[pos]) {
  +            while (p < ep && *p == intern->start_seq[pos]) {
                   ++p;
                   ++pos;
               }
   
               /* partial match found. Store the info for the next round */
               if (p == ep) {
  -                ctx->state = PARSE_HEAD;
  -                ctx->ctx->parse_pos = pos;
  +                intern->state = PARSE_HEAD;
  +                intern->parse_pos = pos;
                   return index;
               }
           }
  @@ -2516,36 +2516,37 @@
    * number of chars of the start_seq which appeared not to be part of a
    * full tag and may have to be passed down the filter chain.
    */
  -static apr_size_t find_partial_start_sequence(ssi_ctx_t *ctx,
  +static apr_size_t find_partial_start_sequence(include_ctx_t *ctx,
                                                 const char *data,
                                                 apr_size_t len,
                                                 apr_size_t *release)
   {
  +    struct ssi_internal_ctx *intern = ctx->intern;
       apr_size_t pos, spos = 0;
  -    apr_size_t slen = ctx->ctx->start_seq_len;
  +    apr_size_t slen = intern->start_seq_len;
       const char *p, *ep;
   
  -    pos = ctx->ctx->parse_pos;
  +    pos = intern->parse_pos;
       ep = data + len;
       *release = 0;
   
       do {
           p = data;
   
  -        while (p < ep && pos < slen && *p == ctx->ctx->start_seq[pos]) {
  +        while (p < ep && pos < slen && *p == intern->start_seq[pos]) {
               ++p;
               ++pos;
           }
   
           /* full match */
           if (pos == slen) {
  -            ctx->state = PARSE_DIRECTIVE;
  +            intern->state = PARSE_DIRECTIVE;
               return (p - data);
           }
   
           /* the whole buffer is a partial match */
           if (p == ep) {
  -            ctx->ctx->parse_pos = pos;
  +            intern->parse_pos = pos;
               return (p - data);
           }
   
  @@ -2558,14 +2559,14 @@
            * begins with this offset. (This can happen, if a strange
            * start_seq like "---->" spans buffers)
            */
  -        if (spos < ctx->ctx->parse_pos) {
  +        if (spos < intern->parse_pos) {
               do {
                   ++spos;
                   ++*release;
  -                p = ctx->ctx->start_seq + spos;
  -                pos = ctx->ctx->parse_pos - spos;
  +                p = intern->start_seq + spos;
  +                pos = intern->parse_pos - spos;
   
  -                while (pos && *p != *ctx->ctx->start_seq) {
  +                while (pos && *p != *intern->start_seq) {
                       ++p;
                       ++spos;
                       ++*release;
  @@ -2579,7 +2580,7 @@
                       apr_size_t t = 1;
   
                       ++p;
  -                    while (t < pos && *p == ctx->ctx->start_seq[t]) {
  +                    while (t < pos && *p == intern->start_seq[t]) {
                           ++p;
                           ++t;
                       }
  @@ -2603,31 +2604,32 @@
       } while (1); /* work hard to find a match ;-) */
   
       /* no match at all, release all (wrongly) matched chars so far */
  -    *release = ctx->ctx->parse_pos;
  -    ctx->state = PARSE_PRE_HEAD;
  +    *release = intern->parse_pos;
  +    intern->state = PARSE_PRE_HEAD;
       return 0;
   }
   
   /*
    * returns the position after the directive
    */
  -static apr_size_t find_directive(ssi_ctx_t *ctx, const char *data,
  +static apr_size_t find_directive(include_ctx_t *ctx, const char *data,
                                    apr_size_t len, char ***store,
                                    apr_size_t **store_len)
   {
  +    struct ssi_internal_ctx *intern = ctx->intern;
       const char *p = data;
       const char *ep = data + len;
       apr_size_t pos;
   
  -    switch (ctx->state) {
  +    switch (intern->state) {
       case PARSE_DIRECTIVE:
           while (p < ep && !apr_isspace(*p)) {
               /* we have to consider the case of missing space between directive
                * and end_seq (be somewhat lenient), e.g. <!--#printenv-->
                */
  -            if (*p == *ctx->ctx->end_seq) {
  -                ctx->state = PARSE_DIRECTIVE_TAIL;
  -                ctx->ctx->parse_pos = 1;
  +            if (*p == *intern->end_seq) {
  +                intern->state = PARSE_DIRECTIVE_TAIL;
  +                intern->parse_pos = 1;
                   ++p;
                   return (p - data);
               }
  @@ -2635,60 +2637,61 @@
           }
   
           if (p < ep) { /* found delimiter whitespace */
  -            ctx->state = PARSE_DIRECTIVE_POSTNAME;
  -            *store = &ctx->directive;
  -            *store_len = &ctx->ctx->directive_length;
  +            intern->state = PARSE_DIRECTIVE_POSTNAME;
  +            *store = &intern->directive;
  +            *store_len = &intern->directive_len;
           }
   
           break;
   
       case PARSE_DIRECTIVE_TAIL:
  -        pos = ctx->ctx->parse_pos;
  +        pos = intern->parse_pos;
   
  -        while (p < ep && pos < ctx->end_seq_len &&
  -               *p == ctx->ctx->end_seq[pos]) {
  +        while (p < ep && pos < intern->end_seq_len &&
  +               *p == intern->end_seq[pos]) {
               ++p;
               ++pos;
           }
   
           /* full match, we're done */
  -        if (pos == ctx->end_seq_len) {
  -            ctx->state = PARSE_DIRECTIVE_POSTTAIL;
  -            *store = &ctx->directive;
  -            *store_len = &ctx->ctx->directive_length;
  +        if (pos == intern->end_seq_len) {
  +            intern->state = PARSE_DIRECTIVE_POSTTAIL;
  +            *store = &intern->directive;
  +            *store_len = &intern->directive_len;
               break;
           }
   
           /* partial match, the buffer is too small to match fully */
           if (p == ep) {
  -            ctx->ctx->parse_pos = pos;
  +            intern->parse_pos = pos;
               break;
           }
   
           /* no match. continue normal parsing */
  -        ctx->state = PARSE_DIRECTIVE;
  +        intern->state = PARSE_DIRECTIVE;
           return 0;
   
       case PARSE_DIRECTIVE_POSTTAIL:
  -        ctx->state = PARSE_EXECUTE;
  -        ctx->ctx->directive_length -= ctx->end_seq_len;
  +        intern->state = PARSE_EXECUTE;
  +        intern->directive_len -= intern->end_seq_len;
           /* continue immediately with the next state */
   
       case PARSE_DIRECTIVE_POSTNAME:
  -        if (PARSE_DIRECTIVE_POSTNAME == ctx->state) {
  -            ctx->state = PARSE_PRE_ARG;
  +        if (PARSE_DIRECTIVE_POSTNAME == intern->state) {
  +            intern->state = PARSE_PRE_ARG;
           }
           ctx->argc = 0;
  -        ctx->argv = NULL;
  +        intern->argv = NULL;
   
  -        if (!ctx->ctx->directive_length) {
  -            ctx->error = 1;
  -            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->r, "missing directive "
  -                          "name in parsed document %s", ctx->r->filename);
  +        if (!intern->directive_len) {
  +            intern->error = 1;
  +            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, intern->r, "missing "
  +                          "directive name in parsed document %s",
  +                          intern->r->filename);
           }
           else {
  -            char *sp = ctx->directive;
  -            char *sep = ctx->directive + ctx->ctx->directive_length;
  +            char *sp = intern->directive;
  +            char *sep = intern->directive + intern->directive_len;
   
               /* normalize directive name */
               for (; sp < sep; ++sp) {
  @@ -2709,9 +2712,10 @@
   /*
    * find out whether the next token is (a possible) end_seq or an argument
    */
  -static apr_size_t find_arg_or_tail(ssi_ctx_t *ctx, const char *data,
  +static apr_size_t find_arg_or_tail(include_ctx_t *ctx, const char *data,
                                      apr_size_t len)
   {
  +    struct ssi_internal_ctx *intern = ctx->intern;
       const char *p = data;
       const char *ep = data + len;
   
  @@ -2722,7 +2726,7 @@
   
       /* buffer doesn't consist of whitespaces only */
       if (p < ep) {
  -        ctx->state = (*p == *ctx->ctx->end_seq) ? PARSE_TAIL : PARSE_ARG;
  +        intern->state = (*p == *intern->end_seq) ? PARSE_TAIL : PARSE_ARG;
       }
   
       return (p - data);
  @@ -2732,39 +2736,40 @@
    * test the stream for end_seq. If it doesn't match at all, it must be an
    * argument
    */
  -static apr_size_t find_tail(ssi_ctx_t *ctx, const char *data,
  +static apr_size_t find_tail(include_ctx_t *ctx, const char *data,
                               apr_size_t len)
   {
  +    struct ssi_internal_ctx *intern = ctx->intern;
       const char *p = data;
       const char *ep = data + len;
  -    apr_size_t pos = ctx->ctx->parse_pos;
  +    apr_size_t pos = intern->parse_pos;
   
  -    if (PARSE_TAIL == ctx->state) {
  -        ctx->state = PARSE_TAIL_SEQ;
  -        pos = ctx->ctx->parse_pos = 0;
  +    if (PARSE_TAIL == intern->state) {
  +        intern->state = PARSE_TAIL_SEQ;
  +        pos = intern->parse_pos = 0;
       }
   
  -    while (p < ep && pos < ctx->end_seq_len && *p == ctx->ctx->end_seq[pos]) {
  +    while (p < ep && pos < intern->end_seq_len && *p == intern->end_seq[pos]) {
           ++p;
           ++pos;
       }
   
       /* bingo, full match */
  -    if (pos == ctx->end_seq_len) {
  -        ctx->state = PARSE_EXECUTE;
  +    if (pos == intern->end_seq_len) {
  +        intern->state = PARSE_EXECUTE;
           return (p - data);
       }
   
       /* partial match, the buffer is too small to match fully */
       if (p == ep) {
  -        ctx->ctx->parse_pos = pos;
  +        intern->parse_pos = pos;
           return (p - data);
       }
   
       /* no match. It must be an argument string then
        * The caller should cleanup and rewind to the reparse point
        */
  -    ctx->state = PARSE_ARG;
  +    intern->state = PARSE_ARG;
       return 0;
   }
   
  @@ -2773,33 +2778,34 @@
    * A pcre-pattern could look (similar to):
    * name\s*(?:=\s*(["'`]?)value\1(?>\s*))?
    */
  -static apr_size_t find_argument(ssi_ctx_t *ctx, const char *data,
  +static apr_size_t find_argument(include_ctx_t *ctx, const char *data,
                                   apr_size_t len, char ***store,
                                   apr_size_t **store_len)
   {
  +    struct ssi_internal_ctx *intern = ctx->intern;
       const char *p = data;
       const char *ep = data + len;
   
  -    switch (ctx->state) {
  +    switch (intern->state) {
       case PARSE_ARG:
           /*
            * create argument structure and append it to the current list
            */
  -        ctx->current_arg = apr_palloc(ctx->dpool,
  -                                      sizeof(*ctx->current_arg));
  -        ctx->current_arg->next = NULL;
  +        intern->current_arg = apr_palloc(ctx->dpool,
  +                                         sizeof(*intern->current_arg));
  +        intern->current_arg->next = NULL;
   
           ++(ctx->argc);
  -        if (!ctx->argv) {
  -            ctx->argv = ctx->current_arg;
  +        if (!intern->argv) {
  +            intern->argv = intern->current_arg;
           }
           else {
  -            ssi_arg_item_t *newarg = ctx->argv;
  +            ssi_arg_item_t *newarg = intern->argv;
   
               while (newarg->next) {
                   newarg = newarg->next;
               }
  -            newarg->next = ctx->current_arg;
  +            newarg->next = intern->current_arg;
           }
   
           /* check whether it's a valid one. If it begins with a quote, we
  @@ -2809,22 +2815,22 @@
           case '"': case '\'': case '`':
               *store = NULL;
   
  -            ctx->state = PARSE_ARG_VAL;
  -            ctx->quote = *p++;
  -            ctx->current_arg->name = NULL;
  -            ctx->current_arg->name_len = 0;
  -            ctx->error = 1;
  -
  -            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->r, "missing argument "
  -                          "name for value to tag %s in %s",
  -                          apr_pstrmemdup(ctx->r->pool, ctx->directive,
  -                                         ctx->ctx->directive_length),
  -                                         ctx->r->filename);
  +            intern->state = PARSE_ARG_VAL;
  +            intern->quote = *p++;
  +            intern->current_arg->name = NULL;
  +            intern->current_arg->name_len = 0;
  +            intern->error = 1;
  +
  +            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, intern->r, "missing "
  +                          "argument name for value to tag %s in %s",
  +                          apr_pstrmemdup(intern->r->pool, intern->directive,
  +                                         intern->directive_len),
  +                                         intern->r->filename);
   
               return (p - data);
   
           default:
  -            ctx->state = PARSE_ARG_NAME;
  +            intern->state = PARSE_ARG_NAME;
           }
           /* continue immediately with next state */
   
  @@ -2834,27 +2840,27 @@
           }
   
           if (p < ep) {
  -            ctx->state = PARSE_ARG_POSTNAME;
  -            *store = &ctx->current_arg->name;
  -            *store_len = &ctx->current_arg->name_len;
  +            intern->state = PARSE_ARG_POSTNAME;
  +            *store = &intern->current_arg->name;
  +            *store_len = &intern->current_arg->name_len;
               return (p - data);
           }
           break;
   
       case PARSE_ARG_POSTNAME:
  -        ctx->current_arg->name = apr_pstrmemdup(ctx->dpool,
  -                                                ctx->current_arg->name,
  -                                                ctx->current_arg->name_len);
  -        if (!ctx->current_arg->name_len) {
  -            ctx->error = 1;
  -            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->r, "missing argument "
  -                          "name for value to tag %s in %s",
  -                          apr_pstrmemdup(ctx->r->pool, ctx->directive,
  -                                         ctx->ctx->directive_length),
  -                                         ctx->r->filename);
  +        intern->current_arg->name = apr_pstrmemdup(ctx->dpool,
  +                                                 intern->current_arg->name,
  +                                                 intern->current_arg->name_len);
  +        if (!intern->current_arg->name_len) {
  +            intern->error = 1;
  +            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, intern->r, "missing "
  +                          "argument name for value to tag %s in %s",
  +                          apr_pstrmemdup(intern->r->pool, intern->directive,
  +                                         intern->directive_len),
  +                                         intern->r->filename);
           }
           else {
  -            char *sp = ctx->current_arg->name;
  +            char *sp = intern->current_arg->name;
   
               /* normalize the name */
               while (*sp) {
  @@ -2863,7 +2869,7 @@
               }
           }
   
  -        ctx->state = PARSE_ARG_EQ;
  +        intern->state = PARSE_ARG_EQ;
           /* continue with next state immediately */
   
       case PARSE_ARG_EQ:
  @@ -2875,12 +2881,12 @@
   
           if (p < ep) {
               if (*p == '=') {
  -                ctx->state = PARSE_ARG_PREVAL;
  +                intern->state = PARSE_ARG_PREVAL;
                   ++p;
               }
               else { /* no value */
  -                ctx->current_arg->value = NULL;
  -                ctx->state = PARSE_PRE_ARG;
  +                intern->current_arg->value = NULL;
  +                intern->state = PARSE_PRE_ARG;
               }
   
               return (p - data);
  @@ -2896,13 +2902,13 @@
   
           /* buffer doesn't consist of whitespaces only */
           if (p < ep) {
  -            ctx->state = PARSE_ARG_VAL;
  +            intern->state = PARSE_ARG_VAL;
               switch (*p) {
               case '"': case '\'': case '`':
  -                ctx->quote = *p++;
  +                intern->quote = *p++;
                   break;
               default:
  -                ctx->quote = '\0';
  +                intern->quote = '\0';
                   break;
               }
   
  @@ -2911,37 +2917,37 @@
           break;
   
       case PARSE_ARG_VAL_ESC:
  -        if (*p == ctx->quote) {
  +        if (*p == intern->quote) {
               ++p;
           }
  -        ctx->state = PARSE_ARG_VAL;
  +        intern->state = PARSE_ARG_VAL;
           /* continue with next state immediately */
   
       case PARSE_ARG_VAL:
           for (; p < ep; ++p) {
  -            if (ctx->quote && *p == '\\') {
  +            if (intern->quote && *p == '\\') {
                   ++p;
                   if (p == ep) {
  -                    ctx->state = PARSE_ARG_VAL_ESC;
  +                    intern->state = PARSE_ARG_VAL_ESC;
                       break;
                   }
   
  -                if (*p != ctx->quote) {
  +                if (*p != intern->quote) {
                       --p;
                   }
               }
  -            else if (ctx->quote && *p == ctx->quote) {
  +            else if (intern->quote && *p == intern->quote) {
                   ++p;
  -                *store = &ctx->current_arg->value;
  -                *store_len = &ctx->current_arg->value_len;
  -                ctx->state = PARSE_ARG_POSTVAL;
  +                *store = &intern->current_arg->value;
  +                *store_len = &intern->current_arg->value_len;
  +                intern->state = PARSE_ARG_POSTVAL;
                   break;
               }
  -            else if (!ctx->quote && apr_isspace(*p)) {
  +            else if (!intern->quote && apr_isspace(*p)) {
                   ++p;
  -                *store = &ctx->current_arg->value;
  -                *store_len = &ctx->current_arg->value_len;
  -                ctx->state = PARSE_ARG_POSTVAL;
  +                *store = &intern->current_arg->value;
  +                *store_len = &intern->current_arg->value_len;
  +                intern->state = PARSE_ARG_POSTVAL;
                   break;
               }
           }
  @@ -2952,21 +2958,21 @@
           /*
            * The value is still the raw input string. Finally clean it up.
            */
  -        --(ctx->current_arg->value_len);
  -        ctx->current_arg->value[ctx->current_arg->value_len] = '\0';
  +        --(intern->current_arg->value_len);
  +        intern->current_arg->value[intern->current_arg->value_len] = '\0';
   
           /* strip quote escaping \ from the string */
  -        if (ctx->quote) {
  +        if (intern->quote) {
               apr_size_t shift = 0;
               char *sp;
   
  -            sp = ctx->current_arg->value;
  -            ep = ctx->current_arg->value + ctx->current_arg->value_len;
  +            sp = intern->current_arg->value;
  +            ep = intern->current_arg->value + intern->current_arg->value_len;
               while (sp < ep && *sp != '\\') {
                   ++sp;
               }
               for (; sp < ep; ++sp) {
  -                if (*sp == '\\' && sp[1] == ctx->quote) {
  +                if (*sp == '\\' && sp[1] == intern->quote) {
                       ++sp;
                       ++shift;
                   }
  @@ -2975,11 +2981,11 @@
                   }
               }
   
  -            ctx->current_arg->value_len -= shift;
  +            intern->current_arg->value_len -= shift;
           }
   
  -        ctx->current_arg->value[ctx->current_arg->value_len] = '\0';
  -        ctx->state = PARSE_PRE_ARG;
  +        intern->current_arg->value[intern->current_arg->value_len] = '\0';
  +        intern->state = PARSE_PRE_ARG;
   
           return 0;
   
  @@ -2996,7 +3002,8 @@
    */
   static apr_status_t send_parsed_content(ap_filter_t *f, apr_bucket_brigade *bb)
   {
  -    ssi_ctx_t *ctx = f->ctx;
  +    include_ctx_t *ctx = f->ctx;
  +    struct ssi_internal_ctx *intern = ctx->intern;
       request_rec *r = f->r;
       apr_bucket *b = APR_BRIGADE_FIRST(bb);
       apr_bucket_brigade *pass_bb;
  @@ -3011,15 +3018,18 @@
       /* we may crash, since already cleaned up; hand over the responsibility
        * to the next filter;-)
        */
  -    if (ctx->seen_eos) {
  +    if (intern->seen_eos) {
           return ap_pass_brigade(f->next, bb);
       }
   
       /* All stuff passed along has to be put into that brigade */
  -    pass_bb = apr_brigade_create(ctx->ctx->pool, f->c->bucket_alloc);
  -    ctx->ctx->bytes_parsed = 0;
  -    ctx->ctx->output_now = 0;
  -    ctx->error = 0;
  +    pass_bb = apr_brigade_create(ctx->pool, f->c->bucket_alloc);
  +
  +    /* initialization for this loop */
  +    intern->bytes_read = 0;
  +    intern->error = 0;
  +    intern->r = r;
  +    ctx->flush_now = 0;
   
       /* loop over the current bucket brigade */
       while (b != APR_BRIGADE_SENTINEL(bb)) {
  @@ -3036,7 +3046,7 @@
               APR_BUCKET_REMOVE(b);
   
               if (APR_BUCKET_IS_EOS(b)) {
  -                ctx->seen_eos = 1;
  +                intern->seen_eos = 1;
   
                   /* Hit end of stream, time for cleanup ... But wait!
                    * Perhaps we're not ready yet. We may have to loop one or
  @@ -3054,8 +3064,8 @@
                    *    will be passed through within the next (and actually
                    *    last) round.
                    */
  -                if (PARSE_EXECUTE            == ctx->state ||
  -                    PARSE_DIRECTIVE_POSTTAIL == ctx->state) {
  +                if (PARSE_EXECUTE            == intern->state ||
  +                    PARSE_DIRECTIVE_POSTTAIL == intern->state) {
                       APR_BUCKET_INSERT_BEFORE(newb, b);
                   }
                   else {
  @@ -3066,7 +3076,7 @@
                   APR_BRIGADE_INSERT_TAIL(pass_bb, b);
   
                   if (APR_BUCKET_IS_FLUSH(b)) {
  -                    ctx->ctx->output_now = 1;
  +                    ctx->flush_now = 1;
                   }
   
                   b = newb;
  @@ -3075,8 +3085,8 @@
           }
   
           /* enough is enough ... */
  -        if (ctx->ctx->output_now ||
  -            ctx->ctx->bytes_parsed > AP_MIN_BYTES_TO_WRITE) {
  +        if (ctx->flush_now ||
  +            intern->bytes_read > AP_MIN_BYTES_TO_WRITE) {
   
               if (!APR_BRIGADE_EMPTY(pass_bb)) {
                   rv = ap_pass_brigade(f->next, pass_bb);
  @@ -3086,17 +3096,17 @@
                   }
               }
   
  -            ctx->ctx->output_now = 0;
  -            ctx->ctx->bytes_parsed = 0;
  +            ctx->flush_now = 0;
  +            intern->bytes_read = 0;
           }
   
           /* read the current bucket data */
           len = 0;
  -        if (!ctx->seen_eos) {
  -            if (ctx->ctx->bytes_parsed > 0) {
  +        if (!intern->seen_eos) {
  +            if (intern->bytes_read > 0) {
                   rv = apr_bucket_read(b, &data, &len, APR_NONBLOCK_READ);
                   if (APR_STATUS_IS_EAGAIN(rv)) {
  -                    ctx->ctx->output_now = 1;
  +                    ctx->flush_now = 1;
                       continue;
                   }
               }
  @@ -3110,11 +3120,11 @@
                   return rv;
               }
   
  -            ctx->ctx->bytes_parsed += len;
  +            intern->bytes_read += len;
           }
   
           /* zero length bucket, fetch next one */
  -        if (!len && !ctx->seen_eos) {
  +        if (!len && !intern->seen_eos) {
               b = APR_BUCKET_NEXT(b);
               continue;
           }
  @@ -3123,7 +3133,7 @@
            * it's actually a data containing bucket, start/continue parsing
            */
   
  -        switch (ctx->state) {
  +        switch (intern->state) {
           /* no current tag; search for start sequence */
           case PARSE_PRE_HEAD:
               index = find_start_sequence(ctx, data, len);
  @@ -3133,7 +3143,7 @@
               }
   
               newb = APR_BUCKET_NEXT(b);
  -            if (ctx->ctx->flags & FLAG_PRINTING) {
  +            if (ctx->flags & FLAG_PRINTING) {
                   APR_BUCKET_REMOVE(b);
                   APR_BRIGADE_INSERT_TAIL(pass_bb, b);
               }
  @@ -3143,9 +3153,9 @@
   
               if (index < len) {
                   /* now delete the start_seq stuff from the remaining bucket */
  -                if (PARSE_DIRECTIVE == ctx->state) { /* full match */
  -                    apr_bucket_split(newb, ctx->ctx->start_seq_len);
  -                    ctx->ctx->output_now = 1; /* pass pre-tag stuff */
  +                if (PARSE_DIRECTIVE == intern->state) { /* full match */
  +                    apr_bucket_split(newb, intern->start_seq_len);
  +                    ctx->flush_now = 1; /* pass pre-tag stuff */
                   }
   
                   b = APR_BUCKET_NEXT(newb);
  @@ -3162,21 +3172,20 @@
               index = find_partial_start_sequence(ctx, data, len, &release);
   
               /* check if we mismatched earlier and have to release some chars */
  -            if (release && (ctx->ctx->flags & FLAG_PRINTING)) {
  -                char *to_release = apr_palloc(ctx->ctx->pool, release);
  +            if (release && (ctx->flags & FLAG_PRINTING)) {
  +                char *to_release = apr_palloc(ctx->pool, release);
   
  -                memcpy(to_release, ctx->ctx->start_seq, release);
  -                newb = apr_bucket_pool_create(to_release, release,
  -                                              ctx->ctx->pool,
  +                memcpy(to_release, intern->start_seq, release);
  +                newb = apr_bucket_pool_create(to_release, release, ctx->pool,
                                                 f->c->bucket_alloc);
                   APR_BRIGADE_INSERT_TAIL(pass_bb, newb);
               }
   
               if (index) { /* any match */
                   /* now delete the start_seq stuff from the remaining bucket */
  -                if (PARSE_DIRECTIVE == ctx->state) { /* final match */
  +                if (PARSE_DIRECTIVE == intern->state) { /* final match */
                       apr_bucket_split(b, index);
  -                    ctx->ctx->output_now = 1; /* pass pre-tag stuff */
  +                    ctx->flush_now = 1; /* pass pre-tag stuff */
                   }
                   newb = APR_BUCKET_NEXT(b);
                   apr_bucket_delete(b);
  @@ -3200,15 +3209,15 @@
               if (store) {
                   if (index) {
                       APR_BUCKET_REMOVE(b);
  -                    APR_BRIGADE_INSERT_TAIL(ctx->tmp_bb, b);
  +                    APR_BRIGADE_INSERT_TAIL(intern->tmp_bb, b);
                       b = newb;
                   }
   
                   /* time for cleanup? */
                   if (store != &magic) {
  -                    apr_brigade_pflatten(ctx->tmp_bb, store, store_len,
  +                    apr_brigade_pflatten(intern->tmp_bb, store, store_len,
                                            ctx->dpool);
  -                    apr_brigade_cleanup(ctx->tmp_bb);
  +                    apr_brigade_cleanup(intern->tmp_bb);
                   }
               }
               else if (index) {
  @@ -3252,15 +3261,15 @@
               if (store) {
                   if (index) {
                       APR_BUCKET_REMOVE(b);
  -                    APR_BRIGADE_INSERT_TAIL(ctx->tmp_bb, b);
  +                    APR_BRIGADE_INSERT_TAIL(intern->tmp_bb, b);
                       b = newb;
                   }
   
                   /* time for cleanup? */
                   if (store != &magic) {
  -                    apr_brigade_pflatten(ctx->tmp_bb, store, store_len,
  +                    apr_brigade_pflatten(intern->tmp_bb, store, store_len,
                                            ctx->dpool);
  -                    apr_brigade_cleanup(ctx->tmp_bb);
  +                    apr_brigade_cleanup(intern->tmp_bb);
                   }
               }
               else if (index) {
  @@ -3275,7 +3284,7 @@
           case PARSE_TAIL_SEQ:
               index = find_tail(ctx, data, len);
   
  -            switch (ctx->state) {
  +            switch (intern->state) {
               case PARSE_EXECUTE:  /* full match */
                   apr_bucket_split(b, index);
                   newb = APR_BUCKET_NEXT(b);
  @@ -3285,14 +3294,14 @@
   
               case PARSE_ARG:      /* no match */
                   /* PARSE_ARG must reparse at the beginning */
  -                APR_BRIGADE_PREPEND(bb, ctx->tmp_bb);
  +                APR_BRIGADE_PREPEND(bb, intern->tmp_bb);
                   b = APR_BRIGADE_FIRST(bb);
                   break;
   
               default:             /* partial match */
                   newb = APR_BUCKET_NEXT(b);
                   APR_BUCKET_REMOVE(b);
  -                APR_BRIGADE_INSERT_TAIL(ctx->tmp_bb, b);
  +                APR_BRIGADE_INSERT_TAIL(intern->tmp_bb, b);
                   b = newb;
                   break;
               }
  @@ -3304,80 +3313,43 @@
            */
           case PARSE_EXECUTE:
               /* if there was an error, it was already logged; just stop here */
  -            if (ctx->error) {
  -                if (ctx->ctx->flags & FLAG_PRINTING) {
  -                    SSI_CREATE_ERROR_BUCKET(ctx->ctx, f, pass_bb);
  -                    ctx->error = 0;
  +            if (intern->error) {
  +                if (ctx->flags & FLAG_PRINTING) {
  +                    SSI_CREATE_ERROR_BUCKET(ctx, f, pass_bb);
  +                    intern->error = 0;
                   }
               }
               else {
                   include_handler_fn_t *handle_func;
   
  -                handle_func = apr_hash_get(include_hash, ctx->directive, 
  -                                           ctx->ctx->directive_length);
  -                if (handle_func) {
  -                    apr_bucket *dummy;
  -                    char *tag;
  -                    apr_size_t tag_len = 0;
  -                    ssi_arg_item_t *carg = ctx->argv;
  -
  -                    /* legacy wrapper code */
  -                    while (carg) {
  -                        tag_len += (carg->name  ? carg->name_len      : 0) +
  -                                   (carg->value ? carg->value_len + 1 : 0);
  -                        carg = carg->next;
  -                    }
  -
  -                    tag = ctx->ctx->combined_tag = ctx->ctx->curr_tag_pos =
  -                        apr_palloc(ctx->dpool, tag_len + 1);
  -
  -                    carg = ctx->argv;
  -                    while (carg) {
  -                        if (carg->name) {
  -                            memcpy(tag, carg->name, carg->name_len);
  -                            tag += carg->name_len;
  -                        }
  -                        if (carg->value) {
  -                            memcpy(tag++, "=", 1);
  -                            memcpy(tag, carg->value, carg->value_len + 1);
  -                            tag += carg->value_len + 1;
  -                        }
  -                        carg = carg->next;
  -                    }
  -                    ctx->ctx->tag_length = tag_len;
  +                handle_func = apr_hash_get(include_hash, intern->directive, 
  +                                           intern->directive_len);
   
  -                    rv = handle_func(ctx->ctx, &bb, r, f, b, &dummy);
  -                    if (rv != 0 && rv != 1 && rv != -1) {
  +                if (handle_func) {
  +                    rv = handle_func(ctx, f, pass_bb);
  +                    if (!APR_STATUS_IS_SUCCESS(rv)) {
                           apr_brigade_destroy(pass_bb);
                           return rv;
                       }
  -
  -                    if (dummy) {
  -                        apr_bucket_brigade *remain;
  -
  -                        remain = apr_brigade_split(bb, b);
  -                        APR_BRIGADE_CONCAT(pass_bb, bb);
  -                        bb = remain;
  -                    }
                   }
                   else {
                       ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                                     "unknown directive \"%s\" in parsed doc %s",
  -                                  apr_pstrmemdup(r->pool, ctx->directive,
  -                                                 ctx->ctx->directive_length),
  +                                  apr_pstrmemdup(r->pool, intern->directive,
  +                                                 intern->directive_len),
                                                    r->filename);
  -                    if (ctx->ctx->flags & FLAG_PRINTING) {
  -                        SSI_CREATE_ERROR_BUCKET(ctx->ctx, f, pass_bb);
  +                    if (ctx->flags & FLAG_PRINTING) {
  +                        SSI_CREATE_ERROR_BUCKET(ctx, f, pass_bb);
                       }
                   }
               }
   
               /* cleanup */
               apr_pool_clear(ctx->dpool);
  -            apr_brigade_cleanup(ctx->tmp_bb);
  +            apr_brigade_cleanup(intern->tmp_bb);
   
               /* Oooof. Done here, start next round */
  -            ctx->state = PARSE_PRE_HEAD;
  +            intern->state = PARSE_PRE_HEAD;
               break;
   
           } /* switch(ctx->state) */
  @@ -3385,36 +3357,35 @@
       } /* while(brigade) */
   
       /* End of stream. Final cleanup */
  -    if (ctx->seen_eos) {
  -        if (PARSE_HEAD == ctx->state) {
  -            if (ctx->ctx->flags & FLAG_PRINTING) {
  -                char *to_release = apr_palloc(ctx->ctx->pool,
  -                                              ctx->ctx->parse_pos);
  +    if (intern->seen_eos) {
  +        if (PARSE_HEAD == intern->state) {
  +            if (ctx->flags & FLAG_PRINTING) {
  +                char *to_release = apr_palloc(ctx->pool, intern->parse_pos);
   
  -                memcpy(to_release, ctx->ctx->start_seq, ctx->ctx->parse_pos);
  +                memcpy(to_release, intern->start_seq, intern->parse_pos);
                   APR_BRIGADE_INSERT_TAIL(pass_bb,
                                           apr_bucket_pool_create(to_release,
  -                                        ctx->ctx->parse_pos, ctx->ctx->pool,
  +                                        intern->parse_pos, ctx->pool,
                                           f->c->bucket_alloc));
               }
           }
  -        else if (PARSE_PRE_HEAD != ctx->state) {
  +        else if (PARSE_PRE_HEAD != intern->state) {
               ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                             "SSI directive was not properly finished at the end "
                             "of parsed document %s", r->filename);
  -            if (ctx->ctx->flags & FLAG_PRINTING) {
  -                SSI_CREATE_ERROR_BUCKET(ctx->ctx, f, pass_bb);
  +            if (ctx->flags & FLAG_PRINTING) {
  +                SSI_CREATE_ERROR_BUCKET(ctx, f, pass_bb);
               }
           }
   
  -        if (!(ctx->ctx->flags & FLAG_PRINTING)) {
  +        if (!(ctx->flags & FLAG_PRINTING)) {
               ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
                             "missing closing endif directive in parsed document"
                             " %s", r->filename);
           }
   
           /* cleanup our temporary memory */
  -        apr_brigade_destroy(ctx->tmp_bb);
  +        apr_brigade_destroy(intern->tmp_bb);
           apr_pool_destroy(ctx->dpool);
   
           /* don't forget to finally insert the EOS bucket */
  @@ -3503,7 +3474,7 @@
   static apr_status_t includes_filter(ap_filter_t *f, apr_bucket_brigade *b)
   {
       request_rec *r = f->r;
  -    ssi_ctx_t *ctx = f->ctx;
  +    include_ctx_t *ctx = f->ctx;
       request_rec *parent;
       include_dir_config *conf = 
                      (include_dir_config *)ap_get_module_config(r->per_dir_config,
  @@ -3517,43 +3488,37 @@
       }
   
       if (!f->ctx) {
  +        struct ssi_internal_ctx *intern;
  +
           /* create context for this filter */
  -        f->ctx = ctx = apr_palloc(f->c->pool, sizeof(*ctx));
  -        ctx->ctx = apr_pcalloc(f->c->pool, sizeof(*ctx->ctx));
  -        ctx->ctx->pool = f->r->pool;
  -        apr_pool_create(&ctx->dpool, ctx->ctx->pool);
  +        f->ctx = ctx = apr_palloc(r->pool, sizeof(*ctx));
  +        ctx->intern = intern = apr_palloc(r->pool, sizeof(*ctx->intern));
  +        ctx->pool = r->pool;
  +        apr_pool_create(&ctx->dpool, ctx->pool);
   
           /* configuration data */
  -        ctx->end_seq_len = strlen(sconf->default_end_tag);
  -        ctx->r = f->r;
  +        intern->end_seq_len = strlen(sconf->default_end_tag);
   
           /* runtime data */
  -        ctx->tmp_bb = apr_brigade_create(ctx->ctx->pool, f->c->bucket_alloc);
  -        ctx->seen_eos = 0;
  -        ctx->state = PARSE_PRE_HEAD;
  -        ctx->ctx->flags = (FLAG_PRINTING | FLAG_COND_TRUE);
  -        if (ap_allow_options(f->r) & OPT_INCNOEXEC) {
  -            ctx->ctx->flags |= FLAG_NO_EXEC;
  -        }
  -        ctx->ctx->if_nesting_level = 0;
  -        ctx->ctx->re_string = NULL;
  -        ctx->ctx->error_str_override = NULL;
  -        ctx->ctx->time_str_override = NULL;
  -
  -        ctx->ctx->state = PARSED; /* dummy */
  -        ctx->ctx->ssi_tag_brigade = apr_brigade_create(f->c->pool,
  -                                                       f->c->bucket_alloc);
  -        ctx->ctx->status = APR_SUCCESS;
  -
  -        ctx->ctx->error_str = conf->default_error_msg;
  -        ctx->ctx->time_str = conf->default_time_fmt;
  -        ctx->ctx->start_seq_pat = &sconf->start_seq_pat;
  -        ctx->ctx->start_seq  = sconf->default_start_tag;
  -        ctx->ctx->start_seq_len = sconf->start_tag_len;
  -        ctx->ctx->end_seq = sconf->default_end_tag;
  -    }
  -    else {
  -        ctx->ctx->bytes_parsed = 0;
  +        intern->tmp_bb = apr_brigade_create(ctx->pool, f->c->bucket_alloc);
  +        intern->seen_eos = 0;
  +        intern->state = PARSE_PRE_HEAD;
  +        ctx->flags = (FLAG_PRINTING | FLAG_COND_TRUE);
  +        if (ap_allow_options(r) & OPT_INCNOEXEC) {
  +            ctx->flags |= SSI_FLAG_NO_EXEC;
  +        }
  +
  +        ctx->if_nesting_level = 0;
  +        intern->re_string = NULL;
  +        intern->error_str_override = NULL;
  +        intern->time_str_override = NULL;
  +
  +        ctx->error_str = conf->default_error_msg;
  +        ctx->time_str = conf->default_time_fmt;
  +        intern->start_seq_pat = &sconf->start_seq_pat;
  +        intern->start_seq  = sconf->default_start_tag;
  +        intern->start_seq_len = sconf->start_tag_len;
  +        intern->end_seq = sconf->default_end_tag;
       }
   
       if ((parent = ap_get_module_config(r->request_config, &include_module))) {
  
  
  
  1.36      +75 -171   httpd-2.0/modules/filters/mod_include.h
  
  Index: mod_include.h
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/modules/filters/mod_include.h,v
  retrieving revision 1.35
  retrieving revision 1.36
  diff -u -r1.35 -r1.36
  --- mod_include.h	20 Aug 2003 16:27:18 -0000	1.35
  +++ mod_include.h	21 Aug 2003 22:01:34 -0000	1.36
  @@ -62,182 +62,86 @@
   #include "apr_pools.h"
   #include "apr_optional.h"
   
  -#define STARTING_SEQUENCE "<!--#"
  -#define ENDING_SEQUENCE "-->"
  +/*
  + * Constants used for ap_ssi_get_tag_and_value's decode parameter
  + */
  +#define SSI_VALUE_DECODED 1
  +#define SSI_VALUE_RAW     0
  +
  +/*
  + * Constants used for ap_ssi_parse_string's leave_name parameter
  + */
  +#define SSI_EXPAND_LEAVE_NAME 1
  +#define SSI_EXPAND_DROP_NAME  0
  +
  +/*
  + * This macro creates a bucket which contains an error message and appends it
  + * to the current pass brigade
  + */
  +#define SSI_CREATE_ERROR_BUCKET(ctx, f, bb) APR_BRIGADE_INSERT_TAIL((bb), \
  +    apr_bucket_pool_create(apr_pstrdup((ctx)->pool, (ctx)->error_str),    \
  +                           strlen((ctx)->error_str), (ctx)->pool,         \
  +                           (f)->c->bucket_alloc))
   
  -#define DEFAULT_ERROR_MSG "[an error occurred while processing this directive]"
  -#define DEFAULT_TIME_FORMAT "%A, %d-%b-%Y %H:%M:%S %Z"
  -#define SIZEFMT_BYTES 0
  -#define SIZEFMT_KMG 1
  -#define TMP_BUF_SIZE 1024
  -#if APR_CHARSET_EBCDIC
  -#define RAW_ASCII_CHAR(ch)  apr_xlate_conv_byte(ap_hdrs_from_ascii, (unsigned char)ch)
  -#else /*APR_CHARSET_EBCDIC*/
  -#define RAW_ASCII_CHAR(ch)  (ch)
  -#endif /*APR_CHARSET_EBCDIC*/
  -
  -/****************************************************************************
  - * Used to keep context information during parsing of a request for SSI tags.
  - * This is especially useful if the tag stretches across multiple buckets or
  - * brigades. This keeps track of which buckets need to be replaced with the
  - * content generated by the SSI tag.
  - *
  - * state: PRE_HEAD - State prior to finding the first character of the 
  - *                   STARTING_SEQUENCE. Next state is PARSE_HEAD.
  - *        PARSE_HEAD - State entered once the first character of the
  - *                     STARTING_SEQUENCE is found and exited when the
  - *                     the full STARTING_SEQUENCE has been matched or
  - *                     a match failure occurs. Next state is PRE_HEAD
  - *                     or PARSE_TAG.
  - *        PARSE_TAG - State entered once the STARTING sequence has been
  - *                    matched. It is exited when the first character in
  - *                    ENDING_SEQUENCE is found. Next state is PARSE_TAIL.
  - *        PARSE_TAIL - State entered from PARSE_TAG state when the first
  - *                     character in ENDING_SEQUENCE is encountered. This
  - *                     state is exited when the ENDING_SEQUENCE has been
  - *                     completely matched, or when a match failure occurs.
  - *                     Next state is PARSE_TAG or PARSED.
  - *        PARSED - State entered from PARSE_TAIL once the complete 
  - *                 ENDING_SEQUENCE has been matched. The SSI tag is
  - *                 processed and the SSI buckets are replaced with the
  - *                 SSI content during this state.
  - * parse_pos: Current matched position within the STARTING_SEQUENCE or
  - *            ENDING_SEQUENCE during the PARSE_HEAD and PARSE_TAIL states.
  - *            This is especially useful when the sequence spans brigades.
  - * X_start_bucket: These point to the buckets containing the first character
  - *                 of the STARTING_SEQUENCE, the first non-whitespace
  - *                 character of the tag, and the first character in the
  - *                 ENDING_SEQUENCE (head_, tag_, and tail_ respectively).
  - *                 The buckets are kept intact until the PARSED state is
  - *                 reached, at which time the tag is consolidated and the
  - *                 buckets are released. The buckets that these point to
  - *                 have all been set aside in the ssi_tag_brigade (along
  - *                 with all of the intervening buckets).
  - * X_start_index: The index points within the specified bucket contents
  - *                where the first character of the STARTING_SEQUENCE,
  - *                the first non-whitespace character of the tag, and the
  - *                first character in the ENDING_SEQUENCE can be found
  - *                (head_, tag_, and tail_ respectively).
  - * combined_tag: Once the PARSED state is reached the tag is collected from
  - *               the bucket(s) in the ssi_tag_brigade into this contiguous
  - *               buffer. The buckets in the ssi_tag_brigade are released
  - *               and the tag is processed.
  - * curr_tag_pos: Ptr to the combined_tag buffer indicating the current
  - *               parse position.
  - * tag_length: The number of bytes in the actual tag (excluding the
  - *             STARTING_SEQUENCE, leading and trailing whitespace,
  - *             and ENDING_SEQUENCE). This length is computed as the
  - *             buckets are parsed and set aside during the PARSE_TAG state.
  - * ssi_tag_brigade: The temporary brigade used by this filter to set aside
  - *                  the buckets containing parts of the ssi tag and headers.
  +/*
  + * These constants are used to set or clear flag bits.
    */
  -#ifdef MOD_INCLUDE_REDESIGN
  -typedef enum {PRE_HEAD, BLOW_PARSE_HEAD, BLOW_PARSE_DIRECTIVE, PARSE_TAG,
  -              BLOW_PARSE_TAIL, PARSED} states;
  -#else
  -typedef enum {PRE_HEAD, PARSE_HEAD, PARSE_DIRECTIVE, PARSE_TAG, PARSE_TAIL,
  -              PARSED} states;
  -#endif
  -
  -/** forward referenced as it needs to be held on the context */
  -typedef struct bndm_t bndm_t;
  -
  -typedef struct include_filter_ctx {
  -    states       state;
  -    long         flags;    /* See the FLAG_XXXXX definitions. */
  +#define SSI_FLAG_PRINTING         (1<<0)  /* Printing conditional lines. */
  +#define SSI_FLAG_COND_TRUE        (1<<1)  /* Conditional eval'd to true. */
  +#define SSI_FLAG_SIZE_IN_BYTES    (1<<2)  /* Sizes displayed in bytes.   */
  +#define SSI_FLAG_NO_EXEC          (1<<3)  /* No Exec in current context. */
  +
  +#define SSI_FLAG_SIZE_ABBREV      (~(SSI_FLAG_SIZE_IN_BYTES))
  +#define SSI_FLAG_CLEAR_PRINT_COND (~((SSI_FLAG_PRINTING) | \
  +                                     (SSI_FLAG_COND_TRUE)))
  +#define SSI_FLAG_CLEAR_PRINTING   (~(SSI_FLAG_PRINTING))
  +
  +/*
  + * The public SSI context structure
  + */
  +typedef struct {
  +    /* permanent pool, use this for creating bucket data */
  +    apr_pool_t  *pool;
  +
  +    /* temp pool; will be cleared after the execution of every directive */
  +    apr_pool_t  *dpool;
  +
  +    /* See the SSI_FLAG_XXXXX definitions. */
  +    int          flags;
  +
  +    /* nesting of *invisible* ifs */
       int          if_nesting_level;
  -    apr_size_t   parse_pos;
  -    int          bytes_parsed;
  -    apr_status_t status;
  -    int          output_now;
  -    int          output_flush;
  -    
  -    apr_bucket   *head_start_bucket;
  -    apr_size_t   head_start_index;
  -
  -    apr_bucket   *tag_start_bucket;
  -    apr_size_t   tag_start_index;
  -
  -    apr_bucket   *tail_start_bucket;
  -    apr_size_t   tail_start_index;
  -
  -    char        *combined_tag;
  -    char        *curr_tag_pos;
  -    apr_size_t   directive_length;
  -    apr_size_t   tag_length;
  -
  -    char         *error_str;
  -    char         *error_str_override;
  -    char         *time_str;
  -    char         *time_str_override;
  -    apr_pool_t   *pool;
  -
  -    apr_bucket_brigade *ssi_tag_brigade;
  -    bndm_t       *start_seq_pat;
  -    char         *start_seq;
  -    int          start_seq_len;
  -    char         *end_seq;
  -    char         *re_string;
  -    regmatch_t   (*re_result)[10];
  +
  +    /* if true, the current buffer will be passed down the filter chain before
  +     * continuing with next input bucket and the variable will be reset to
  +     * false.
  +     */
  +    int          flush_now;
  +
  +    /* argument counter (of the current directive) */
  +    unsigned     argc;
  +
  +    /* currently configured error string */
  +    char        *error_str;
  +
  +    /* currently configured time format */
  +    char        *time_str;
  +
  +    /* pointer to internal (non-public) data, don't touch */
  +    struct ssi_internal_ctx *intern;
   } include_ctx_t;
   
  -/* These flags are used to set flag bits. */
  -#define FLAG_PRINTING         0x00000001  /* Printing conditional lines. */
  -#define FLAG_COND_TRUE        0x00000002  /* Conditional eval'd to true. */
  -#define FLAG_SIZE_IN_BYTES    0x00000004  /* Sizes displayed in bytes.   */
  -#define FLAG_NO_EXEC          0x00000008  /* No Exec in current context. */
  -
  -/* These flags are used to clear flag bits. */
  -#define FLAG_SIZE_ABBREV      0xFFFFFFFB  /* Reset SIZE_IN_BYTES bit.    */
  -#define FLAG_CLEAR_PRINT_COND 0xFFFFFFFC  /* Reset PRINTING and COND_TRUE*/
  -#define FLAG_CLEAR_PRINTING   0xFFFFFFFE  /* Reset just PRINTING bit.    */
  -
  -#define CREATE_ERROR_BUCKET(cntx, t_buck, h_ptr, ins_head)        \
  -{                                                                 \
  -    /* XXX: it'd probably be nice to use a pool bucket here */    \
  -    t_buck = apr_bucket_heap_create(cntx->error_str,              \
  -                                    strlen(cntx->error_str),      \
  -                                    NULL, h_ptr->list);           \
  -    APR_BUCKET_INSERT_BEFORE(h_ptr, t_buck);                      \
  -                                                                  \
  -    if (ins_head == NULL) {                                       \
  -        ins_head = t_buck;                                        \
  -    }                                                             \
  -}
  -
  -/* Make sure to check the return code rc. If it is anything other
  - *   than APR_SUCCESS, then you should return this value up the
  - *   call chain.
  - */
  -#define SPLIT_AND_PASS_PRETAG_BUCKETS(brgd, cntxt, next, rc)          \
  -if ((APR_BRIGADE_EMPTY((cntxt)->ssi_tag_brigade)) &&                  \
  -    ((cntxt)->head_start_bucket != NULL)) {                           \
  -    apr_bucket_brigade *tag_plus;                                     \
  -                                                                      \
  -    tag_plus = apr_brigade_split((brgd), (cntxt)->head_start_bucket); \
  -    if ((cntxt)->output_flush) {                                      \
  -        APR_BRIGADE_INSERT_TAIL((brgd), apr_bucket_flush_create((brgd)->bucket_alloc));   \
  -    }                                                                 \
  -    (rc) = ap_pass_brigade((next), (brgd));                           \
  -    (cntxt)->bytes_parsed = 0;                                        \
  -    (brgd) = tag_plus;                                                \
  -}
  -
  -
  -typedef int (include_handler_fn_t)(include_ctx_t *ctx, apr_bucket_brigade **bb,
  -                       request_rec *r, ap_filter_t *f, apr_bucket *head_ptr, 
  -                       apr_bucket **inserted_head);
  -
  -APR_DECLARE_OPTIONAL_FN(void, ap_ssi_get_tag_and_value, (include_ctx_t *ctx,
  -                                                         char **tag,
  -                                                         char **tag_val,
  -                                                         int dodecode));
  -APR_DECLARE_OPTIONAL_FN(char*, ap_ssi_parse_string, (request_rec *r,
  -                                                    include_ctx_t *ctx,
  -                                                    const char *in,
  -                                                    char *out,
  -                                                    apr_size_t length,
  -                                                    int leave_name));
  +typedef apr_status_t (include_handler_fn_t)(include_ctx_t *, ap_filter_t *,
  +                                            apr_bucket_brigade *);
  +
  +APR_DECLARE_OPTIONAL_FN(void, ap_ssi_get_tag_and_value,
  +                        (include_ctx_t *ctx, char **tag, char **tag_val,
  +                         int dodecode));
  +
  +APR_DECLARE_OPTIONAL_FN(char*, ap_ssi_parse_string,
  +                        (request_rec *r, include_ctx_t *ctx, const char *in,
  +                         char *out, apr_size_t length, int leave_name));
  +
   APR_DECLARE_OPTIONAL_FN(void, ap_register_include_handler, 
                           (char *tag, include_handler_fn_t *func));
   
  
  
  

Mime
View raw message