* Transient bucket seems to be working fine in mod_sed.
* Added error handling code so that if ap_pass_brigade fails during
  request processing, error is returned to sed_response_filter /
  sed_request_filter.

Testing :
* Compiled with 2.2 branch and make sure there is no regression (against gsed
test cases).
* Compiled with trunk.

Final patch is attached.

Regards,
Basant.



On Mon, Sep 15, 2008 at 12:17:04AM -0700, Basant Kukreja wrote:
> Hi,
> 
> Attached is the *rough* patch which uses transient buckets in mod_sed output
> filter.
> 
> Testing :
>   I created a 30MB and 300MB text files and ran OutputSed commands on the 
> file.
> * Before the patch, process size (worker mpm with 1 thread) increased up to 
> 300M 
> for single request.  After the  patch, process size remains to 3MB to server
> 300M response output.
> 
> I also removed 1 extra copying for processing output.
> 
> I need to add some more error handling to finalize the patch. Any comments are
> welcome.
> 
> Regards,
> Basant.
> 
> On Thu, Sep 04, 2008 at 09:47:26PM -0500, William A. Rowe, Jr. wrote:
> > Basant Kukreja wrote:
> >>
> >> Based on your suggestion, I will check what are the other improvements from
> >> mod_substitute can be brought into mod_sed.
> >
> > Note that mod_substitute's brigade handling is already based on the work of
> > both Jim and Nick (author of mod_line_edit) - so they are pretty certain
> > that it is the right approach.  Good idea to borrow from it.
> >
> > Bill

