Earlier I've committed a new API for filter self-removal, which works from within the filter itself. If you want to remove filters from elsewhere, it's not quite simple, because we can't find them in the filter chain by their handler names. This patch provides the functionality to traverse httpd filter chains and find mod_perl filters, which can then be used to remove them. Obviously the traversal API should be in the httpd core and I've posted an rfc to the httpd-dev list. Meanwhile please tell me if you like the perl API and think we want this functionality at all.

What I was planning is:

registered request filters can be removed in the response handler:

  $r->remove_input_filter( __PACKAGE__ . "::in_filter");
  $r->remove_output_filter(__PACKAGE__ . "::out_filter");

registered connection filters can be removed in the process_connection handler:

  $c->remove_input_filter( __PACKAGE__ . "::in_filter");
  $c->remove_output_filter(__PACKAGE__ . "::out_filter");

In the following patch you can see the preparation for this support, implementatin of only $r->remove_output_filter and a test which exercises it.
This patch applies against the latest mod_perl cvs, and the test should work.dev


Index: src/modules/perl/modperl_filter.c
===================================================================
RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_filter.c,v
retrieving revision 1.56
diff -u -r1.56 modperl_filter.c
--- src/modules/perl/modperl_filter.c   14 Mar 2003 05:33:18 -0000      1.56
+++ src/modules/perl/modperl_filter.c   1 Apr 2003 07:46:31 -0000
@@ -794,6 +794,92 @@
                (unsigned long)callback);
 }

+typedef int (ap_filter_chain_traverse_fh_t)(void *data, ap_filter_t *f);
+int ap_filter_chain_traverse(ap_filter_chain_traverse_fh_t *traverse,
+                             void *data, ap_filter_t **chain);
+
+int ap_filter_chain_traverse(ap_filter_chain_traverse_fh_t *traverse,
+                                    void *data, ap_filter_t **chain)
+{
+    int rv = 0;
+    ap_filter_t *curr = *chain;
+
+    while (curr) {
+        if ((rv = (*traverse)(data, curr)) != 0) {
+            return rv;
+        }
+        curr = curr->next;
+    }
+    return rv;
+}
+
+typedef struct {
+    char* filter_name;
+    char* handler_name;
+    ap_filter_t* f;
+} filter_chain_traverse_t;
+
+static int find_filter_by_handler_name(void *data, ap_filter_t *f)
+{
+    apr_pool_t* p = f->r ? f->r->pool : f->c->pool;
+    filter_chain_traverse_t* traverse = (filter_chain_traverse_t*)data;
+    char *normalized_name;
+
+    /* 'name' in frec is always lowercased */
+    normalized_name = apr_pstrdup(p, traverse->filter_name);
+    ap_str_tolower(normalized_name);
+
+    /* skip non-mod_perl filters */
+    if (strNE(f->frec->name, normalized_name)) {
+        return 0;
+    } else {
+        modperl_filter_ctx_t *ctx = f->ctx;
+        if (strEQ(ctx->handler->name, traverse->handler_name)) {
+            traverse->f = f;
+            return 1; /* found what we wanted */
+        }
+    }
+
+    return 0;
+}
+
+/*  modperl_filter_remove_by_handler_name(aTHX_ r, c,
+ *                                        MP_OUTPUT_FILTER_MODE,
+ *                                        "MyFilter::output_lc")
+ */
+void modperl_filter_remove_by_handler_name(pTHX_ request_rec *r,
+                                           conn_rec *c,
+                                           modperl_filter_mode_e mode,
+                                           char* handler_name)
+{
+    int rv = 0;
+    apr_pool_t *pool = r ? r->pool : c->pool;
+    ap_filter_t *f;
+    filter_chain_traverse_t *traverse =
+        apr_pcalloc(pool, sizeof(filter_chain_traverse_t*));
+
+    /* XXX: generalize for conn/req in/out */
+    traverse->filter_name = MP_FILTER_REQUEST_OUTPUT_NAME;
+    traverse->handler_name = handler_name;
+
+    rv = ap_filter_chain_traverse(find_filter_by_handler_name, traverse,
+                                  &r->output_filters); /* generalize */
+    if (rv) {
+        f = traverse->f; /* XXX: validate */
+        MP_TRACE_f(MP_FUNC, "found filter handler %s\n", handler_name);
+    }
+    else {
+        Perl_croak(aTHX_ "unable to find filter handler '%s'\n", handler_name);
+    }
+
+    MP_TRACE_f(MP_FUNC, "removing filter %s\n", handler_name);
+    if (mode == MP_INPUT_FILTER_MODE) {
+        ap_remove_input_filter(f);
+    }
+    else {
+        ap_remove_output_filter(f);
+    }
+}

 void modperl_brigade_dump(apr_bucket_brigade *bb, FILE *fp)
 {
Index: src/modules/perl/modperl_filter.h
===================================================================
RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_filter.h,v
retrieving revision 1.21
diff -u -r1.21 modperl_filter.h
--- src/modules/perl/modperl_filter.h   3 Mar 2003 03:39:06 -0000       1.21
+++ src/modules/perl/modperl_filter.h   1 Apr 2003 07:46:31 -0000
@@ -90,5 +90,9 @@
                                 modperl_filter_add_t addfunc,
                                 SV *callback, const char *type);

