httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Basant.Kukr...@Sun.COM
Subject Re: Solaris sed based apache filtering module (mod_sed)
Date Fri, 18 Apr 2008 02:42:25 GMT
On Sat, Apr 12, 2008 at 10:27:40AM -0700, Chris Elving wrote:
> sed is an inherently line-oriented editor. It seems wrong to buffer 
> multiple lines within libsed. Consider, for example, how adding such 
> multi-line buffering to libsed would complicate implementing an 
> interactive sed like sed(1).
> 
> Instead, it seems like such buffering should occur in mod_sed. mod_sed 
> is what couples libsed to the bucket brigade, and mod_sed knows that 
> such such buffering is appropriate.

As suggested by Chris Elving, I moved the buffering code from sed code to
mod_sed filter code.

Diff from first version is attached.
New sources can be viewed at :
http://src.opensolaris.org/source/xref/webstack/mod_sed/
(as well as by mercurial : hg clone ssh://anon@hg.opensolaris.org/hg/webstack/mod_sed )

Regards,
Basant.


Index: mod_sed.c
===================================================================
--- mod_sed.c   4 Apr 2008 02:33:57 -0000   1.20.2.6
+++ mod_sed.c   17 Apr 2008 21:33:01 -0000  1.20.2.8
@@ -26,6 +26,7 @@
 #include "libsed.h"
 
 static const char *sed_filter_name = "Sed";
+#define MODSED_OUTBUF_SIZE 4000
 
 typedef struct sed_expr_config
 {
@@ -45,6 +46,9 @@
     sed_eval_t eval;
     request_rec *r;
     apr_bucket_brigade *bb;
+    char *outbuf;
+    char *curoutbuf;
+    int bufsize;
 } sed_filter_ctxt;
 
 module AP_MODULE_DECLARE_DATA sed_module;
@@ -67,10 +71,32 @@
     sed_cfg->last_error = error;
 }
 
+/*
+ * flush_output_buffer
+ * Flush the  output data (stored in ctx->outbuf)
+ */
+static void flush_output_buffer(sed_filter_ctxt *ctx, char* buf, int sz)
+{
+    int size = ctx->curoutbuf - ctx->outbuf;
+    char *out;
+    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 */
+    ctx->curoutbuf = ctx->outbuf;
+    apr_bucket *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,
- * this function will be invoked. Caller creates a copy of the buffer from the
- * request pool so we don't need to create a copy here. In this method, we
- * simply create a bucket and append into the brigade at the tail.
+ * this function will be invoked.
  */
 static void sed_write_output(void *dummy, char *buf, int sz)
 {
@@ -78,9 +104,14 @@
      * of sed_eval_buffer
      */
     sed_filter_ctxt *ctx = (sed_filter_ctxt *) dummy;
-    apr_bucket *b = apr_bucket_pool_create(buf, sz, ctx->r->pool,
-                                           ctx->r->connection->bucket_alloc);
-    APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
+    if (((ctx->curoutbuf - ctx->outbuf) + sz) >= ctx->bufsize) {
+        /* flush current buffer */
+        flush_output_buffer(ctx, buf, sz);
+    }
+    else {
+        memcpy(ctx->curoutbuf, buf, sz);
+        ctx->curoutbuf += sz;
+    }
 }
 
 /* Compile a sed expression. Compiled context is saved in sed_cfg->sed_cmds.
@@ -119,6 +150,34 @@
     return APR_SUCCESS;
 }
 
+/* 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)
+{
+    apr_status_t status;
+    sed_filter_ctxt* ctx;
+    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
+     * invoking log_sed_errf.
+     */
+    ctx = apr_pcalloc(r->pool, sizeof(sed_filter_ctxt));
+    ctx->r = r;
+    ctx->bb = NULL;
+    status = sed_init_eval(&ctx->eval, sed_cfg->sed_cmds, log_sed_errf,
+                           r, &sed_write_output, r->pool);
+    if (status != APR_SUCCESS) {
+        return status;
+    }
+    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;
+    f->ctx = ctx;
+    return APR_SUCCESS;
+}
+
 /* Entry function for Sed output filter */
 static apr_status_t sed_response_filter(ap_filter_t *f,
                                         apr_bucket_brigade *bb)