> Index: modules/filters/mod_sed.c
> ===================================================================
> --- modules/filters/mod_sed.c (revision 692768)
> +++ modules/filters/mod_sed.c (working copy)
> @@ -26,7 +26,8 @@
>  #include "libsed.h"
>  
>  static const char *sed_filter_name = "Sed";
> -#define MODSED_OUTBUF_SIZE 4000
> +#define MODSED_OUTBUF_SIZE 8000
> +#define MAX_TRANSIENT_BUCKETS 50
>  
>  typedef struct sed_expr_config
>  {
> @@ -44,11 +45,14 @@
>  typedef struct sed_filter_ctxt
>  {
>      sed_eval_t eval;
> +    ap_filter_t *f;
>      request_rec *r;
>      apr_bucket_brigade *bb;
>      char *outbuf;
>      char *curoutbuf;
>      int bufsize;
> +    apr_pool_t *tpool;
> +    int numbuckets;
>  } sed_filter_ctxt;
>  
>  module AP_MODULE_DECLARE_DATA sed_module;
> @@ -71,29 +75,68 @@
>      sed_cfg->last_error = error;
>  }
>  
> +/* clear the temporary pool (used for transient buckets)
> + */
> +static void clear_ctxpool(sed_filter_ctxt* ctx)
> +{
> +    apr_pool_clear(ctx->tpool);
> +    ctx->outbuf = NULL;
> +    ctx->curoutbuf = NULL;
> +    ctx->numbuckets = 0;
> +}
> +
> +/* alloc_outbuf
> + * allocate output buffer
> + */
> +static void alloc_outbuf(sed_filter_ctxt* ctx)
> +{
> +    ctx->outbuf = apr_palloc(ctx->tpool, ctx->bufsize + 1);
> +    ctx->curoutbuf = ctx->outbuf;
> +}
> +
> +/* append_bucket
> + * Allocate a new bucket from buf and sz and append to ctx->bb
> + */
> +static void append_bucket(sed_filter_ctxt* ctx, char* buf, int sz)
> +{
> +    int rv;
> +    apr_bucket *b;
> +    if (ctx->tpool == ctx->r->pool) {
> +        /* We are not using transient bucket */
> +        b = apr_bucket_pool_create(buf, sz, ctx->r->pool,
> +                                   ctx->r->connection->bucket_alloc);
> +        APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
> +    }
> +    else {
> +        /* We are using transient bucket */
> +        b = apr_bucket_transient_create(buf, sz,
> +                                        ctx->r->connection->bucket_alloc);
> +        APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
> +        ctx->numbuckets++;
> +        if (ctx->numbuckets >= MAX_TRANSIENT_BUCKETS) {
> +            b = apr_bucket_flush_create(ctx->r->connection->bucket_alloc);
> +            APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
> +            rv = ap_pass_brigade(ctx->f->next, ctx->bb);
> +            apr_brigade_cleanup(ctx->bb);
> +            clear_ctxpool(ctx);
> +        }
> +    }
> +}
> +
>  /*
>   * flush_output_buffer
>   * Flush the  output data (stored in ctx->outbuf)
>   */
> -static void flush_output_buffer(sed_filter_ctxt *ctx, char* buf, int sz)
> +static void flush_output_buffer(sed_filter_ctxt *ctx)
>  {
>      int size = ctx->curoutbuf - ctx->outbuf;
>      char *out;
> -    apr_bucket *b;
> -    if (size + sz <= 0)
> +    if ((ctx->outbuf == NULL) || (size <=0))
>          return;
> -    out = apr_palloc(ctx->r->pool, size + sz);
> -    if (size) {
> -        memcpy(out, ctx->outbuf, size);
> -    }
> -    if (buf && (sz > 0)) {
> -        memcpy(out + size, buf, sz);
> -    }
> -    /* Reset the output buffer position */
> +    out = apr_palloc(ctx->tpool, size);
> +    memcpy(out, ctx->outbuf, size);
> +    append_bucket(ctx, out, size);
>      ctx->curoutbuf = ctx->outbuf;
> -    b = apr_bucket_pool_create(out, size + sz, ctx->r->pool,
> -                               ctx->r->connection->bucket_alloc);
> -    APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
>  }
>  
>  /* This is a call back function. When libsed wants to generate the output,
> @@ -104,11 +147,38 @@
>      /* dummy is basically filter context. Context is passed during invocation
>       * of sed_eval_buffer
>       */
> +    int remainbytes = 0;
>      sed_filter_ctxt *ctx = (sed_filter_ctxt *) dummy;
> -    if (((ctx->curoutbuf - ctx->outbuf) + sz) >= ctx->bufsize) {
> -        /* flush current buffer */
> -        flush_output_buffer(ctx, buf, sz);
> +    if (ctx->outbuf == NULL) {
> +        alloc_outbuf(ctx);
>      }
> +    remainbytes = ctx->bufsize - (ctx->curoutbuf - ctx->outbuf);
> +    if (sz >= remainbytes) {
> +        if (remainbytes > 0) {
> +            memcpy(ctx->curoutbuf, buf, remainbytes);
> +            buf += remainbytes;
> +            sz -= remainbytes;
> +            ctx->curoutbuf += remainbytes;
> +        }
> +        /* buffer is now full */
> +        append_bucket(ctx, ctx->outbuf, ctx->bufsize);
> +        /* old buffer is now used so allocate new buffer */
> +        alloc_outbuf(ctx);
> +        /* if size is bigger than the allocated buffer directly add to 
> output brigade */
> +        if (sz >= ctx->bufsize) {
> +            char* newbuf = apr_palloc(ctx->tpool, sz);
> +            memcpy(newbuf, buf, sz);
> +            append_bucket(ctx, newbuf, sz);
> +            /* pool might get clear after append_bucket */
> +            if (ctx->outbuf == NULL) {
> +                alloc_outbuf(ctx);
> +            }
> +        }
> +        else {
> +            memcpy(ctx->curoutbuf, buf, sz);
> +            ctx->curoutbuf += sz;
> +        }
> +    }
>      else {
>          memcpy(ctx->curoutbuf, buf, sz);
>          ctx->curoutbuf += sz;
> @@ -153,10 +223,11 @@
>  
>  /* Initialize sed filter context. If successful then context is set in f->ctx
>   */
> -static apr_status_t init_context(ap_filter_t *f, sed_expr_config *sed_cfg)
> +static apr_status_t init_context(ap_filter_t *f, sed_expr_config *sed_cfg, 
> int usetpool)
>  {
>      apr_status_t status;
>      sed_filter_ctxt* ctx;
> +    apr_pool_t *tpool;
>      request_rec *r = f->r;
>      /* Create the context. Call sed_init_eval. libsed will generated
>       * output by calling sed_write_output and generates any error by
> @@ -165,6 +236,8 @@
>      ctx = apr_pcalloc(r->pool, sizeof(sed_filter_ctxt));
>      ctx->r = r;
>      ctx->bb = NULL;
> +    ctx->numbuckets = 0;
> +    ctx->f = f;
>      status = sed_init_eval(&ctx->eval, sed_cfg->sed_cmds, log_sed_errf,
>                             r, &sed_write_output, r->pool);
>      if (status != APR_SUCCESS) {
> @@ -173,8 +246,13 @@
>      apr_pool_cleanup_register(r->pool, &ctx->eval, sed_eval_cleanup,
>                                apr_pool_cleanup_null);
>      ctx->bufsize = MODSED_OUTBUF_SIZE;
> -    ctx->outbuf = apr_palloc(r->pool, ctx->bufsize + 1);
> -    ctx->curoutbuf = ctx->outbuf;
> +    if (usetpool) {
> +        apr_pool_create(&(ctx->tpool), r->pool);
> +    }
> +    else {
> +        ctx->tpool = r->pool;
> +    }
> +    alloc_outbuf(ctx);
>      f->ctx = ctx;
>      return APR_SUCCESS;
>  }
> @@ -204,10 +282,11 @@
>              return ap_pass_brigade(f->next, bb);
>          }
>  
> -        status = init_context(f, sed_cfg);
> +        status = init_context(f, sed_cfg, 1);
>          if (status != APR_SUCCESS)
>               return status;
>          ctx = f->ctx;
> +        apr_table_unset(f->r->headers_out, "Content-Length");
>      }
>  
>      ctx->bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
> @@ -239,7 +318,7 @@
>              apr_bucket *b1 = APR_BUCKET_NEXT(b);
>              /* Now clean up the internal sed buffer */
>              sed_finalize_eval(&ctx->eval, ctx);
> -            flush_output_buffer(ctx, NULL, 0);
> +            flush_output_buffer(ctx);
>              APR_BUCKET_REMOVE(b);
>              /* Insert the eos bucket to ctx->bb brigade */
>              APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
> @@ -248,12 +327,8 @@
>          else if (APR_BUCKET_IS_FLUSH(b)) {
>              apr_bucket *b1 = APR_BUCKET_NEXT(b);
>              APR_BUCKET_REMOVE(b);
> +            flush_output_buffer(ctx);
>              APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
> -            status = ap_pass_brigade(f->next, ctx->bb);
> -            apr_brigade_cleanup(ctx->bb);
> -            if (status != APR_SUCCESS) {
> -                return status;
> -            }
>              b = b1;
>          }
>          else if (APR_BUCKET_IS_METADATA(b)) {
> @@ -264,9 +339,9 @@
>              apr_bucket *b1 = APR_BUCKET_NEXT(b);
>              status = sed_eval_buffer(&ctx->eval, buf, bytes, ctx);
>              if (status != APR_SUCCESS) {
> +                clear_ctxpool(ctx);
>                  return status;
>              }
> -            flush_output_buffer(ctx, NULL, 0);
>              APR_BUCKET_REMOVE(b);
>              apr_bucket_delete(b);
>              b = b1;
> @@ -278,7 +353,14 @@
>          }
>      }
>      apr_brigade_cleanup(bb);
> -    return ap_pass_brigade(f->next, ctx->bb);
> +    flush_output_buffer(ctx);
> +    status = APR_SUCCESS;
> +    if (!APR_BRIGADE_EMPTY(ctx->bb)) {
> +        status = ap_pass_brigade(f->next, ctx->bb);
> +        apr_brigade_cleanup(ctx->bb);
> +    }
> +    clear_ctxpool(ctx);
> +    return status;
>  }
>  
>  /* Entry function for Sed input filter */
> @@ -309,7 +391,7 @@
>              /* XXX : Should we filter the sub requests too */
>              return ap_get_brigade(f->next, bb, mode, block, readbytes);
>          }
> -        status = init_context(f, sed_cfg);
> +        status = init_context(f, sed_cfg, 0);
>          if (status != APR_SUCCESS)
>               return status;
>          ctx = f->ctx;
> @@ -352,7 +434,7 @@
>              if (APR_BUCKET_IS_EOS(b)) {
>                  /* eos bucket. Clear the internal sed buffers */
>                  sed_finalize_eval(&ctx->eval, ctx);
> -                flush_output_buffer(ctx, NULL, 0);
> +                flush_output_buffer(ctx);
>                  APR_BUCKET_REMOVE(b);
>                  APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
>                  break;
> @@ -366,7 +448,7 @@
>                  status = sed_eval_buffer(&ctx->eval, buf, bytes, ctx);
>                  if (status != APR_SUCCESS)
>                      return status;
> -                flush_output_buffer(ctx, NULL, 0);
> +                flush_output_buffer(ctx);
>              }
>          }
>          apr_brigade_cleanup(bbinp);

