Hi,

I guess I do not need to tell you that input filters with mod_ext_filter
were not implemented. Since I needed this feature I implemented it.

It would be a great honour for me if you would apply this patch to the 
main tree.

-Philipp
--- mod_ext_filter.c	Thu Feb 27 13:33:07 2003
+++ mod_ext_filter.c_enh	Sun Jun 22 10:30:45 2003
@@ -58,6 +58,10 @@
 
 /*
  * mod_ext_filter allows Unix-style filters to filter http content.
+ * 
+ * Support for input filters added by Philipp Reisner in June 2003.
+ * 
+ * apxs2 -Wc,-Wall,-g -Wl,-g -c -i mod_ext_filter.c
  */
 
 #include "httpd.h"
@@ -124,6 +128,11 @@
 
 #define ERRFN_USERDATA_KEY         "EXTFILTCHILDERRFN"
 
+static int ef_input_filter(ap_filter_t *f, apr_bucket_brigade *bb, 
+                           ap_input_mode_t mode, apr_read_type_e block,
+                           apr_off_t readbytes);
+
+
 static void *create_ef_dir_conf(apr_pool_t *p, char *dummy)
 {
     ef_dir_t *dc = (ef_dir_t *)apr_pcalloc(p, sizeof(ef_dir_t));
@@ -351,12 +360,12 @@
         /* XXX need a way to ensure uniqueness among all filters */
         ap_register_output_filter(filter->name, ef_output_filter, NULL, filter->ftype);
     }
-#if 0              /* no input filters yet */
+              /* no input filters yet */
     else if (filter->mode == INPUT_FILTER) {
         /* XXX need a way to ensure uniqueness among all filters */
         ap_register_input_filter(filter->name, ef_input_filter, NULL, AP_FTYPE_RESOURCE);
     }
-#endif
+
     else {
         ap_assert(1 != 1); /* we set the field wrong somehow */
     }
@@ -590,20 +599,24 @@
         return APR_EINVAL;
     }
     ctx->p = f->r->pool;
