You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@perl.apache.org by Stas Bekman <st...@stason.org> on 2003/04/01 09:55:56 UTC

[patch] ($r||$c)->remove_(output|input)_filter

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:stas@stason.org http://use.perl.org http://apacheweek.com
http://modperlbook.org http://apache.org   http://ticketmaster.com


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@perl.apache.org
For additional commands, e-mail: dev-help@perl.apache.org