Index: modules/filters/mod_sed.c
===================================================================
--- modules/filters/mod_sed.c   (revision 728840)
+++ modules/filters/mod_sed.c   (working copy)
@@ -27,6 +27,7 @@
 
 static const char *sed_filter_name = "Sed";
 #define MODSED_OUTBUF_SIZE 8000
+#define MAX_TRANSIENT_BUCKETS 50
 
 typedef struct sed_expr_config
 {
@@ -44,11 +45,14 @@
 typedef struct sed_filter_ctxt
 {
     sed_eval_t eval;
+    ap_filter_t *f;
     request_rec *r;
     apr_bucket_brigade *bb;
     char *outbuf;
     char *curoutbuf;
     int bufsize;
+    apr_pool_t *tpool;
+    int numbuckets;
 } sed_filter_ctxt;
 
 module AP_MODULE_DECLARE_DATA sed_module;
@@ -56,63 +60,137 @@
 /* This function will be call back from libsed functions if there is any error
  * happend during execution of sed scripts
  */
-static void log_sed_errf(void *data, const char *error)
+static apr_status_t log_sed_errf(void *data, const char *error)
 {
     request_rec *r = (request_rec *) data;
     ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, error);
+    return APR_SUCCESS;
 }
 
 /* This function will be call back from libsed functions if there is any
  * compilation error.
  */
