You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by sf...@apache.org on 2011/09/26 22:09:06 UTC
svn commit: r1176019 - in /httpd/httpd/trunk: CHANGES
modules/filters/mod_substitute.c
Author: sf
Date: Mon Sep 26 20:09:06 2011
New Revision: 1176019
URL: http://svn.apache.org/viewvc?rev=1176019&view=rev
Log:
Make mod_substitute more efficient:
- Use varbuf resizable buffer instead of constantly allocating pool
memory and copying data around. This changes the memory requirement from
quadratic in ((number of substitutions in line) * (length of line)) to
linear in (length of line).
- Instead of copying buckets just to append a \0, use new ap_regexec_len()
function
PR: 50559
Modified:
httpd/httpd/trunk/CHANGES
httpd/httpd/trunk/modules/filters/mod_substitute.c
Modified: httpd/httpd/trunk/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/CHANGES?rev=1176019&r1=1176018&r2=1176019&view=diff
==============================================================================
--- httpd/httpd/trunk/CHANGES [utf-8] (original)
+++ httpd/httpd/trunk/CHANGES [utf-8] Mon Sep 26 20:09:06 2011
@@ -12,6 +12,9 @@ Changes with Apache 2.3.15
PR 51714. [Stefan Fritsch, Jim Jagielski, Ruediger Pluem, Eric Covener,
<lowprio20 gmail.com>]
+ *) mod_substitute: Reduce memory usage and copying of data. PR 50559.
+ [Stefan Fritsch]
+
*) mod_ssl/proxy: enable the SNI extension for backend TLS connections
[Kaspar Brand]
Modified: httpd/httpd/trunk/modules/filters/mod_substitute.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/filters/mod_substitute.c?rev=1176019&r1=1176018&r2=1176019&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/filters/mod_substitute.c (original)
+++ httpd/httpd/trunk/modules/filters/mod_substitute.c Mon Sep 26 20:09:06 2011
@@ -26,6 +26,7 @@
#include "apr_strmatch.h"
#include "apr_lib.h"
#include "util_filter.h"
+#include "util_varbuf.h"
#include "apr_buckets.h"
#include "http_request.h"
#define APR_WANT_STRFUNC
@@ -79,17 +80,6 @@ static void *merge_substitute_dcfg(apr_p
#define AP_MAX_BUCKETS 1000
-#define SEDSCAT(s1, s2, pool, buff, blen, repl) do { \
- if (!s1) { \
- s1 = apr_pstrmemdup(pool, buff, blen); \
- } \
- else { \
- s2 = apr_pstrmemdup(pool, buff, blen); \
- s1 = apr_pstrcat(pool, s1, s2, NULL); \
- } \
- s1 = apr_pstrcat(pool, s1, repl, NULL); \
-} while (0)
-
#define SEDRMPATBCKT(b, offset, tmp_b, patlen) do { \
apr_bucket_split(b, offset); \
tmp_b = APR_BUCKET_NEXT(b); \
@@ -100,23 +90,18 @@ static void *merge_substitute_dcfg(apr_p
static void do_pattmatch(ap_filter_t *f, apr_bucket *inb,
apr_bucket_brigade *mybb,
- apr_pool_t *tmp_pool)
+ apr_pool_t *pool)
{
int i;
int force_quick = 0;
ap_regmatch_t regm[AP_MAX_REG_MATCH];
apr_size_t bytes;
apr_size_t len;
- apr_size_t fbytes;
const char *buff;
const char *repl;
- char *scratch;
- char *p;
- char *s1;
- char *s2;
+ struct ap_varbuf vb;
apr_bucket *b;
apr_bucket *tmp_b;
- apr_pool_t *tpool;
subst_dir_conf *cfg =
(subst_dir_conf *) ap_get_module_config(f->r->per_dir_config,
@@ -124,11 +109,9 @@ static void do_pattmatch(ap_filter_t *f,
subst_pattern_t *script;
APR_BRIGADE_INSERT_TAIL(mybb, inb);
+ ap_varbuf_init(pool, &vb, 0);
script = (subst_pattern_t *) cfg->patterns->elts;
- apr_pool_create(&tpool, tmp_pool);
- scratch = NULL;
- fbytes = 0;
/*
* Simple optimization. If we only have one pattern, then
* we can safely avoid the overhead of flattening
@@ -149,10 +132,12 @@ static void do_pattmatch(ap_filter_t *f,
}
if (apr_bucket_read(b, &buff, &bytes, APR_BLOCK_READ)
== APR_SUCCESS) {
- s1 = NULL;
+ int have_match = 0;
+ vb.strlen = 0;
if (script->pattern) {
while ((repl = apr_strmatch(script->pattern, buff, bytes)))
{
+ have_match = 1;
/* get offset into buff for pattern */
len = (apr_size_t) (repl - buff);
if (script->flatten && !force_quick) {
@@ -164,8 +149,8 @@ static void do_pattmatch(ap_filter_t *f,
* are constanting allocing space and copying
* strings.
*/
- SEDSCAT(s1, s2, tmp_pool, buff, len,
- script->replacement);
+ ap_varbuf_strmemcat(&vb, buff, len);
+ ap_varbuf_strcat(&vb, script->replacement);
}
else {
/*
@@ -189,82 +174,70 @@ static void do_pattmatch(ap_filter_t *f,
bytes -= len;
buff += len;
}
- if (script->flatten && s1 && !force_quick) {
- /*
- * we've finished looking at the bucket, so remove the
- * old one and add in our new one
- */
- s2 = apr_pstrmemdup(tmp_pool, buff, bytes);
- s1 = apr_pstrcat(tmp_pool, s1, s2, NULL);
- tmp_b = apr_bucket_transient_create(s1, strlen(s1),
- f->r->connection->bucket_alloc);
+ if (have_match && script->flatten && !force_quick) {
+ char *copy = ap_varbuf_pdup(pool, &vb, NULL, 0,
+ buff, bytes, &len);
+ tmp_b = apr_bucket_pool_create(copy, len, pool,
+ f->r->connection->bucket_alloc);
APR_BUCKET_INSERT_BEFORE(b, tmp_b);
apr_bucket_delete(b);
b = tmp_b;
}
-
}
else if (script->regexp) {
- /*
- * we need a null terminated string here :(. To hopefully
- * save time and memory, we don't alloc for each run
- * through, but only if we need to have a larger chunk
- * to save the string to. So we keep track of how much
- * we've allocated and only re-alloc when we need it.
- * NOTE: this screams for a macro.
- */
- if (!scratch || (bytes > (fbytes + 1))) {
- fbytes = bytes + 1;
- scratch = apr_palloc(tpool, fbytes);
- }
- /* reset pointer to the scratch space */
- p = scratch;
- memcpy(p, buff, bytes);
- p[bytes] = '\0';
- while (!ap_regexec(script->regexp, p,
+ int left = bytes;
+ const char *pos = buff;
+ while (!ap_regexec_len(script->regexp, pos, left,
AP_MAX_REG_MATCH, regm, 0)) {
- /* first, grab the replacement string */
- repl = ap_pregsub(tmp_pool, script->replacement, p,
- AP_MAX_REG_MATCH, regm);
+ have_match = 1;
if (script->flatten && !force_quick) {
- SEDSCAT(s1, s2, tmp_pool, p, regm[0].rm_so, repl);
+ /* copy bytes before the match */
+ if (regm[0].rm_so > 0)
+ ap_varbuf_strmemcat(&vb, pos, regm[0].rm_so);
+ /* add replacement string */
+ ap_varbuf_regsub(&vb, script->replacement, pos,
+ AP_MAX_REG_MATCH, regm);
}
else {
+ repl = ap_pregsub(pool, script->replacement, pos,
+ AP_MAX_REG_MATCH, regm);
len = (apr_size_t) (regm[0].rm_eo - regm[0].rm_so);
SEDRMPATBCKT(b, regm[0].rm_so, tmp_b, len);
tmp_b = apr_bucket_transient_create(repl,
- strlen(repl),
+ strlen(repl),
f->r->connection->bucket_alloc);
APR_BUCKET_INSERT_BEFORE(b, tmp_b);
}
/*
- * reset to past what we just did. buff now maps to b
+ * reset to past what we just did. pos now maps to b
* again
*/
- p += regm[0].rm_eo;
+ pos += regm[0].rm_eo;
+ left -= regm[0].rm_eo;
}
- if (script->flatten && s1 && !force_quick) {
- s1 = apr_pstrcat(tmp_pool, s1, p, NULL);
- tmp_b = apr_bucket_transient_create(s1, strlen(s1),
- f->r->connection->bucket_alloc);
+ if (have_match && script->flatten && !force_quick) {
+ char *copy;
+ /* Copy result plus the part after the last match into
+ * a bucket.
+ */
+ copy = ap_varbuf_pdup(pool, &vb, NULL, 0, pos, left,
+ &len);
+ tmp_b = apr_bucket_pool_create(copy, len, pool,
+ f->r->connection->bucket_alloc);
APR_BUCKET_INSERT_BEFORE(b, tmp_b);
apr_bucket_delete(b);
b = tmp_b;
}
-
}
else {
- /* huh? */
+ ap_assert(0);
continue;
}
}
}
script++;
}
-
- apr_pool_destroy(tpool);
-
- return;
+ ap_varbuf_free(&vb);
}
static apr_status_t substitute_filter(ap_filter_t *f, apr_bucket_brigade *bb)
RE: svn commit: r1176019 - in /httpd/httpd/trunk: CHANGES modules/filters/mod_substitute.c
Posted by "Plüm, Rüdiger, VF-Group" <ru...@vodafone.com>.
Thanks. Will review and vote.
Regards
Rüdiger
> -----Original Message-----
> From: Rainer Jung
> Sent: Donnerstag, 29. September 2011 14:36
> To: dev@httpd.apache.org
> Subject: Re: svn commit: r1176019 - in /httpd/httpd/trunk:
> CHANGES modules/filters/mod_substitute.c
>
> On 29.09.2011 13:09, "Plüm, Rüdiger, VF-Group" wrote:
> > Anyone time for remote eyes if my findings are correct or wrong?
>
> I did only locally check the scratch and fbytes stuff, but I agree, it
> must be
>
> Index: modules/filters/mod_substitute.c
> ===================================================================
> --- modules/filters/mod_substitute.c (revision 1177244)
> +++ modules/filters/mod_substitute.c (working copy)
> @@ -213,7 +213,7 @@
> * we've allocated and only re-alloc
> when we need it.
> * NOTE: this screams for a macro.
> */
> - if (!scratch || (bytes > (fbytes + 1))) {
> + if (!scratch || (bytes + 1 > fbytes)) {
> fbytes = bytes + 1;
> scratch = apr_palloc(tpool, fbytes);
> }
>
> Will propose for 2.2.x.
>
> Regards,
>
> Rainer
>
Re: svn commit: r1176019 - in /httpd/httpd/trunk: CHANGES modules/filters/mod_substitute.c
Posted by Rainer Jung <ra...@kippdata.de>.
On 29.09.2011 13:09, "Plüm, Rüdiger, VF-Group" wrote:
> Anyone time for remote eyes if my findings are correct or wrong?
I did only locally check the scratch and fbytes stuff, but I agree, it
must be
Index: modules/filters/mod_substitute.c
===================================================================
--- modules/filters/mod_substitute.c (revision 1177244)
+++ modules/filters/mod_substitute.c (working copy)
@@ -213,7 +213,7 @@
* we've allocated and only re-alloc when we need it.
* NOTE: this screams for a macro.
*/
- if (!scratch || (bytes > (fbytes + 1))) {
+ if (!scratch || (bytes + 1 > fbytes)) {
fbytes = bytes + 1;
scratch = apr_palloc(tpool, fbytes);
}
Will propose for 2.2.x.
Regards,
Rainer
RE: svn commit: r1176019 - in /httpd/httpd/trunk: CHANGES modules/filters/mod_substitute.c
Posted by "Plüm, Rüdiger, VF-Group" <ru...@vodafone.com>.
Anyone time for remote eyes if my findings are correct or wrong?
Regards
Rüdiger
> -----Original Message-----
> From: Ruediger Pluem
> Sent: Mittwoch, 28. September 2011 08:29
> To: dev@httpd.apache.org
> Subject: Re: svn commit: r1176019 - in /httpd/httpd/trunk:
> CHANGES modules/filters/mod_substitute.c
>
>
>
> On 09/26/2011 10:09 PM, sf@apache.org wrote:
> > Author: sf
> > Date: Mon Sep 26 20:09:06 2011
> > New Revision: 1176019
> >
> > URL: http://svn.apache.org/viewvc?rev=1176019&view=rev
> > Log:
> > Make mod_substitute more efficient:
> > - Use varbuf resizable buffer instead of constantly allocating pool
> > memory and copying data around. This changes the memory
> requirement from
> > quadratic in ((number of substitutions in line) * (length
> of line)) to
> > linear in (length of line).
> > - Instead of copying buckets just to append a \0, use new
> ap_regexec_len()
> > function
> >
> > PR: 50559
> >
> > Modified:
> > httpd/httpd/trunk/CHANGES
> > httpd/httpd/trunk/modules/filters/mod_substitute.c
> >
> > Modified: httpd/httpd/trunk/modules/filters/mod_substitute.c
> > URL:
> http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/filters
> /mod_substitute.c?rev=1176019&r1=1176018&r2=1176019&view=diff
> >
> ==============================================================
> ================
> > --- httpd/httpd/trunk/modules/filters/mod_substitute.c (original)
> > +++ httpd/httpd/trunk/modules/filters/mod_substitute.c Mon
> Sep 26 20:09:06 2011
> /*
> > @@ -189,82 +174,70 @@ static void do_pattmatch(ap_filter_t *f,
> > bytes -= len;
> > buff += len;
> > }
> > - if (script->flatten && s1 && !force_quick) {
> > - /*
> > - * we've finished looking at the
> bucket, so remove the
> > - * old one and add in our new one
> > - */
> > - s2 = apr_pstrmemdup(tmp_pool, buff, bytes);
> > - s1 = apr_pstrcat(tmp_pool, s1, s2, NULL);
> > - tmp_b =
> apr_bucket_transient_create(s1, strlen(s1),
> > -
> f->r->connection->bucket_alloc);
> > + if (have_match && script->flatten &&
> !force_quick) {
> > + char *copy = ap_varbuf_pdup(pool,
> &vb, NULL, 0,
> > + buff,
> bytes, &len);
> > + tmp_b =
> apr_bucket_pool_create(copy, len, pool,
> > +
> f->r->connection->bucket_alloc);
> > APR_BUCKET_INSERT_BEFORE(b, tmp_b);
> > apr_bucket_delete(b);
> > b = tmp_b;
> > }
> > -
> > }
> > else if (script->regexp) {
> > - /*
> > - * we need a null terminated string
> here :(. To hopefully
> > - * save time and memory, we don't
> alloc for each run
> > - * through, but only if we need to
> have a larger chunk
> > - * to save the string to. So we keep
> track of how much
> > - * we've allocated and only re-alloc
> when we need it.
> > - * NOTE: this screams for a macro.
> > - */
> > - if (!scratch || (bytes > (fbytes + 1))) {
>
> Not that it matters on trunk now any longer, but on 2.2.x:
>
> Don't we have an off by two here?
> If scratch was already allocated it is fbytes large.
> If bytes is e.g. equal to fbytes or bytes == fbytes +1
> the above won't be true, but we will
> copy fbytes + 1 (2) data (trailing \0) to the buffer.
> Shouldn't the check be
>
> bytes + 1 > fbytes
>
> instead?
>
> > - fbytes = bytes + 1;
> > - scratch = apr_palloc(tpool, fbytes);
> > - }
> > - /* reset pointer to the scratch space */
> > - p = scratch;
> > - memcpy(p, buff, bytes);
> > - p[bytes] = '\0';
> > - while (!ap_regexec(script->regexp, p,
> > + int left = bytes;
> > + const char *pos = buff;
> > + while (!ap_regexec_len(script->regexp,
> pos, left,
> > AP_MAX_REG_MATCH,
> regm, 0)) {
> > - /* first, grab the replacement string */
> > - repl = ap_pregsub(tmp_pool,
> script->replacement, p,
> > - AP_MAX_REG_MATCH, regm);
> > + have_match = 1;
> > if (script->flatten && !force_quick) {
> > - SEDSCAT(s1, s2, tmp_pool, p,
> regm[0].rm_so, repl);
> > + /* copy bytes before the match */
> > + if (regm[0].rm_so > 0)
> > + ap_varbuf_strmemcat(&vb,
> pos, regm[0].rm_so);
> > + /* add replacement string */
> > + ap_varbuf_regsub(&vb,
> script->replacement, pos,
> > +
> AP_MAX_REG_MATCH, regm);
> > }
> > else {
> > + repl = ap_pregsub(pool,
> script->replacement, pos,
> > +
> AP_MAX_REG_MATCH, regm);
> > len = (apr_size_t)
> (regm[0].rm_eo - regm[0].rm_so);
> > SEDRMPATBCKT(b, regm[0].rm_so,
> tmp_b, len);
> > tmp_b =
> apr_bucket_transient_create(repl,
> > -
> strlen(repl),
> > + strlen(repl),
> >
> f->r->connection->bucket_alloc);
> > APR_BUCKET_INSERT_BEFORE(b, tmp_b);
> > }
> > /*
> > - * reset to past what we just did.
> buff now maps to b
> > + * reset to past what we just did.
> pos now maps to b
> > * again
> > */
> > - p += regm[0].rm_eo;
> > + pos += regm[0].rm_eo;
> > + left -= regm[0].rm_eo;
> > }
> > - if (script->flatten && s1 && !force_quick) {
> > - s1 = apr_pstrcat(tmp_pool, s1, p, NULL);
> > - tmp_b =
> apr_bucket_transient_create(s1, strlen(s1),
> > -
> f->r->connection->bucket_alloc);
> > + if (have_match && script->flatten &&
> !force_quick) {
> > + char *copy;
> > + /* Copy result plus the part after
> the last match into
> > + * a bucket.
> > + */
> > + copy = ap_varbuf_pdup(pool, &vb,
> NULL, 0, pos, left,
> > + &len);
> > + tmp_b =
> apr_bucket_pool_create(copy, len, pool,
> > +
> f->r->connection->bucket_alloc);
> > APR_BUCKET_INSERT_BEFORE(b, tmp_b);
> > apr_bucket_delete(b);
> > b = tmp_b;
> > }
> > -
> > }
> > else {
> > - /* huh? */
> > + ap_assert(0);
> > continue;
> > }
> > }
> > }
> > script++;
> > }
> > -
> > - apr_pool_destroy(tpool);
> > -
> > - return;
> > + ap_varbuf_free(&vb);
> > }
> >
> > static apr_status_t substitute_filter(ap_filter_t *f,
> apr_bucket_brigade *bb)
> >
> >
> >
> >
>
>
> Regards
>
> Rüdiger
>
Re: svn commit: r1176019 - in /httpd/httpd/trunk: CHANGES modules/filters/mod_substitute.c
Posted by Ruediger Pluem <rp...@apache.org>.
On 09/26/2011 10:09 PM, sf@apache.org wrote:
> Author: sf
> Date: Mon Sep 26 20:09:06 2011
> New Revision: 1176019
>
> URL: http://svn.apache.org/viewvc?rev=1176019&view=rev
> Log:
> Make mod_substitute more efficient:
> - Use varbuf resizable buffer instead of constantly allocating pool
> memory and copying data around. This changes the memory requirement from
> quadratic in ((number of substitutions in line) * (length of line)) to
> linear in (length of line).
> - Instead of copying buckets just to append a \0, use new ap_regexec_len()
> function
>
> PR: 50559
>
> Modified:
> httpd/httpd/trunk/CHANGES
> httpd/httpd/trunk/modules/filters/mod_substitute.c
>
> Modified: httpd/httpd/trunk/modules/filters/mod_substitute.c
> URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/filters/mod_substitute.c?rev=1176019&r1=1176018&r2=1176019&view=diff
> ==============================================================================
> --- httpd/httpd/trunk/modules/filters/mod_substitute.c (original)
> +++ httpd/httpd/trunk/modules/filters/mod_substitute.c Mon Sep 26 20:09:06 2011
/*
> @@ -189,82 +174,70 @@ static void do_pattmatch(ap_filter_t *f,
> bytes -= len;
> buff += len;
> }
> - if (script->flatten && s1 && !force_quick) {
> - /*
> - * we've finished looking at the bucket, so remove the
> - * old one and add in our new one
> - */
> - s2 = apr_pstrmemdup(tmp_pool, buff, bytes);
> - s1 = apr_pstrcat(tmp_pool, s1, s2, NULL);
> - tmp_b = apr_bucket_transient_create(s1, strlen(s1),
> - f->r->connection->bucket_alloc);
> + if (have_match && script->flatten && !force_quick) {
> + char *copy = ap_varbuf_pdup(pool, &vb, NULL, 0,
> + buff, bytes, &len);
> + tmp_b = apr_bucket_pool_create(copy, len, pool,
> + f->r->connection->bucket_alloc);
> APR_BUCKET_INSERT_BEFORE(b, tmp_b);
> apr_bucket_delete(b);
> b = tmp_b;
> }
> -
> }
> else if (script->regexp) {
> - /*
> - * we need a null terminated string here :(. To hopefully
> - * save time and memory, we don't alloc for each run
> - * through, but only if we need to have a larger chunk
> - * to save the string to. So we keep track of how much
> - * we've allocated and only re-alloc when we need it.
> - * NOTE: this screams for a macro.
> - */
> - if (!scratch || (bytes > (fbytes + 1))) {
Not that it matters on trunk now any longer, but on 2.2.x:
Don't we have an off by two here?
If scratch was already allocated it is fbytes large.
If bytes is e.g. equal to fbytes or bytes == fbytes +1
the above won't be true, but we will
copy fbytes + 1 (2) data (trailing \0) to the buffer.
Shouldn't the check be
bytes + 1 > fbytes
instead?
> - fbytes = bytes + 1;
> - scratch = apr_palloc(tpool, fbytes);
> - }
> - /* reset pointer to the scratch space */
> - p = scratch;
> - memcpy(p, buff, bytes);
> - p[bytes] = '\0';
> - while (!ap_regexec(script->regexp, p,
> + int left = bytes;
> + const char *pos = buff;
> + while (!ap_regexec_len(script->regexp, pos, left,
> AP_MAX_REG_MATCH, regm, 0)) {
> - /* first, grab the replacement string */
> - repl = ap_pregsub(tmp_pool, script->replacement, p,
> - AP_MAX_REG_MATCH, regm);
> + have_match = 1;
> if (script->flatten && !force_quick) {
> - SEDSCAT(s1, s2, tmp_pool, p, regm[0].rm_so, repl);
> + /* copy bytes before the match */
> + if (regm[0].rm_so > 0)
> + ap_varbuf_strmemcat(&vb, pos, regm[0].rm_so);
> + /* add replacement string */
> + ap_varbuf_regsub(&vb, script->replacement, pos,
> + AP_MAX_REG_MATCH, regm);
> }
> else {
> + repl = ap_pregsub(pool, script->replacement, pos,
> + AP_MAX_REG_MATCH, regm);
> len = (apr_size_t) (regm[0].rm_eo - regm[0].rm_so);
> SEDRMPATBCKT(b, regm[0].rm_so, tmp_b, len);
> tmp_b = apr_bucket_transient_create(repl,
> - strlen(repl),
> + strlen(repl),
> f->r->connection->bucket_alloc);
> APR_BUCKET_INSERT_BEFORE(b, tmp_b);
> }
> /*
> - * reset to past what we just did. buff now maps to b
> + * reset to past what we just did. pos now maps to b
> * again
> */
> - p += regm[0].rm_eo;
> + pos += regm[0].rm_eo;
> + left -= regm[0].rm_eo;
> }
> - if (script->flatten && s1 && !force_quick) {
> - s1 = apr_pstrcat(tmp_pool, s1, p, NULL);
> - tmp_b = apr_bucket_transient_create(s1, strlen(s1),
> - f->r->connection->bucket_alloc);
> + if (have_match && script->flatten && !force_quick) {
> + char *copy;
> + /* Copy result plus the part after the last match into
> + * a bucket.
> + */
> + copy = ap_varbuf_pdup(pool, &vb, NULL, 0, pos, left,
> + &len);
> + tmp_b = apr_bucket_pool_create(copy, len, pool,
> + f->r->connection->bucket_alloc);
> APR_BUCKET_INSERT_BEFORE(b, tmp_b);
> apr_bucket_delete(b);
> b = tmp_b;
> }
> -
> }
> else {
> - /* huh? */
> + ap_assert(0);
> continue;
> }
> }
> }
> script++;
> }
> -
> - apr_pool_destroy(tpool);
> -
> - return;
> + ap_varbuf_free(&vb);
> }
>
> static apr_status_t substitute_filter(ap_filter_t *f, apr_bucket_brigade *bb)
>
>
>
>
Regards
Rüdiger