* 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 */