-static void sed_compile_errf(void *data, const char *error)
+static apr_status_t sed_compile_errf(void *data, const char *error)
 {
     sed_expr_config *sed_cfg = (sed_expr_config *) data;
     sed_cfg->last_error = error;
+    return APR_SUCCESS;
 }
 
+/* clear the temporary pool (used for transient buckets)
+ */
+static void clear_ctxpool(sed_filter_ctxt* ctx)
+{
+    apr_pool_clear(ctx->tpool);
+    ctx->outbuf = NULL;
+    ctx->curoutbuf = NULL;
+    ctx->numbuckets = 0;
+}
+
+/* alloc_outbuf
+ * allocate output buffer
+ */
+static void alloc_outbuf(sed_filter_ctxt* ctx)
+{
+    ctx->outbuf = apr_palloc(ctx->tpool, ctx->bufsize + 1);
+    ctx->curoutbuf = ctx->outbuf;
+}
+
+/* append_bucket
+ * Allocate a new bucket from buf and sz and append to ctx->bb
+ */
+static apr_status_t append_bucket(sed_filter_ctxt* ctx, char* buf, int sz)
+{
+    apr_status_t status = APR_SUCCESS;
+    apr_bucket *b;
+    if (ctx->tpool == ctx->r->pool) {
+        /* We are not using transient bucket */
+        b = apr_bucket_pool_create(buf, sz, ctx->r->pool,
+                                   ctx->r->connection->bucket_alloc);
+        APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
+    }
+    else {
+        /* We are using transient bucket */
+        b = apr_bucket_transient_create(buf, sz,
+                                        ctx->r->connection->bucket_alloc);
+        APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
+        ctx->numbuckets++;
+        if (ctx->numbuckets >= MAX_TRANSIENT_BUCKETS) {
+            b = apr_bucket_flush_create(ctx->r->connection->bucket_alloc);
+            APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
+            status = ap_pass_brigade(ctx->f->next, ctx->bb);
+            apr_brigade_cleanup(ctx->bb);
+            clear_ctxpool(ctx);
+        }
+    }
+    return status;
+}
+
 /*
  * flush_output_buffer
  * Flush the  output data (stored in ctx->outbuf)
  */
-static void flush_output_buffer(sed_filter_ctxt *ctx, char* buf, int sz)
+static apr_status_t flush_output_buffer(sed_filter_ctxt *ctx)
 {
     int size = ctx->curoutbuf - ctx->outbuf;
     char *out;
-    apr_bucket *b;
-    if (size + sz <= 0)
-        return;
-    out = apr_palloc(ctx->r->pool, size + sz);
-    if (size) {
-        memcpy(out, ctx->outbuf, size);
-    }
-    if (buf && (sz > 0)) {
-        memcpy(out + size, buf, sz);
-    }
-    /* Reset the output buffer position */
+    apr_status_t status = APR_SUCCESS;
+    if ((ctx->outbuf == NULL) || (size <=0))
+        return status;
+    out = apr_palloc(ctx->tpool, size);
+    memcpy(out, ctx->outbuf, size);
+    status = append_bucket(ctx, out, size);
     ctx->curoutbuf = ctx->outbuf;
-    b = apr_bucket_pool_create(out, size + sz, ctx->r->pool,
-                               ctx->r->connection->bucket_alloc);
-    APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
+    return status;
 }
 
 /* This is a call back function. When libsed wants to generate the output,
  * this function will be invoked.
  */