+void modperl_filter_remove_by_handler_name(pTHX_ request_rec *r,
+                                           conn_rec *c,
+                                           modperl_filter_mode_e mode,
+                                           char* handler_name);

 #endif /* MODPERL_FILTER_H */
Index: xs/Apache/Filter/Apache__Filter.h
===================================================================
RCS file: /home/cvs/modperl-2.0/xs/Apache/Filter/Apache__Filter.h,v
retrieving revision 1.26
diff -u -r1.26 Apache__Filter.h
--- xs/Apache/Filter/Apache__Filter.h   1 Apr 2003 05:20:50 -0000       1.26
+++ xs/Apache/Filter/Apache__Filter.h   1 Apr 2003 07:46:31 -0000
@@ -185,6 +185,17 @@
 }

 static MP_INLINE
+void mpxs_Apache__RequestRec_remove_output_filter(pTHX_ request_rec *r,
+                                                  char* handler_name)
+{
+
+    modperl_filter_remove_by_handler_name(aTHX_ r,
+                                          r->connection,
+                                          MP_OUTPUT_FILTER_MODE,
+                                          handler_name);
+}
+
+static MP_INLINE
 void mpxs_Apache__Filter_remove(pTHX_ I32 items, SV **MARK, SV **SP)
 {
     modperl_filter_t *modperl_filter;
@@ -207,3 +218,4 @@
         ap_remove_output_filter(f);
     }
 }
+
Index: xs/maps/modperl_functions.map
===================================================================
RCS file: /home/cvs/modperl-2.0/xs/maps/modperl_functions.map,v
retrieving revision 1.56
diff -u -r1.56 modperl_functions.map
--- xs/maps/modperl_functions.map       1 Apr 2003 05:20:50 -0000       1.56
+++ xs/maps/modperl_functions.map       1 Apr 2003 07:46:31 -0000
@@ -90,6 +90,7 @@
 MODULE=Apache::Filter PACKAGE=Apache::RequestRec
  mpxs_Apache__RequestRec_add_input_filter
  mpxs_Apache__RequestRec_add_output_filter
+ mpxs_Apache__RequestRec_remove_output_filter

 MODULE=Apache::Filter PACKAGE=Apache::Connection
  mpxs_Apache__Connection_add_input_filter
