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
Date Sat, 23 Aug 2003 03:27:51 GMT
nd          2003/08/22 20:27:51

  Modified:    modules/filters mod_include.c
  Log:
  overhaul of ap_ssi_parse_string
  - improve efficiency and memory footprint (don't use the power-of-two
    allocator)
  - allow the combination of out = NULL && length = 0, which means that
    the resulting expansion is unlimited in length
  
  Revision  Changes    Path
  1.252     +200 -153  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.251
  retrieving revision 1.252
  diff -u -r1.251 -r1.252
  --- mod_include.c	22 Aug 2003 23:14:30 -0000	1.251
  +++ mod_include.c	23 Aug 2003 03:27:51 -0000	1.252
  @@ -144,6 +144,13 @@
    * +-------------------------------------------------------+
    */
   
  +/* sll used for string expansion */
  +typedef struct result_item {
  +    struct result_item *next;
  +    apr_size_t len;
  +    const char *string;
  +} result_item_t;
  +
   typedef enum {
       XBITHACK_OFF,
       XBITHACK_ON,
  @@ -437,8 +444,7 @@
       return val;
   }
   
  -static const char *get_include_var(request_rec *r, include_ctx_t *ctx, 
  -                                   const char *var)
  +static const char *get_include_var(const char *var, include_ctx_t *ctx)
   {
       const char *val;
       if (apr_isdigit(*var) && !var[1]) {
  @@ -457,195 +463,235 @@
                    || (*ctx->intern->re_result)[idx].rm_eo < 0) {
                   return NULL;
               }
  -            val = apr_pstrmemdup(r->pool, ctx->intern->re_string
  +            val = apr_pstrmemdup(ctx->dpool, ctx->intern->re_string
                                    + (*ctx->intern->re_result)[idx].rm_so, len);
           }
       }
       else {
  -        val = apr_table_get(r->subprocess_env, var);
  +        val = apr_table_get(ctx->intern->r->subprocess_env, var);
   
           if (val == LAZY_VALUE)
  -            val = add_include_vars_lazy(r, var);
  +            val = add_include_vars_lazy(ctx->intern->r, var);
       }
       return val;
   }
   
  -/* initial buffer size for power-of-two allocator in ap_ssi_parse_string */
  -#define PARSE_STRING_INITIAL_SIZE 64
  -
   /*
    * Do variable substitution on strings
  + *
    * (Note: If out==NULL, this function allocs a buffer for the resulting
  - * string from r->pool.  The return value is the parsed string)
  + * string from ctx->pool. The return value is always the parsed string)
    */
   static char *ap_ssi_parse_string(include_ctx_t *ctx, const char *in, char *out,
                                    apr_size_t length, int leave_name)
   {
  -    char ch;
  -    char *next;
  -    char *end_out;
  -    apr_size_t out_size;
       request_rec *r = ctx->intern->r;
  +    result_item_t *result = NULL, *current = NULL;
  +    apr_size_t outlen = 0, inlen, span;
  +    char *ret = NULL, *eout = NULL;
  +    const char *p;
  +
  +    if (out) {
  +        /* sanity check, out && !length is not supported */
  +        ap_assert(out && length);
  +
  +        ret = out;
  +        eout = out + length - 1;
  +    }
  +
  +    span = strcspn(in, "\\$");
  +    inlen = strlen(in);
  +
  +    /* fast exit */
  +    if (inlen == span) {
  +        if (out) {
  +            apr_cpystrn(out, in, length);
  +        }
  +        else {
  +            ret = apr_pstrmemdup(ctx->pool, in, (length && length <= inlen)
  +                                                ? length - 1 : inlen);
  +        }
  +
  +        return ret;
  +    }
  +
  +    /* well, actually something to do */
  +    p = in + span;
   
  -    /* allocate an output buffer if needed */
  -    if (!out) {
  -        out_size = PARSE_STRING_INITIAL_SIZE;
  -        if (out_size > length) {
  -            out_size = length;
  +    if (out) {
  +        if (span) {
  +            memcpy(out, in, (out+span <= eout) ? span : (eout-out));
  +            out += span;
           }
  -        out = apr_palloc(r->pool, out_size);
       }
       else {
  -        out_size = length;
  +        current = result = apr_palloc(ctx->dpool, sizeof(*result));
  +        current->next = NULL;
  +        current->string = in;
  +        current->len = span;
  +        outlen = span;
       }
   
  -    /* leave room for nul terminator */
  -    end_out = out + out_size - 1;
  +    /* loop for specials */
  +    do {
  +        if ((out && out >= eout) || (length && outlen >= length))
{
  +            break;
  +        }
   
  -    next = out;
  -    while ((ch = *in++) != '\0') {
  -        switch (ch) {
  -        case '\\':
  -            if (next == end_out) {
  -                if (out_size < length) {
  -                    /* double the buffer size */
  -                    apr_size_t new_out_size = out_size * 2;
  -                    apr_size_t current_length = next - out;
  -                    char *new_out;
  -                    if (new_out_size > length) {
  -                        new_out_size = length;
  -                    }
  -                    new_out = apr_palloc(r->pool, new_out_size);
  -                    memcpy(new_out, out, current_length);
  -                    out = new_out;
  -                    out_size = new_out_size;
  -                    end_out = out + out_size - 1;
  -                    next = out + current_length;
  +        /* prepare next entry */
  +        if (!out && current->len) {
  +            current->next = apr_palloc(ctx->dpool, sizeof(*current->next));
  +            current = current->next;
  +            current->next = NULL;
  +            current->len = 0;
  +        }
  +
  +        /*
  +         * escaped character
  +         */
  +        if (*p == '\\') {
  +            if (out) {
  +                *out++ = (p[1] == '$') ? *++p : *p;
  +                ++p;
  +            }
  +            else {
  +                current->len = 1;
  +                current->string = (p[1] == '$') ? ++p : p;
  +                ++p;
  +                ++outlen;
  +            }
  +        }
  +
  +        /*
  +         * variable expansion
  +         */
  +        else {       /* *p == '$' */
  +            const char *newp = NULL, *ep, *key = NULL;
  +
  +            if (*++p == '{') {
  +                ep = ap_strchr_c(++p, '}');
  +                if (!ep) {
  +                    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Missing '}' on "
  +                                  "variable \"%s\" in %s", p, r->filename);
  +                    break;
                   }
  -                else {
  -                    /* truncated */
  -                    *next = '\0';
  -                    return out;
  +
  +                if (p < ep) {
  +                    key = apr_pstrmemdup(ctx->dpool, p, ep - p);
  +                    newp = ep + 1;
                   }
  -            }
  -            if (*in == '$') {
  -                *next++ = *in++;
  +                p -= 2;
               }
               else {
  -                *next++ = ch;
  +                ep = p;
  +                while (*ep == '_' || apr_isalnum(*ep)) {
  +                    ++ep;
  +                }
  +
  +                if (p < ep) {
  +                    key = apr_pstrmemdup(ctx->dpool, p, ep - p);
  +                    newp = ep;
  +                }
  +                --p;
               }
  -            break;
  -        case '$':
  -            {
  -                const char *start_of_var_name;
  -                char *end_of_var_name;        /* end of var name + 1 */
  -                const char *expansion, *temp_end, *val;
  -                char        tmp_store;
  -                apr_size_t l;
  -
  -                /* guess that the expansion won't happen */
  -                expansion = in - 1;
  -                if (*in == '{') {
  -                    ++in;
  -                    start_of_var_name = in;
  -                    in = ap_strchr_c(in, '}');
  -                    if (in == NULL) {
  -                        ap_log_rerror(APLOG_MARK, APLOG_ERR,
  -                                      0, r, "Missing '}' on variable \"%s\"",
  -                                      expansion);
  -                        *next = '\0';
  -                        return out;
  -                    }
  -                    temp_end = in;
  -                    end_of_var_name = (char *)temp_end;
  -                    ++in;
  +
  +            /* empty name results in a copy of '$' in the output string */
  +            if (!key) {
  +                if (out) {
  +                    *out++ = *p++;
                   }
                   else {
  -                    start_of_var_name = in;
  -                    while (apr_isalnum(*in) || *in == '_') {
  -                        ++in;
  -                    }
  -                    temp_end = in;
  -                    end_of_var_name = (char *)temp_end;
  +                    current->len = 1;
  +                    current->string = p++;
  +                    ++outlen;
                   }
  -                /* what a pain, too bad there's no table_getn where you can
  -                 * pass a non-nul terminated string */
  -                l = end_of_var_name - start_of_var_name;
  -                if (l != 0) {
  -                    tmp_store        = *end_of_var_name;
  -                    *end_of_var_name = '\0';
  -                    val = get_include_var(r, ctx, start_of_var_name);
  -                    *end_of_var_name = tmp_store;
  -
  -                    if (val) {
  -                        expansion = val;
  -                        l = strlen(expansion);
  -                    }
  -                    else if (leave_name) {
  -                        l = in - expansion;
  -                    }
  -                    else {
  -                        /* no expansion to be done */
  -                        break;
  -                    }
  +            }
  +            else {
  +                const char *val = get_include_var(key, ctx);
  +                apr_size_t len = 0;
  +
  +                if (val) {
  +                    len = strlen(val);
                   }
  -                else {
  -                    /* zero-length variable name causes just the $ to be 
  -                     * copied */
  -                    l = 1;
  -                }
  -                if ((next + l > end_out) && (out_size < length)) {
  -                    /* increase the buffer size to accommodate l more chars */
  -                    apr_size_t new_out_size = out_size;
  -                    apr_size_t current_length = next - out;
  -                    char *new_out;
  -                    do {
  -                        new_out_size *= 2;
  -                    } while (new_out_size < current_length + l);
  -                    if (new_out_size > length) {
  -                        new_out_size = length;
  +                else if (leave_name) {
  +                    val = p;
  +                    len = ep - p;
  +                }
  +
  +                if (val && len) {
  +                    if (out) {
  +                        memcpy(out, val, (out+len <= eout) ? len : (eout-out));
  +                        out += len;
                       }
  -                    new_out = apr_palloc(r->pool, new_out_size);
  -                    memcpy(new_out, out, current_length);
  -                    out = new_out;
  -                    out_size = new_out_size;
  -                    end_out = out + out_size - 1;
  -                    next = out + current_length;
  -                }
  -                l = ((int)l > end_out - next) ? (end_out - next) : l;
  -                memcpy(next, expansion, l);
  -                next += l;
  -                break;
  -            }
  -        default:
  -            if (next == end_out) {
  -                if (out_size < length) {
  -                    /* double the buffer size */
  -                    apr_size_t new_out_size = out_size * 2;
  -                    apr_size_t current_length = next - out;
  -                    char *new_out;
  -                    if (new_out_size > length) {
  -                        new_out_size = length;
  +                    else {
  +                        current->len = len;
  +                        current->string = val;
  +                        outlen += len;
                       }
  -                    new_out = apr_palloc(r->pool, new_out_size);
  -                    memcpy(new_out, out, current_length);
  -                    out = new_out;
  -                    out_size = new_out_size;
  -                    end_out = out + out_size - 1;
  -                    next = out + current_length;
  -                }
  -                else {
  -                    /* truncated */
  -                    *next = '\0';
  -                    return out;
                   }
  +
  +                p = newp;
               }
  -            *next++ = ch;
  +        }
  +
  +        if ((out && out >= eout) || (length && outlen >= length))
{
               break;
           }
  +
  +        /* check the remainder */
  +        if (*p && (span = strcspn(p, "\\$")) > 0) {
  +            if (!out && current->len) {
  +                current->next = apr_palloc(ctx->dpool, sizeof(*current->next));
  +                current = current->next;
  +                current->next = NULL;
  +            }
  +
  +            if (out) {
  +                memcpy(out, p, (out+span <= eout) ? span : (eout-out));
  +                out += span;
  +            }
  +            else {
  +                current->len = span;
  +                current->string = p;
  +                outlen += span;
  +            }
  +
  +            p += span;
  +        }
  +    } while (p < in+inlen);
  +
  +    /* assemble result */
  +    if (out) {
  +        if (out > eout) {
  +            *eout = '\0';
  +        }
  +        else {
  +            *out = '\0';
  +        }
       }
  -    *next = '\0';
  -    return out;
  +    else {
  +        const char *ep;
  +
  +        if (length && outlen > length) {
  +            outlen = length - 1;
  +        }
  +
  +        ret = out = apr_palloc(ctx->pool, outlen + 1);
  +        ep = ret + outlen;
  +
  +        do {
  +            if (result->len) {
  +                memcpy(out, result->string, (out+result->len <= ep)
  +                                            ? result->len : (ep-out));
  +                out += result->len;
  +            }
  +            result = result->next;
  +        } while (result && out < ep);
  +
  +        ret[outlen] = '\0';
  +    }
  +
  +    return ret;
   }
   
   
  @@ -1811,10 +1857,11 @@
               const char *echo_text = NULL;
               apr_size_t e_len;
   
  -            val = get_include_var(r, ctx,
  -                                  ap_ssi_parse_string(ctx, tag_val, NULL,
  +            val = get_include_var(ap_ssi_parse_string(ctx, tag_val, NULL,
                                                         MAX_STRING_LEN,
  -                                                      SSI_EXPAND_DROP_NAME));
  +                                                      SSI_EXPAND_DROP_NAME),
  +                                  ctx);
  +
               if (val) {
                   switch(encode) {
                   case E_NONE:
  
  
  

Mime
View raw message