-static void sed_write_output(void *dummy, char *buf, int sz)
+static apr_status_t sed_write_output(void *dummy, char *buf, int sz)
 {
     /* dummy is basically filter context. Context is passed during invocation
      * of sed_eval_buffer
      */
+    int remainbytes = 0;
+    apr_status_t status = APR_SUCCESS;
     sed_filter_ctxt *ctx = (sed_filter_ctxt *) dummy;
-    if (((ctx->curoutbuf - ctx->outbuf) + sz) >= ctx->bufsize) {
-        /* flush current buffer */
-        flush_output_buffer(ctx, buf, sz);
+    if (ctx->outbuf == NULL) {
+        alloc_outbuf(ctx);
     }
+    remainbytes = ctx->bufsize - (ctx->curoutbuf - ctx->outbuf);
+    if (sz >= remainbytes) {
+        if (remainbytes > 0) {
+            memcpy(ctx->curoutbuf, buf, remainbytes);
+            buf += remainbytes;
+            sz -= remainbytes;
+            ctx->curoutbuf += remainbytes;
+        }
+        /* buffer is now full */
+        status = append_bucket(ctx, ctx->outbuf, ctx->bufsize);
+        /* old buffer is now used so allocate new buffer */
+        alloc_outbuf(ctx);
+        /* if size is bigger than the allocated buffer directly add to output
+         * brigade */
+        if ((status == APR_SUCCESS) && (sz >= ctx->bufsize)) {
+            char* newbuf = apr_palloc(ctx->tpool, sz);
+            memcpy(newbuf, buf, sz);
+            status = append_bucket(ctx, newbuf, sz);
+            /* pool might get clear after append_bucket */
+            if (ctx->outbuf == NULL) {
+                alloc_outbuf(ctx);
+            }
+        }
+        else {
+            memcpy(ctx->curoutbuf, buf, sz);
+            ctx->curoutbuf += sz;
+        }
+    }
     else {
         memcpy(ctx->curoutbuf, buf, sz);
         ctx->curoutbuf += sz;
     }
+    return status;
 }
 
 /* Compile a sed expression. Compiled context is saved in sed_cfg->sed_cmds.
@@ -153,7 +231,7 @@
 
 /* Initialize sed filter context. If successful then context is set in f->ctx
  */
-static apr_status_t init_context(ap_filter_t *f, sed_expr_config *sed_cfg)
+static apr_status_t init_context(ap_filter_t *f, sed_expr_config *sed_cfg, int 
usetpool)
 {
     apr_status_t status;
     sed_filter_ctxt* ctx;
@@ -165,6 +243,8 @@
     ctx = apr_pcalloc(r->pool, sizeof(sed_filter_ctxt));
     ctx->r = r;
     ctx->bb = NULL;
+    ctx->numbuckets = 0;
+    ctx->f = f;
     status = sed_init_eval(&ctx->eval, sed_cfg->sed_cmds, log_sed_errf,
                            r, &sed_write_output, r->pool);
     if (status != APR_SUCCESS) {
@@ -173,8 +253,13 @@
     apr_pool_cleanup_register(r->pool, &ctx->eval, sed_eval_cleanup,
                               apr_pool_cleanup_null);
     ctx->bufsize = MODSED_OUTBUF_SIZE;
-    ctx->outbuf = apr_palloc(r->pool, ctx->bufsize + 1);
-    ctx->curoutbuf = ctx->outbuf;
+    if (usetpool) {
+        apr_pool_create(&(ctx->tpool), r->pool);
+    }
+    else {
+        ctx->tpool = r->pool;
+    }
+    alloc_outbuf(ctx);
     f->ctx = ctx;
     return APR_SUCCESS;
 }
@@ -204,10 +289,11 @@
             return ap_pass_brigade(f->next, bb);
         }
 
-        status = init_context(f, sed_cfg);
+        status = init_context(f, sed_cfg, 1);
         if (status != APR_SUCCESS)
              return status;
         ctx = f->ctx;
+        apr_table_unset(f->r->headers_out, "Content-Length");
     }
 
     ctx->bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
@@ -239,7 +325,11 @@
             apr_bucket *b1 = APR_BUCKET_NEXT(b);
             /* Now clean up the internal sed buffer */
             sed_finalize_eval(&ctx->eval, ctx);
-            flush_output_buffer(ctx, NULL, 0);
+            status = flush_output_buffer(ctx);
+            if (status != APR_SUCCESS) {
+                clear_ctxpool(ctx);
+                return status;
+            }
             APR_BUCKET_REMOVE(b);
             /* Insert the eos bucket to ctx->bb brigade */
             APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
@@ -248,12 +338,12 @@
         else if (APR_BUCKET_IS_FLUSH(b)) {
             apr_bucket *b1 = APR_BUCKET_NEXT(b);
             APR_BUCKET_REMOVE(b);
-            APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
-            status = ap_pass_brigade(f->next, ctx->bb);
-            apr_brigade_cleanup(ctx->bb);
+            status = flush_output_buffer(ctx);
             if (status != APR_SUCCESS) {
+                clear_ctxpool(ctx);
                 return status;
             }
+            APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
             b = b1;
         }
         else if (APR_BUCKET_IS_METADATA(b)) {
@@ -264,9 +354,9 @@
             apr_bucket *b1 = APR_BUCKET_NEXT(b);
             status = sed_eval_buffer(&ctx->eval, buf, bytes, ctx);
             if (status != APR_SUCCESS) {
+                clear_ctxpool(ctx);
                 return status;
             }
-            flush_output_buffer(ctx, NULL, 0);
             APR_BUCKET_REMOVE(b);
             apr_bucket_delete(b);
             b = b1;
@@ -278,7 +368,17 @@
         }
     }
     apr_brigade_cleanup(bb);