Index: xs/tables/current/ModPerl/FunctionTable.pm
===================================================================
RCS file: /home/cvs/modperl-2.0/xs/tables/current/ModPerl/FunctionTable.pm,v
retrieving revision 1.110
diff -u -r1.110 FunctionTable.pm
--- xs/tables/current/ModPerl/FunctionTable.pm  1 Apr 2003 05:20:50 -0000       1.110
+++ xs/tables/current/ModPerl/FunctionTable.pm  1 Apr 2003 07:46:31 -0000
@@ -353,6 +353,24 @@
   },
   {
     'return_type' => 'void',
+    'name' => 'mpxs_Apache__RequestRec_remove_output_filter',
+    'args' => [
+      {
+        'type' => 'PerlInterpreter *',
+        'name' => 'perl'
+      },
+      {
+        'type' => 'request_rec *',
+        'name' => 'r'
+      },
+      {
+        'type' => 'char *',
+        'name' => 'handler_name'
+      },
+    ]
+  },
+  {
+    'return_type' => 'void',
     'name' => 'mpxs_Apache__Connection_add_input_filter',
     'args' => [
       {

--- /dev/null   1970-01-01 10:00:00.000000000 +1000
+++ t/filter/both_str_rec_remove.t      2003-04-01 16:36:55.000000000 +1000
@@ -0,0 +1,17 @@
+use strict;
+use warnings FATAL => 'all';
+
+use Apache::Test;
+use Apache::TestRequest;
+use Apache::TestUtil;
+
+plan tests => 1;
+
+my $data = join ' ', 'A'..'Z', 0..9;
+#my $expected = lc $data; # that's what the input filter does
+#$expected =~ s/\s+//g;   # that's what the output filter does
+my $expected = $data;
+my $location = '/TestFilter::both_str_rec_remove';
+my $response = POST_BODY $location, content => $data;
+ok t_cmp($expected, $response, "lc input and reverse output filters");
+

--- /dev/null   1970-01-01 10:00:00.000000000 +1000
+++ t/filter/TestFilter/both_str_rec_remove.pm  2003-04-01 16:46:22.000000000 +1000
@@ -0,0 +1,61 @@
+package TestFilter::both_str_rec_remove;
+
+# insert an input filter which lowers the case of the data
+# insert an output filter which strips spaces
+
+use strict;
+use warnings FATAL => 'all';
+
+use Apache::Filter ();
+
+use Apache::Const -compile => qw(OK M_POST);
+
+sub header_parser {
+    my $r = shift;
+
+    return Apache::DECLINED;
+}
+
+sub out_filter {
+    my $filter = shift;
+
+    while ($filter->read(my $buffer, 1024)) {
+        $buffer =~ s/\s+//g;
+        $filter->print($buffer);
+    }
+
+    Apache::OK;
+}
+
+sub handler {
+    my $r = shift;
+
+    # test adding by sub's name
+    $r->remove_output_filter(__PACKAGE__ . "::out_filter");
+
+    $r->content_type('text/plain');
+
+    if ($r->method_number == Apache::M_POST) {
+        $r->print(ModPerl::Test::read_post($r));
+    }
+
+    return Apache::OK;
+}
+
+
+
+1;
+__DATA__
+<NoAutoConfig>
+    PerlModule TestFilter::both_str_rec_remove
+    <Location /TestFilter::both_str_rec_remove>
+        SetHandler modperl
+        PerlHeaderParserHandler TestFilter::both_str_rec_remove::header_parser
+        PerlOutputFilterHandler TestFilter::both_str_rec_remove::out_filter
+        PerlResponseHandler     TestFilter::both_str_rec_remove
+    </Location>
+</NoAutoConfig>
+
+
+
+


__________________________________________________________________ Stas Bekman JAm_pH ------> Just Another mod_perl Hacker http://stason.org/ mod_perl Guide ---> http://perl.apache.org mailto:[EMAIL PROTECTED] http://use.perl.org http://apacheweek.com http://modperlbook.org http://apache.org http://ticketmaster.com


--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]



Reply via email to