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 =
{