-    return ap_pass_brigade(f->next, ctx->bb);
+    status = flush_output_buffer(ctx);
+    if (status != APR_SUCCESS) {
+        clear_ctxpool(ctx);
+        return status;
+    }
+    if (!APR_BRIGADE_EMPTY(ctx->bb)) {
+        status = ap_pass_brigade(f->next, ctx->bb);
+        apr_brigade_cleanup(ctx->bb);
+    }
+    clear_ctxpool(ctx);
+    return status;
 }
 
 /* Entry function for Sed input filter */
@@ -309,7 +409,7 @@
             /* XXX : Should we filter the sub requests too */
             return ap_get_brigade(f->next, bb, mode, block, readbytes);
         }
-        status = init_context(f, sed_cfg);
+        status = init_context(f, sed_cfg, 0);
         if (status != APR_SUCCESS)
              return status;
         ctx = f->ctx;
@@ -352,7 +452,7 @@
             if (APR_BUCKET_IS_EOS(b)) {
                 /* eos bucket. Clear the internal sed buffers */
                 sed_finalize_eval(&ctx->eval, ctx);
-                flush_output_buffer(ctx, NULL, 0);
+                flush_output_buffer(ctx);
                 APR_BUCKET_REMOVE(b);
                 APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
                 break;
@@ -366,7 +466,7 @@
                 status = sed_eval_buffer(&ctx->eval, buf, bytes, ctx);
                 if (status != APR_SUCCESS)
                     return status;
-                flush_output_buffer(ctx, NULL, 0);
+                flush_output_buffer(ctx);
             }
         }
         apr_brigade_cleanup(bbinp);
Index: modules/filters/sed1.c
===================================================================
--- modules/filters/sed1.c      (revision 728840)
+++ modules/filters/sed1.c      (working copy)
@@ -71,8 +71,8 @@
 static char *place(sed_eval_t *eval, char *asp, char *al1, char *al2);
 static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
                             step_vars_storage *step_vars);
-static void wline(sed_eval_t *eval, char *buf, int sz);
-static void arout(sed_eval_t *eval);
+static apr_status_t wline(sed_eval_t *eval, char *buf, int sz);
+static apr_status_t arout(sed_eval_t *eval);
 
 static void eval_errf(sed_eval_t *eval, const char *fmt, ...)
 {
@@ -370,8 +370,8 @@
         eval->lspend--;
         *eval->lspend = '\0';
         rv = execute(eval);
-        if (rv != 0)
-            return APR_EGENERAL;
+        if (rv != APR_SUCCESS)
+            return rv;
     }
 
     while (bufsz) {
@@ -396,8 +396,8 @@
         buf += (llen + 1);
         bufsz -= (llen + 1);
         rv = execute(eval);
-        if (rv != 0)
-            return APR_EGENERAL;
+        if (rv != APR_SUCCESS)
+            return rv;
         if (eval->quitflag)
             break;
     }
@@ -440,8 +440,8 @@
 
         *eval->lspend = '\0';
         rv = execute(eval);
-        if (rv != 0)
-            return APR_EGENERAL;
+        if (rv != APR_SUCCESS)
+            return rv;
     }
 
     eval->quitflag = 1;
@@ -456,6 +456,7 @@
 {
     sed_reptr_t *ipc = eval->commands->ptrspace;
     step_vars_storage step_vars;
+    apr_status_t rv = APR_SUCCESS;
 
     eval->lnum++;
 
@@ -471,7 +472,6 @@
     while (ipc->command) {
         char *p1;
         char *p2;
-        apr_status_t rv;
         int c;
 
         p1 = ipc->ad1;
@@ -554,17 +554,20 @@
             ipc = ipc->next;
     }
 
-    if (!eval->commands->nflag && !eval->delflag)
-        wline(eval, eval->linebuf, eval->lspend - eval->linebuf);
+    if (!eval->commands->nflag && !eval->delflag) {
+        rv = wline(eval, eval->linebuf, eval->lspend - eval->linebuf);
+        if (rv != APR_SUCCESS)
+            return rv;
+    }
 
     if (eval->aptr > eval->abuf)
-        arout(eval);
+        rv = arout(eval);
 
     eval->delflag = 0;
 
     eval->lspend = eval->linebuf;
 
-    return APR_SUCCESS;
+    return rv;
 }
 
 /*
@@ -686,6 +689,7 @@
     char   *p1, *p2, *p3;
     int length;
     char sz[32]; /* 32 bytes enough to store 64 bit integer in decimal */