+
     if (ctx->filter->intype &&
         ctx->filter->intype != INTYPE_ALL) {
-        if (!f->r->content_type) {
-            ctx->noop = 1;
-        }
-        else {
-            const char *ctypes = f->r->content_type;
-            const char *ctype = ap_getword(f->r->pool, &ctypes, ';');
-
-            if (strcasecmp(ctx->filter->intype, ctype)) {
-                /* wrong IMT for us; don't mess with the output */
-                ctx->noop = 1;
-            }
-        }
+	const char *ctypes = apr_table_get(ctx->filter->mode == INPUT_FILTER ?
+					   f->r->headers_in : f->r->headers_out,
+					   "Content-Type");
+	const char *ctype = ap_getword(f->r->pool, &ctypes, ';');
+	
+	if (strcasecmp(ctx->filter->intype, ctype)) {
+	    /* wrong IMT for us; don't mess with the output */
+	    ctx->noop = 1;
+	}
+	
+	ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, 0, f->r,
+                      "filter '%s': Content-Type='%s' => %s",
+		      ctx->filter->name, ctype,
+		      ctx->noop == 1 ? "noop" : "apply");
+
     }
     if (ctx->filter->enable_env &&
         !apr_table_get(f->r->subprocess_env, ctx->filter->enable_env)) {
@@ -646,10 +659,10 @@
 
 /* drain_available_output(): 
  *
- * if any data is available from the filter, read it and pass it
- * to the next filter
+ * if any data is available from the filter, read it and append it
+ * to the the bucket brigade
  */
-static apr_status_t drain_available_output(ap_filter_t *f)
+static apr_status_t drain_available_output(ap_filter_t *f,apr_bucket_brigade *bb)
 {
     request_rec *r = f->r;
     conn_rec *c = r->connection;
@@ -658,7 +671,6 @@
     apr_size_t len;
     char buf[4096];
     apr_status_t rv;
-    apr_bucket_brigade *bb;
     apr_bucket *b;
 
     while (1) {
@@ -675,14 +687,9 @@
         if (rv != APR_SUCCESS) {
             return rv;
         }
-        bb = apr_brigade_create(r->pool, c->bucket_alloc);
-        b = apr_bucket_transient_create(buf, len, c->bucket_alloc);
+        b = apr_bucket_heap_create(buf, len, NULL, c->bucket_alloc);
         APR_BRIGADE_INSERT_TAIL(bb, b);
-        if ((rv = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {
-            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
-                          "ap_pass_brigade()");
-            return rv;
-        }
+	return APR_SUCCESS;
     }
     /* we should never get here; if we do, a bogus error message would be
      * the least of our problems 
@@ -691,7 +698,7 @@
 }
 
 static apr_status_t pass_data_to_filter(ap_filter_t *f, const char *data, 
-                                        apr_size_t len)
+                                        apr_size_t len,apr_bucket_brigade *bb)
 {
     ef_ctx_t *ctx = f->ctx;
     ef_dir_t *dc = ctx->dc;
@@ -716,7 +723,7 @@
              * to read data from the child process and pass it down to the
              * next filter!
              */
-            rv = drain_available_output(f);
+            rv = drain_available_output(f,bb);
             if (APR_STATUS_IS_EAGAIN(rv)) {
 #if APR_FILES_AS_SOCKETS
                 int num_events;
@@ -750,7 +757,14 @@
     return rv;
 }
 
-static apr_status_t ef_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
+/* ef_unified_filter: 
+ *
+ * runs the bucket brigade bb through the filter and returns the 
+ * and puts the result into bb. Dropping the previous content
+ * of bb (the input)
+ */
+
+static int ef_unified_filter(ap_filter_t *f, apr_bucket_brigade *bb)
 {
     request_rec *r = f->r;
     conn_rec *c = r->connection;
@@ -762,45 +776,36 @@
     apr_status_t rv;
     char buf[4096];
     apr_bucket *eos = NULL;
+    apr_bucket_brigade *bb_tmp;
 
-    if (!ctx) {
-        if ((rv = init_filter_instance(f)) != APR_SUCCESS) {
-            return rv;
-        }
-        ctx = f->ctx;
-    }
-    if (ctx->noop) {
-        ap_remove_output_filter(f);
-        return ap_pass_brigade(f->next, bb);
-    }
     dc = ctx->dc;
-
+    bb_tmp = apr_brigade_create(r->pool, c->bucket_alloc);
+    
     APR_BRIGADE_FOREACH(b, bb) {
 
-        if (APR_BUCKET_IS_EOS(b)) {
+	if (APR_BUCKET_IS_EOS(b)) {
             eos = b;
             break;
         }
 
-        rv = apr_bucket_read(b, &data, &len, APR_BLOCK_READ);
-        if (rv != APR_SUCCESS) {
-            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "apr_bucket_read()");
-            return rv;
-        }
-
-        /* Good cast, we just tested len isn't negative */
+	rv = apr_bucket_read(b, &data, &len, APR_BLOCK_READ);
+	if (rv != APR_SUCCESS) {
+	    ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, "apr_bucket_read() failed");
+	    return rv;
+	}
+	
+	/* Good cast, we just tested len isn't negative */
         if (len > 0 &&
-            (rv = pass_data_to_filter(f, data, (apr_size_t)len)) 
-                != APR_SUCCESS) {
+            (rv = pass_data_to_filter(f, data, (apr_size_t)len,bb_tmp))
+	    != APR_SUCCESS) {
             return rv;
         }
     }
 
-    apr_brigade_destroy(bb);
-
-    /* XXX What we *really* need to do once we've hit eos is create a pipe bucket
-     * from the child output pipe and pass down the pipe bucket + eos.
-     */
+    apr_brigade_cleanup(bb);
+    APR_BRIGADE_CONCAT(bb,bb_tmp);
+    apr_brigade_destroy(bb_tmp);
+    
     if (eos) {
         /* close the child's stdin to signal that no more data is coming;
          * that will cause the child to finish generating output
@@ -842,15 +847,9 @@
         }
         
         if (rv == APR_SUCCESS) {
-            bb = apr_brigade_create(r->pool, c->bucket_alloc);
-            b = apr_bucket_transient_create(buf, len, c->bucket_alloc);
+	    b = apr_bucket_heap_create(buf, len, NULL, c->bucket_alloc);
             APR_BRIGADE_INSERT_TAIL(bb, b);
-            if ((rv = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {
-                ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
-                              "ap_pass_brigade(filtered buffer) failed");
-                return rv;
-            }
-        }
+	}
     } while (rv == APR_SUCCESS);
 
     if (!APR_STATUS_IS_EOF(rv)) {
@@ -858,55 +857,71 @@
     }
 
     if (eos) {
-        /* pass down eos */
-        bb = apr_brigade_create(r->pool, c->bucket_alloc);
         b = apr_bucket_eos_create(c->bucket_alloc);
         APR_BRIGADE_INSERT_TAIL(bb, b);
-        if ((rv = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {
-            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
-                          "ap_pass_brigade(eos) failed");
+    }
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t ef_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
+{
+    request_rec *r = f->r;
+    ef_ctx_t *ctx = f->ctx;
+    apr_status_t rv;
+
+    if (!ctx) {
+        if ((rv = init_filter_instance(f)) != APR_SUCCESS) {
             return rv;
         }
+        ctx = f->ctx;
+    }
+    if (ctx->noop) {
+        ap_remove_output_filter(f);
+        return ap_pass_brigade(f->next, bb);
     }
 
-    return APR_SUCCESS;
+    rv = ef_unified_filter(f, bb);
+    if( rv != APR_SUCCESS) { 
+	ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+		      "ef_unified_filter() failed");
+    }
+
+    if ((rv = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {
+	ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+		      "ap_pass_brigade() failed");
+    }
+    return rv;
 }
 
-#if 0
 static int ef_input_filter(ap_filter_t *f, apr_bucket_brigade *bb, 
                            ap_input_mode_t mode, apr_read_type_e block,
                            apr_off_t readbytes)
 {
+    request_rec *r = f->r;
+    ef_ctx_t *ctx = f->ctx;
     apr_status_t rv;
-    apr_bucket *b;
-    char *buf;
-    apr_ssize_t len;
-    char *zero;
 
-    rv = ap_get_brigade(f->next, bb, mode, block, readbytes);
-    if (rv != APR_SUCCESS) {
-        return rv;
+    if (!ctx) {
+        if ((rv = init_filter_instance(f)) != APR_SUCCESS) {
+            return rv;
+        }
+        ctx = f->ctx;
     }
 
-    APR_BRIGADE_FOREACH(b, bb) {
-        if (!APR_BUCKET_IS_EOS(b)) {
-            if ((rv = apr_bucket_read(b, (const char **)&buf, &len, APR_BLOCK_READ)) != APR_SUCCESS) {
-                ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, "apr_bucket_read() failed");
-                return rv;
-            }
-            ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "apr_bucket_read -> %d bytes",
-                         len);
-            while ((zero = memchr(buf, '0', len))) {
-                *zero = 'a';
-            }
-        }
-        else
-            ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "got eos bucket");
+    if (ctx->noop) {
+        ap_remove_input_filter(f);
+        return ap_get_brigade(f->next, bb, mode, block, readbytes);
     }
 
+    rv = ap_get_brigade(f->next, bb, mode, block, readbytes);
+    if (rv != APR_SUCCESS) {
+	return rv;
+    }
+
+    rv = ef_unified_filter(f, bb);
     return rv;
 }
-#endif
 
 module AP_MODULE_DECLARE_DATA ext_filter_module =
 {

Reply via email to