@@ -144,21 +203,10 @@
             return ap_pass_brigade(f->next, bb);
         }
 
-        /* Create the context. Call sed_init_eval. libsed will generated
-         * output by calling sed_write_output and generates any error by
-         * invoking log_sed_errf.
-         */
-        ctx = f->ctx = apr_pcalloc(f->r->pool, sizeof(sed_filter_ctxt));
-        ctx->r = f->r;
-        ctx->bb = NULL;
-
-        status = sed_init_eval(&ctx->eval, sed_cfg->sed_cmds, log_sed_errf,
-                               f->r, &sed_write_output, f->r->pool);
-        if (status != APR_SUCCESS) {
-            return status;
-        }
-        apr_pool_cleanup_register(f->r->pool, &ctx->eval, sed_eval_cleanup,
-                                  apr_pool_cleanup_null);
+        status = init_context(f, sed_cfg);
+        if (status != APR_SUCCESS)
+             return status;
+        ctx = f->ctx;
     }
 
     ctx->bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
@@ -190,6 +238,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);
             APR_BUCKET_REMOVE(b);
             /* Insert the eos bucket to ctx->bb brigade */
             APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
@@ -216,6 +265,7 @@
             if (status != APR_SUCCESS) {
                 return status;
             }
+            flush_output_buffer(ctx, NULL, 0);
             APR_BUCKET_REMOVE(b);
             apr_bucket_delete(b);
             b = b1;
@@ -258,19 +308,10 @@
             /* XXX : Should we filter the sub requests too */
             return ap_get_brigade(f->next, bb, mode, block, readbytes);
         }
-        /* Create the context. Call sed_init_eval. libsed will generate
-         * output by calling sed_write_output and generates any error by
-         * invoking log_sed_errf.
-         */
-        ctx = f->ctx = apr_pcalloc(f->r->pool, sizeof(sed_filter_ctxt));
-        ctx->r = f->r;
-        status = sed_init_eval(&ctx->eval, sed_cfg->sed_cmds, log_sed_errf,
-                               f->r, &sed_write_output, f->r->pool);
-        if (status != APR_SUCCESS) {
-            return status;
-        }
-        apr_pool_cleanup_register(f->r->pool, &ctx->eval, sed_eval_cleanup,
-                                  apr_pool_cleanup_null);
+        status = init_context(f, sed_cfg);
+        if (status != APR_SUCCESS)
+             return status;
+        ctx = f->ctx;
         ctx->bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
     }
 
@@ -310,6 +351,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);
                 APR_BUCKET_REMOVE(b);
                 APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
                 break;
@@ -323,6 +365,7 @@
                 status = sed_eval_buffer(&ctx->eval, buf, bytes, ctx);
                 if (status != APR_SUCCESS)
                     return status;
+                flush_output_buffer(ctx, NULL, 0);
             }
         }
         apr_brigade_cleanup(bbinp);
Index: sed1.c
===================================================================
--- sed1.c  4 Apr 2008 21:21:39 -0000   1.11.2.19
+++ sed1.c  17 Apr 2008 21:42:23 -0000
@@ -840,7 +840,7 @@
             while ((apr_file_read(fi, buf, &n)) == APR_SUCCESS) {
                 if (n == 0)
                     break;
-                eval->writefn(eval->fout, apr_pmemdup(eval->pool, buf, n), n);
+                eval->writefn(eval->fout, buf, n);
                 n = sizeof(buf);
             }
             apr_file_close(fi);
@@ -855,9 +855,7 @@
  */
 static void wline(sed_eval_t *eval, char *buf, int sz)
 {
-    char *out = apr_palloc(eval->pool, sz + 1);
-    memcpy(out, buf, sz);
-    *(out + sz) = '\n';
-    eval->writefn(eval->fout, out, sz + 1);
+    eval->writefn(eval->fout, buf, sz);
+    eval->writefn(eval->fout, "\n", 1);
 }
 



Mime
View raw message