+    apr_status_t rv = APR_SUCCESS;
 
 
     switch(ipc->command) {
@@ -704,7 +708,7 @@
             if(!eval->inar[ipc->nrep] || eval->dolflag) {
                 for (p1 = ipc->re1; *p1; p1++)
                     ;
-                wline(eval, ipc->re1, p1 - ipc->re1);
+                rv = wline(eval, ipc->re1, p1 - ipc->re1);
             }
             break;
         case DCOM:
@@ -727,7 +731,7 @@
 
         case EQCOM:
             length = apr_snprintf(sz, sizeof(sz), "%d", (int) eval->lnum);
-            wline(eval, sz, length);
+            rv = wline(eval, sz, length);
             break;
 
         case GCOM:
@@ -750,7 +754,7 @@
 
         case ICOM:
             for (p1 = ipc->re1; *p1; p1++);
-            wline(eval, ipc->re1, p1 - ipc->re1);
+            rv = wline(eval, ipc->re1, p1 - ipc->re1);
             break;
 
         case BCOM:
@@ -769,8 +773,10 @@
                         while ((*p2++ = *p3++) != 0)
                             if(p2 >= eval->lcomend) {
                                 *p2 = '\\';
-                                wline(eval, eval->genbuf,
-                                      strlen(eval->genbuf));
+                                rv = wline(eval, eval->genbuf,
+                                           strlen(eval->genbuf));
+                                if (rv != APR_SUCCESS)
+                                    return rv;
                                 p2 = eval->genbuf;
                             }
                         p2--;
@@ -781,32 +787,47 @@
                         *p2++ = '\\';
                         if(p2 >= eval->lcomend) {
                             *p2 = '\\';
-                            wline(eval, eval->genbuf, strlen(eval->genbuf));
+                            rv = wline(eval, eval->genbuf,
+                                       strlen(eval->genbuf));
+                            if (rv != APR_SUCCESS)
+                                return rv;
                             p2 = eval->genbuf;
                         }
                         *p2++ = (*p1 >> 6) + '0';
                         if(p2 >= eval->lcomend) {
                             *p2 = '\\';
-                            wline(eval, eval->genbuf, strlen(eval->genbuf));
+                            rv = wline(eval, eval->genbuf,
+                                       strlen(eval->genbuf));
+                            if (rv != APR_SUCCESS)
+                                return rv;
                             p2 = eval->genbuf;
                         }
                         *p2++ = ((*p1 >> 3) & 07) + '0';
                         if(p2 >= eval->lcomend) {
                             *p2 = '\\';
-                            wline(eval, eval->genbuf, strlen(eval->genbuf));
+                            rv = wline(eval, eval->genbuf,
+                                       strlen(eval->genbuf));
+                            if (rv != APR_SUCCESS)
+                                return rv;
                             p2 = eval->genbuf;
                         }
                         *p2++ = (*p1++ & 07) + '0';
                         if(p2 >= eval->lcomend) {
                             *p2 = '\\';
-                            wline(eval, eval->genbuf, strlen(eval->genbuf));
+                            rv = wline(eval, eval->genbuf,
+                                       strlen(eval->genbuf));
+                            if (rv != APR_SUCCESS)
+                                return rv;
                             p2 = eval->genbuf;
                         }
                     } else {
                         *p2++ = *p1++;
                         if(p2 >= eval->lcomend) {
                             *p2 = '\\';
-                            wline(eval, eval->genbuf, strlen(eval->genbuf));
+                            rv = wline(eval, eval->genbuf,
+                                       strlen(eval->genbuf));
+                            if (rv != APR_SUCCESS)
+                                return rv;
                             p2 = eval->genbuf;
                         }
                     }
@@ -815,48 +836,65 @@
                     while ((*p2++ = *p3++) != 0)
                         if(p2 >= eval->lcomend) {
                             *p2 = '\\';
-                            wline(eval, eval->genbuf, strlen(eval->genbuf));
+                            rv = wline(eval, eval->genbuf,
+                                       strlen(eval->genbuf));
+                            if (rv != APR_SUCCESS)
+                                return rv;
                             p2 = eval->genbuf;
                         }
                     p2--;
                     p1++;
                 }
             *p2 = 0;
-            wline(eval, eval->genbuf, strlen(eval->genbuf));
+            rv = wline(eval, eval->genbuf, strlen(eval->genbuf));
             break;
 
         case NCOM:
             if(!eval->commands->nflag) {
-                wline(eval, eval->linebuf, eval->lspend - eval->linebuf);
+                rv = wline(eval, eval->linebuf, eval->lspend - eval->linebuf);
+                if (rv != APR_SUCCESS)
+                    return rv;
             }
 
-            if(eval->aptr > eval->abuf)
-                arout(eval);
+            if(eval->aptr > eval->abuf) {
+                rv = arout(eval);
+                if (rv != APR_SUCCESS)
+                    return rv;
+            }
             eval->lspend = eval->linebuf;
             eval->pending = ipc->next;
 
             break;
         case CNCOM:
-            if(eval->aptr > eval->abuf)
-                arout(eval);
+            if(eval->aptr > eval->abuf) {
+                rv = arout(eval);
+                if (rv != APR_SUCCESS)
+                    return rv;
+            }
             append_to_linebuf(eval, "\n");
             eval->pending = ipc->next;
             break;
 
         case PCOM:
-            wline(eval, eval->linebuf, eval->lspend - eval->linebuf);
+            rv = wline(eval, eval->linebuf, eval->lspend - eval->linebuf);
             break;
         case CPCOM:
             for (p1 = eval->linebuf; *p1 != '\n' && *p1 != '\0'; p1++);
-            wline(eval, eval->linebuf, p1 - eval->linebuf);
+            rv = wline(eval, eval->linebuf, p1 - eval->linebuf);
             break;
 
         case QCOM:
-            if (!eval->commands->nflag)
-                wline(eval, eval->linebuf, eval->lspend - eval->linebuf);
+            if (!eval->commands->nflag) {
+                rv = wline(eval, eval->linebuf, eval->lspend - eval->linebuf);
+                if (rv != APR_SUCCESS)
+                    break;
+            }
 
-            if(eval->aptr > eval->abuf)
-                arout(eval);
+            if(eval->aptr > eval->abuf) {
+                rv = arout(eval);
+                if (rv != APR_SUCCESS)
+                    return rv;
+            }
 
             eval->quitflag = 1;
             break;
@@ -876,10 +914,15 @@
             }
             if(ipc->pfl && eval->commands->nflag && i) {
                 if(ipc->pfl == 1) {
-                    wline(eval, eval->linebuf, eval->lspend - eval->linebuf);
+                    rv = wline(eval, eval->linebuf, eval->lspend -
+                               eval->linebuf);
+                    if (rv != APR_SUCCESS)
+                        return rv;
                 } else {
                     for (p1 = eval->linebuf; *p1 != '\n' && *p1 != '\0'; p1++);
-                    wline(eval, eval->linebuf, p1 - eval->linebuf);
+                    rv = wline(eval, eval->linebuf, p1 - eval->linebuf);
+                    if (rv != APR_SUCCESS)
+                        return rv;
                 }
             }
             if (i && (ipc->findex >= 0) && eval->fcode[ipc->findex])
@@ -910,21 +953,24 @@
             while((*p1 = p2[(unsigned char)*p1]) != 0)    p1++;
             break;
     }
-    return APR_SUCCESS;
+    return rv;
 }
 
 /*
  * arout
  */
-static void arout(sed_eval_t *eval)
+static apr_status_t arout(sed_eval_t *eval)
 {
+    apr_status_t rv = APR_SUCCESS;
     eval->aptr = eval->abuf - 1;
     while (*++eval->aptr) {
         if ((*eval->aptr)->command == ACOM) {
             char *p1;
 
             for (p1 = (*eval->aptr)->re1; *p1; p1++);
-            wline(eval, (*eval->aptr)->re1, p1 - (*eval->aptr)->re1);
+            rv = wline(eval, (*eval->aptr)->re1, p1 - (*eval->aptr)->re1);
+            if (rv != APR_SUCCESS)
+                return rv;
         } else {
             apr_file_t *fi = NULL;
             char buf[512];
@@ -936,7 +982,11 @@
             while ((apr_file_read(fi, buf, &n)) == APR_SUCCESS) {
                 if (n == 0)
                     break;
-                eval->writefn(eval->fout, buf, n);
+                rv = eval->writefn(eval->fout, buf, n);
+                if (rv != APR_SUCCESS) {
+                    apr_file_close(fi);
+                    return rv;
+                }
                 n = sizeof(buf);
             }
             apr_file_close(fi);
@@ -944,14 +994,19 @@
     }
     eval->aptr = eval->abuf;
     *eval->aptr = NULL;
+    return rv;
 }
 
 /*
  * wline
  */
-static void wline(sed_eval_t *eval, char *buf, int sz)
+static apr_status_t wline(sed_eval_t *eval, char *buf, int sz)
 {
-    eval->writefn(eval->fout, buf, sz);
-    eval->writefn(eval->fout, "\n", 1);
+    apr_status_t rv = APR_SUCCESS;
+    rv = eval->writefn(eval->fout, buf, sz);
+    if (rv != APR_SUCCESS)
+        return rv;
+    rv = eval->writefn(eval->fout, "\n", 1);
+    return rv;
 }
 
Index: modules/filters/libsed.h
===================================================================
--- modules/filters/libsed.h    (revision 728840)
+++ modules/filters/libsed.h    (working copy)
@@ -62,8 +62,8 @@
     sed_reptr_t *address;
 };
 
-typedef void (sed_err_fn_t)(void *data, const char *error);
-typedef void (sed_write_fn_t)(void *ctx, char *buf, int sz);
+typedef apr_status_t (sed_err_fn_t)(void *data, const char *error);
+typedef apr_status_t (sed_write_fn_t)(void *ctx, char *buf, int sz);
 
 typedef struct sed_commands_s sed_commands_t;
 #define NWFILES 11 /* 10 plus one for standard output */

Reply via email to